Documentation
¶
Overview ¶
Package affected selects the verification units reachable from a dirty worktree.
The package is language-agnostic by construction. A language participates by implementing Language; selection, witnesses, exclusion certificates, and widening are then computed identically for every plugin, so adding a language cannot change what a selection means.
This package performs no execution. It observes source text and a bounded Git status, and produces a plan. A plan is an observation about the dependency graph it names, never a claim that unselected tests cannot fail.
Index ¶
- Constants
- Variables
- func DecodeNameList(raw []byte) ([]string, error)
- func DecodeStatus(raw []byte) ([]string, error)
- func DirectoriesOf(paths []string) []string
- func DirtyPaths(ctx context.Context, gitExecutable, root string) ([]string, error)
- func DirtyPathsFor(ctx context.Context, gitExecutable, root string, observation *Observation) ([]string, error)
- func NormalizePaths(values []string) []string
- func RangePaths(ctx context.Context, gitExecutable, root, base string) ([]string, error)
- func ReadSource(root, relative string) ([]byte, error)
- func SourceFiles(root string, accept func(name string) bool) ([]string, error)
- func SourceFilesIncluding(root string, accept func(name string) bool, includedDirectories ...string) ([]string, bool, error)
- func Union(dirty []string, overlay Overlay) []string
- func ValidRelativePath(value string) bool
- type Exclusion
- type Graph
- func (graph *Graph) Canonical() ([]byte, error)
- func (graph *Graph) Digest() string
- func (graph *Graph) Frontier() []string
- func (graph *Graph) Languages() []string
- func (graph *Graph) OwnerOf(path string) (string, bool)
- func (graph *Graph) Unit(id string) (Unit, bool)
- func (graph *Graph) UnitIDs() []string
- type Language
- type Observation
- type Overlay
- type Plan
- type Result
- type Selection
- type Unit
- type Unknown
- type Witness
Constants ¶
const ( // MaxStatusBytes bounds one status capture, including the overflow byte. MaxStatusBytes = 8 << 20 // StatusDeadline is the fixed capture deadline. StatusDeadline = 10 * time.Second )
const ( WitnessDirectSource = "DIRECT_SOURCE_CHANGE" WitnessDirectTest = "DIRECT_TEST_CHANGE" WitnessDependency = "DEPENDENCY_PATH" // WitnessPathLiteralReader names a unit whose own files carry a string // literal naming a dirty path no plugin owns (AFP-V0-021). WitnessPathLiteralReader = "PATH_LITERAL_READER" )
Witness kinds. Every selected unit names exactly one machine-checkable witness, per LPCV-V0-013.
const ( ExcludedNoDependencyPath = "NO_DEPENDENCY_PATH_TO_DIRTY_UNIT" ExcludedDirtyGoPathMayBeDeletedOrRenamed = "UNINDEXED_DIRTY_GO_PATH_MAY_BE_DELETED_OR_RENAMED" )
Exclusion reasons. Every eligible unit that is not selected carries one, per LPCV-V0-014.
const ( // UnknownUnindexedSourcePath reports a dirty path a language plugin claims // as its own source text but which no unit declares. A new file, a rename, // or an excluded build variant produces this. UnknownUnindexedSourcePath = "UNINDEXED_SOURCE_PATH" // UnknownUnownedDirtyPath reports a dirty path no plugin claims. Build // configuration, generators, fixtures, and data files land here: they may // affect any unit, so the exclusion set cannot be justified. UnknownUnownedDirtyPath = "UNOWNED_DIRTY_PATH" // UnknownLanguageFrontier reports that a plugin could not resolve part of // its own graph exactly. UnknownLanguageFrontier = "LANGUAGE_FRONTIER" // UnknownNoSelectableTest reports a changed unit (one owning a dirty path) // that no selectable test checks under its plugin's rule (AFP-V0-020). UnknownNoSelectableTest = "NO_SELECTABLE_TEST" )
Widening reasons. Any of these makes the plan's scope UNKNOWN, per LPCV-V0-016: uncertainty widens rather than disappearing.
const ( ScopeBounded = "BOUNDED" ScopeUnknown = "UNKNOWN" )
Scope axes, per the LPCV result-axis rule. Selection produces scope only; execution status and currency belong to the runtime provider and the caller.
const ( // MaxWalkEntries bounds one repository walk. MaxWalkEntries = 400_000 // MaxIncludedDirectoryEntries bounds each language-opted directory subtree. MaxIncludedDirectoryEntries = 20_000 // MaxSourceBytes bounds one source file a plugin may read for imports. MaxSourceBytes = 4 << 20 )
const MaxPathsPerUnit = 20_000
MaxPathsPerUnit bounds the file lists carried by one unit.
const MaxUnits = 200_000
MaxUnits bounds one graph so a pathological tree cannot exhaust memory.
const PathTokenBound = "path-token-bound"
PathTokenBound names, in a LANGUAGE_FRONTIER detail "<namespace>:path-token-bound:<unit>", a unit whose plugin dropped its path tokens at the bound (AFP-V0-021).
Variables ¶
var ( // observed at all. ErrStatusUnavailable = errors.New("affected: worktree status is unavailable") // ErrStatusOverflow reports a status larger than the fixed bound. A // truncated status would understate the dirty set, so it fails closed. ErrStatusOverflow = errors.New("affected: worktree status exceeds the byte bound") // ErrStatusMalformed reports a status Corvint could not decode exactly. ErrStatusMalformed = errors.New("affected: worktree status is malformed") )
var ( // ErrInvalidUnit reports a unit that is not in canonical form. ErrInvalidUnit = errors.New("affected: unit is not canonical") // ErrDuplicateUnit reports two units sharing one identity. ErrDuplicateUnit = errors.New("affected: duplicate unit identity") // ErrDuplicateOwner reports one path claimed by two units. ErrDuplicateOwner = errors.New("affected: duplicate path ownership") // ErrInvalidLanguage reports a plugin that broke the seam contract. ErrInvalidLanguage = errors.New("affected: language plugin is invalid") )
var ErrWalkLimit = errors.New("affected: repository walk exceeds its bound")
ErrWalkLimit reports a repository larger than the fixed walk bound.
var ErrWalkUnreadable = errors.New("affected: source walk hit an unreadable entry")
ErrWalkUnreadable reports a directory or entry the walk could not read.
var ErrWalkUnrepresentable = errors.New("affected: source walk hit a file path no unit can name")
ErrWalkUnrepresentable reports an accepted file whose repository-relative path is no canonical unit path, so no unit could name it.
var SkippedDirectories = map[string]bool{ ".git": true, ".hg": true, ".svn": true, "node_modules": true, "vendor": true, "__pycache__": true, ".venv": true, "venv": true, ".tox": true, ".mypy_cache": true, ".pytest_cache": true, ".ruff_cache": true, "site-packages": true, "dist": true, "build": true, "target": true, ".idea": true, ".vscode": true, }
SkippedDirectories are not descended by SourceFiles. A language plugin may explicitly admit names that can hold its first-party source through SourceFilesIncluding.
Functions ¶
func DecodeNameList ¶
DecodeNameList parses a NUL-delimited path list such as `git diff --name-only -z` emits, admitting only valid relative paths.
func DecodeStatus ¶
DecodeStatus parses the NUL-delimited porcelain v1 stream.
Each record is two status codes, a space, and the path. A rename or copy record is followed by a second NUL-terminated field holding the original path; both paths enter the dirty set, because a rename changes the unit that lost the file as well as the one that gained it.
It is exported because an authority that already captured the same status bytes must decode them the same way this package would. Sharing the decoder is what makes a published dirty set and a locally captured one the same object rather than two implementations that can drift apart on renames.
func DirectoriesOf ¶
DirectoriesOf returns the sorted set of directories containing the paths. It is the cheap invalidation key for plugins whose unit is a directory.
func DirtyPaths ¶
DirtyPaths captures the exact repository-relative path set Git reports as changed in the worktree at root.
The capture fails closed: overflow, deadline, a Git failure, or an undecodable record returns an error rather than a short list that would silently narrow later selection. Ignored paths are deliberately not enumerated; they are unobserved, not proven absent.
This function reads Git's report only. It never opens a worktree file.
func DirtyPathsFor ¶
func DirtyPathsFor(ctx context.Context, gitExecutable, root string, observation *Observation) ([]string, error)
DirtyPathsFor returns the dirty set selection consumes, preferring an existing observation over capturing one.
The observation is normalized, not re-derived: it is already the decoded output of a status capture that the observing authority bound its identity to. When none is offered, this falls back to DirtyPaths and its own fail-closed capture, so the selector still works standalone.
func NormalizePaths ¶
NormalizePaths sorts and deduplicates a dirty path set and drops anything not in canonical repository-relative form.
func RangePaths ¶
RangePaths captures the exact repository-relative path set whose content differs between the committed tree at base and the committed tree at HEAD.
It is the committed counterpart of DirtyPaths and shares its bounds and its fail-closed rule: overflow, deadline, a Git failure, or an undecodable name returns an error, never a short list. Renames are not detected, so a moved file enters the set under both its old and new path, exactly as the status decoder admits both sides of a rename record. The diff compares two trees; it never reads the worktree.
func ReadSource ¶
ReadSource reads one repository-relative source file under root, bounded by MaxSourceBytes. A file at or over the bound is refused rather than truncated, because a truncated read would silently drop import edges.
func SourceFiles ¶
SourceFiles walks root and returns every repository-relative file path whose name satisfies accept, sorted.
Directories in SkippedDirectories and directories whose name begins with "." are not descended. Symbolic links are never followed: a link is reported as the link itself and, because no plugin accepts a link as source text, it is simply not a unit member.
func SourceFilesIncluding ¶
func SourceFilesIncluding(root string, accept func(name string) bool, includedDirectories ...string) ([]string, bool, error)
SourceFilesIncluding is SourceFiles with explicit language-owned exceptions to SkippedDirectories. Each exception applies at every depth.
func Union ¶
Union merges a Git-observed dirty set with an accepted overlay into the single sorted path set selection consumes.
Selection is identity-free at this layer: an overlaid path is dirty whether or not Git already reported it, so a keystroke in an otherwise clean file selects exactly what saving that file would have selected.
func ValidRelativePath ¶
ValidRelativePath reports whether value is the canonical repository-relative form this package accepts everywhere: non-empty, valid UTF-8, slash separated, no leading slash, no "." or ".." component, and no empty component.
Types ¶
type Exclusion ¶
type Exclusion struct {
UnitID string `json:"unitId"`
Reason string `json:"reason"`
Universe string `json:"universe"`
Invalidation string `json:"invalidation"`
}
Exclusion is a bounded certificate for one eligible unit the plan did not select. It names the inspected universe and the condition that invalidates it. It is never a claim that the unit's tests cannot fail.
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph is the composed dependency graph over every participating language.
A graph is immutable once built. Its digest covers every unit, every edge, and every frontier reason, so two graphs with the same digest select identically and a plan can name the exact universe it inspected.
func Build ¶
Build composes one graph from every supplied language plugin.
Plugins are observed in the order given but the resulting graph is order-independent: identities, paths, and edges are all canonically sorted before the digest is taken.
func (*Graph) Canonical ¶
Canonical returns the deterministic JSON body the digest is taken over. It is the persistable form: a graph rebuilt from repository authority produces byte-identical output.
type Language ¶
type Language interface {
// Name is the plugin's namespace. Every unit it returns has the identity
// prefix Name() + ":".
Name() string
// Owns reports whether a repository-relative path is source text this
// plugin is responsible for. A dirty path owned by no plugin widens scope.
Owns(path string) bool
// Units observes the repository rooted at the absolute path root.
Units(root string) (Result, error)
}
Language is the seam a second language plugs into.
A plugin observes source text only. It must not execute the repository, shell out to a package manager, or read outside root.
type Observation ¶
type Observation struct {
Paths []string
}
Observation is a dirty path set some other component already observed, in the same repository, from the same Git status bytes this package would have captured itself.
It exists so a caller that holds an authority observation does not observe the worktree a second time. A worktree is mutable: two captures are two different facts, and a plan built from the second cannot be attributed to the identity recorded from the first. A nil *Observation means no such observation is available, which is distinct from an observation whose path set is empty because the worktree is clean.
type Overlay ¶
type Overlay struct {
Paths []string
}
Overlay is an accepted unsaved-editor-buffer set: repository-relative paths whose in-editor bytes differ from the worktree.
Corvint admits an overlay as a selection input only. This package never writes overlay bytes into the user's worktree; materializing them for execution is the runtime provider's job, under its own isolation.
type Plan ¶
type Plan struct {
GraphDigest string `json:"graphDigest"`
Dirty []string `json:"dirty"`
Scope string `json:"scope"`
Selected []Selection `json:"selected"`
Excluded []Exclusion `json:"excluded"`
Unknown []Unknown `json:"unknown"`
}
Plan is the selection result: what to verify, what was deliberately left out and why, and what could not be justified at all.
func Select ¶
Select computes the plan for one dirty path set.
The traversal is a breadth-first sweep over reverse dependency edges from every unit that directly contains a dirty path. Breadth-first order plus sorted expansion makes the witness for each reached unit the shortest chain, broken by the lexicographically smallest dirty path, so the plan is deterministic for fixed inputs (LPCV-V0-019).
A unit is traversed whether or not it declares tests; it is selected only if it declares at least one, because a unit with no tests contributes no check. A changed unit that no selectable test checks is named as unknown scope instead of being omitted (AFP-V0-020); untestedRules holds each plugin's rule. Every dirty path also selects the units whose path literals name it (AFP-V0-021); an unowned path stays unknown all the same.
Selected units are emitted in the AFP-V0-007 order: witness chain length ascending, shared directory prefix with the witness's dirty path descending, unit id ascending. Exclusions stay in unit id order.
func (Plan) Canonical ¶
Canonical returns the deterministic JSON body of a plan. This is the receipt payload an agent consumes and a digest may be taken over.
func (Plan) SelectedTests ¶
SelectedTests flattens the plan's selected tests into one sorted path list.
type Result ¶
Result is what one Language plugin observed for a repository.
Frontier carries the reason codes for everything the plugin could not resolve exactly. A non-empty frontier widens the plan's scope to UNKNOWN rather than silently narrowing selection.
type Selection ¶
type Selection struct {
UnitID string `json:"unitId"`
Tests []string `json:"tests"`
Witness Witness `json:"witness"`
}
Selection is one unit whose tests the plan requires.
type Unit ¶
type Unit struct {
ID string `json:"id"`
Sources []string `json:"sources"`
Tests []string `json:"tests"`
Imports []string `json:"imports"`
PathTokens []string `json:"pathTokens,omitempty"`
PathTokensBounded bool `json:"pathTokensBounded,omitempty"`
}
Unit is one language-agnostic verification unit: the smallest thing a runtime provider can be asked to verify. A Go package, a Python module, and a JavaScript file are all units.
Every path is repository-relative, slash-separated, sorted, and unique. Imports name other Unit identities; an import that a plugin could not resolve to a repository unit is omitted here and reported through Result.Frontier. PathTokens are the sorted, unique path-shaped tokens of the string literals the unit's own files carry; every dirty path selects the units whose tokens name it (AFP-V0-021). A plugin that reads no literals leaves it empty. PathTokensBounded reports that the plugin dropped the unit's tokens at its bound, so the unit's reads are unknown.
type Witness ¶
type Witness struct {
Kind string `json:"kind"`
DirtyPath string `json:"dirtyPath"`
Via []string `json:"via"`
}
Witness is the reason one unit entered the plan.
Via is the dependency chain from the unit that directly contains DirtyPath to the selected unit, inclusive at both ends. For a direct change it holds one element.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package dotnet is the C# implementation of the affected-selection language seam.
|
Package dotnet is the C# implementation of the affected-selection language seam. |
|
Package golang is the Go implementation of the affected-selection language seam.
|
Package golang is the Go implementation of the affected-selection language seam. |
|
Package kotlin is the Kotlin/JVM implementation of the affected-selection language seam.
|
Package kotlin is the Kotlin/JVM implementation of the affected-selection language seam. |
|
Package python is the Python implementation of the affected-selection language seam.
|
Package python is the Python implementation of the affected-selection language seam. |
|
Package ruby is the Ruby implementation of the affected-selection language seam.
|
Package ruby is the Ruby implementation of the affected-selection language seam. |
|
Package rust is the Rust implementation of the affected-selection language seam.
|
Package rust is the Rust implementation of the affected-selection language seam. |
|
Package swift is the Swift implementation of the affected-selection language seam.
|
Package swift is the Swift implementation of the affected-selection language seam. |
|
Package typescript is the JavaScript and TypeScript implementation of the affected-selection language seam.
|
Package typescript is the JavaScript and TypeScript implementation of the affected-selection language seam. |