graph

package
v0.26.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// PolicyDiagnostic walks every edge — debugging / full blast radius.
	PolicyDiagnostic = TraversalPolicy{Name: "diagnostic"}
	// PolicyImpact: blast radius keeps dynamic dispatch (real edges) but drops
	// the regex fallback and the weakest type-use guesses (0.5).
	PolicyImpact = TraversalPolicy{Name: "impact", MinConfidence: 0.6,
		ExcludeReason: map[core.EdgeReason]bool{core.ReasonRegexFallbck: true}}
	// PolicyCertification backs guarantees: only AST-exact / structural /
	// native edges (≥0.9). The 0.9 floor already drops heuristic dispatch
	// (0.7) and constructor/inheritance guesses (0.85); the reason exclusions
	// state the intent.
	PolicyCertification = TraversalPolicy{Name: "certification", MinConfidence: 0.9,
		ExcludeReason: map[core.EdgeReason]bool{
			core.ReasonDispatch: true, core.ReasonRegexFallbck: true,
			core.ReasonInheritance: true, core.ReasonConstructor: true,
		}}
)

Functions

func BuildEdges

func BuildEdges(symbols []core.SymbolRecord) []core.Edge

BuildEdges constructs all 8 edge types from the symbol set.

Edge construction order (matches Implementation Plan §3.1):

  1. defines (file → symbol) confidence 1.0
  2. contains (parent → child) confidence 1.0
  3. imports (file → import:path) confidence 0.9
  4. extends (subtype → supertype) confidence 0.85
  5. implements (concrete → interface/trait) confidence 0.85
  6. uses-type (symbol → referenced type) confidence 0.5
  7. calls (caller → callee) confidence 0.85 same-file, 0.6 cross-file
  8. tests (test sym → tested sym) confidence 0.8

"calls" and "uses-type" are scoped to same-file + imported-file symbols per the non-negotiable accuracy rule in the plan.

func BuildEdgesDelta added in v0.24.0

func BuildEdgesDelta(prevEdges []core.Edge, prevSymbols, symbols []core.SymbolRecord, changedFiles map[string]bool, nativeAnalyzedDirs map[string]bool) []core.Edge

BuildEdgesDelta is the []core.Edge-only form of BuildEdgesDeltaMeta.

func DetectConflicts

func DetectConflicts(a, b core.IsolatedChangeRegion) core.ConflictResult

DetectConflicts checks whether two ICRs have overlapping exclusive symbols or files.

func DiffSymbols added in v0.6.0

func DiffSymbols(before, after []core.SymbolRecord) core.GraphDiff

DiffSymbols computes the structural delta between two symbol snapshots (typically: the graph before and after a merge or reindex).

Symbols are matched by stable identity — file path + qualified name + kind — not by symbol ID: IDs embed the file content SHA, so any edit changes every ID in the file and an ID-based diff would report whole-file churn for a one-line change. A symbol whose span moved but whose signature and body are unchanged is not reported at all; that is what makes the diff usable as a drift signal ("the ground shifted under you") rather than a line-number echo.

Same-key collisions (e.g. C++ overloads sharing a qualified name) are paired positionally in document order; surplus entries on either side surface as added/removed.

Types

type ChangeImpactResult added in v0.14.1

type ChangeImpactResult struct {
	Query        string              // the query as given
	Declarations []core.SymbolRecord // resolved declaration(s) on the named type
	Supers       []core.SymbolRecord // same-member declarations on other contracts (supertypes of the seed OR of any family member — a sibling interface satisfied by the same implementations breaks under the change exactly like the seed contract)
	Family       []core.SymbolRecord // overrides/implementations in the subtype closure (excluding Declarations)
	Callers      []core.SymbolRecord // methods with call edges into Declarations or Family (excluding both)

	// DeclaringTypes: type declarations whose bodies contain a change-set
	// member signature that is not indexed as its own symbol (Go and TS
	// interface members). For those declarations the innermost enclosing
	// symbol in the file IS the type, so the type's declaration block is
	// the change site a diff, a scorer, or a reviewer names. Empty for
	// languages whose member declarations are real symbols (Java, Python).
	DeclaringTypes []core.SymbolRecord

	// ExternalSupers lists supertype names declared in the hierarchy's
	// extends/implements clauses that resolve to no indexed type (JDK or
	// dependency types). Informational: the clause is in project source even
	// when the type is not.
	ExternalSupers []string
	// OverridesExternal is non-empty when the queried method is a member of
	// an external supertype's contract ("java.util.Iterator#next"): changing
	// its signature breaks that contract, and the change-set below is the
	// project-local dispatch closure, not a complete must-change set (calls
	// through receivers typed as the external supertype are not indexed).
	OverridesExternal []string
	// Completeness is "closed" when the override family is fully rooted in
	// indexed types, "project-local" when it is bounded by an external
	// contract (OverridesExternal non-empty, or the query named an external
	// type directly).
	Completeness string
}

ChangeImpactResult is the full, deterministic change-set for a method signature change: the declaration, every override/implementation in the subtype closure, and every method with a resolved call edge into any of them. This is the task-shaped answer to "what must change if X changes" — computed in the engine so no agent has to orchestrate the traversal over primitives (references → overrides → callers → dedup).

func (*ChangeImpactResult) Sites added in v0.14.1

func (r *ChangeImpactResult) Sites() []core.SymbolRecord

Sites returns every METHOD in the change-set — declarations, family, callers, and supers — as one deduplicated, file-ordered list. Supers are included because a same-member declaration on another contract (a sibling interface satisfied by the same implementations, or a supertype when the query seeded on an implementation) must change exactly like the seed: omitting it silently dropped the interface's own member from rename-plan. DeclaringTypes is deliberately NOT unioned here — those are TYPE declarations, not methods; rename-plan consumes them separately (they are edit sites), and a caller counting METHOD sites must not.

type CodeGraph

type CodeGraph struct {
	// contains filtered or unexported fields
}

func New

func New() *CodeGraph

func (*CodeGraph) BaselineRef added in v0.24.0

func (g *CodeGraph) BaselineRef() ([]core.SymbolRecord, []core.Edge)

BaselineRef returns the live symbol and edge slices WITHOUT copying, for read-only baseline use by incremental edge construction (deep-copying a 6M-edge monorepo graph doubles peak heap and its GC cost dwarfs the delta itself). The caller must treat both slices as immutable and drop them as soon as the delta completes. Symbols are materialized from the map (order is irrelevant to the delta path, which indexes by ID and file).

func (*CodeGraph) ChangeImpact added in v0.14.1

func (g *CodeGraph) ChangeImpact(query string) (*ChangeImpactResult, error)

ChangeImpact resolves a "Type.method" or "Type.method(ParamType, ...)" query to the exact change-set for that method's signature. Unlike Impact (name-substring seeded, type-erased BFS), seeding here is type-resolved: the named type's declaration is found via contains edges, the family via the extends/implements subtype closure filtered by signature compatibility, and callers via inbound call edges to those exact symbol IDs — never to same-named methods on unrelated types.

func (*CodeGraph) ComputeICR

func (g *CodeGraph) ComputeICR(intent string) core.IsolatedChangeRegion

ComputeICR computes an Isolated Change Region for the given intent string. When no symbol matches the intent, the region is empty with floor confidence and no lock keys: an arbitrary fallback region (the previous behaviour seeded from the first 20 symbols alphabetically) would make two unrelated no-match intents lock and conflict on the same random files.

func (*CodeGraph) DeadCode added in v0.15.0

func (g *CodeGraph) DeadCode(extraRoots []string) *DeadCodeResult

DeadCode computes forward reachability from every entry point — main/init functions, test symbols, exported symbols, plus extraRoots by name — over call, uses-type, and override edges, and reports the production functions/methods nothing reaches.

func (*CodeGraph) Deps

func (g *CodeGraph) Deps(filePath string) []core.Edge

Deps returns all edges that touch the given file path. Uses exact-prefix matching: edges from "file:<path>" or whose node ID begins with "<path>::" (symbol IDs in that file).

func (*CodeGraph) EdgesSnapshot added in v0.17.1

func (g *CodeGraph) EdgesSnapshot() []core.Edge

EdgesSnapshot returns a copy of the edge list only — the store write path needs no symbols, and deep-copying 100k symbol records to discard them dominated the write phase on monorepos.

func (*CodeGraph) FileSymbols added in v0.6.1

func (g *CodeGraph) FileSymbols(filePath string) []core.SymbolRecord

FileSymbols returns deep copies of the symbols defined in filePath (slash-separated, repo-relative), ordered by span. Cheap relative to Snapshot: only the one file's symbols are copied.

func (*CodeGraph) Impact

func (g *CodeGraph) Impact(query string, maxDepth int) []core.SymbolRecord

Impact returns all symbols reachable from the seed (identified by query) by traversing inbound edges up to maxDepth. "Inbound" means: things that call, test, or contain the seed symbol — i.e., the blast radius if the seed changes.

func (*CodeGraph) ImpactWithPolicy added in v0.11.0

func (g *CodeGraph) ImpactWithPolicy(query string, maxDepth int, policy TraversalPolicy) []core.SymbolRecord

ImpactWithPolicy is Impact with an explicit traversal policy — e.g. PolicyCertification for a blast radius that only follows guarantee-grade edges.

func (*CodeGraph) MissingImplementations added in v0.15.0

func (g *CodeGraph) MissingImplementations(query string) (*MissingImplementationsResult, error)

MissingImplementations resolves a "Type.method" or "Type.method(ParamType, ...)" query to every type in the subtype closure that fails to implement the member. Seeding is type-resolved exactly as in ChangeImpact; nominal closure only, so for Go the structural caveat is the same as ChangeImpact's.

func (*CodeGraph) Neighbors added in v0.13.0

func (g *CodeGraph) Neighbors(query, direction string, kinds map[core.EdgeType]bool) []Neighbor

Neighbors returns the seed symbol's direct typed neighbors — one graph hop, edge types preserved (unlike Impact, which flattens the blast radius). This is what lets a caller ask precisely for "what does X call" (direction "out", kind calls), "who calls X" (direction "in", kind calls), or "what tests X" (direction "in", kind tests) instead of a relevance-ranked blob.

direction is "out", "in", or "both"/"". kinds filters by edge type; an empty set returns every kind. Seeds are matched by exact name / qualified name / ID.

func (*CodeGraph) RenamePlan added in v0.16.0

func (g *CodeGraph) RenamePlan(query, newName string) (*RenamePlanResult, error)

RenamePlan computes ChangeImpact(query) and converts it to line edits renaming the method to newName.

func (*CodeGraph) Replace

func (g *CodeGraph) Replace(symbols []core.SymbolRecord, filesIndexed int)

func (*CodeGraph) ReplaceWithBaseEdges added in v0.24.0

func (g *CodeGraph) ReplaceWithBaseEdges(symbols []core.SymbolRecord, base, extraEdges []core.Edge, filesIndexed int)

ReplaceWithBaseEdges installs a precomputed BASE edge set (a BuildEdges/BuildEdgesDelta output) merged with native analyzer edges — the incremental counterpart of ReplaceWithEdges, which computes the base itself.

func (*CodeGraph) ReplaceWithEdges added in v0.5.0

func (g *CodeGraph) ReplaceWithEdges(symbols []core.SymbolRecord, extraEdges []core.Edge, filesIndexed int)

func (*CodeGraph) ReplaceWithStoredEdges added in v0.6.0

func (g *CodeGraph) ReplaceWithStoredEdges(symbols []core.SymbolRecord, edges []core.Edge, filesIndexed int)

ReplaceWithStoredEdges installs a previously-computed edge set verbatim — the edges persisted by the last index are already the merged (baseline + native) set, so rehydration must not pay the BuildEdges cost again. Databases written before edges were persisted (symbols but no edges) fall back to a full rebuild.

func (*CodeGraph) Search

func (g *CodeGraph) Search(query string, limit int) []core.SymbolRecord

Search returns symbols matching the query (case-insensitive), ranked by match quality: exact name > exact qualified name > name prefix > name substring > qualified-name substring > path/signature substring. Ranking matters because results are truncated at limit — with the previous alphabetical-by-path ordering, the exact-name match for a common query could be cut off by substring hits in files that happened to sort earlier.

func (*CodeGraph) SemanticSearch

func (g *CodeGraph) SemanticSearch(query string, limit int) []embeddings.Scored

SemanticSearch ranks symbols against a free-text intent using the configured embedding backend (Model2Vec by default; TF-IDF if GROVE_EMBEDDINGS=tfidf). Documents are constructed from (name + qualifiedName + signature + docstring + parent). The engine is built lazily and cached until the next Replace().

func (*CodeGraph) Snapshot

func (g *CodeGraph) Snapshot() ([]core.SymbolRecord, []core.Edge)

func (*CodeGraph) Status

func (g *CodeGraph) Status() core.Status

type DeadCodeResult added in v0.15.0

type DeadCodeResult struct {
	RootCount      int `json:"rootCount"`      // entry points seeded (mains, inits, tests, exported, extra)
	ReachableCount int `json:"reachableCount"` // symbols reached from the roots
	Considered     int `json:"considered"`     // production functions/methods examined

	// Dead: unreachable, non-exported, name unreferenced anywhere in live
	// code. The deletion-candidate list.
	Dead []core.SymbolRecord `json:"dead"`
	// ExportedUnreferenced: exported symbols with no in-project reference at
	// all (no inbound edge, name unreferenced). Dead only if nothing outside
	// this project links against it — a decision the graph cannot make.
	ExportedUnreferenced []core.SymbolRecord `json:"exportedUnreferenced"`

	// Caveats state what static reachability cannot see. They are part of
	// the result, not documentation: an agent relaying this answer must
	// relay them.
	Caveats []string `json:"caveats"`
}

DeadCodeResult reports production functions/methods that nothing reaches. Precision-first: a symbol appears in Dead only when it is unreachable from every root, is not exported, and its name occurs nowhere in live code text (so callback/value references that produce no call edge still keep a symbol alive). Anything static analysis cannot decide is bucketed separately or excluded, never reported as dead.

type DeltaMeta added in v0.24.0

type DeltaMeta struct {
	// AffectedOwners: symbol IDs (in unchanged files) whose out-edges were
	// recomputed — their stored rows must be deleted and reinserted.
	AffectedOwners map[string]bool
	// ChangedFiles / NativeAnalyzedDirs: as passed in (splice needs them to
	// select insert rows and native-row deletions).
	ChangedFiles       map[string]bool
	NativeAnalyzedDirs map[string]bool
}

BuildEdgesDelta computes the new edge set from the previous edge set (a prior base output, or the merged-with-native set when nativeAnalyzedDirs names every natively re-analyzed package dir), the previous and current full symbol slices, and the set of changed (added/modified/removed) repo-relative file paths. Falls back to BuildEdges(symbols) whenever soundness of the scoping cannot be guaranteed cheaply.

Identity remap: symbol IDs embed the file blob SHA, so EVERY edit turns over every ID in the file. Symbols whose resolution-relevant content is unchanged (identityKey) keep their edges via an oldID→newID rewrite instead of caller re-resolution — a comment-level edit re-resolves almost nothing. Only semantically added/removed/changed symbols contribute to the name delta and the affected set. DeltaMeta describes the write-set of an incremental rebuild — everything a store splice needs to bring the persisted table to the new state without a full-table diff. Nil when the delta fell back to a full rebuild.

func BuildEdgesDeltaMeta added in v0.24.0

func BuildEdgesDeltaMeta(prevEdges []core.Edge, prevSymbols, symbols []core.SymbolRecord, changedFiles map[string]bool, nativeAnalyzedDirs map[string]bool) ([]core.Edge, *DeltaMeta)

type MissingImplementationsResult added in v0.15.0

type MissingImplementationsResult struct {
	Query    string              // the query as given
	Contract []core.SymbolRecord // the method's declaration(s) on the named type

	// Missing lists concrete types (class/struct/enum) in the subtype
	// closure with no signature-compatible implementation of their own and
	// none inherited through their class-extends chain. Each is a compile
	// error once the member is required.
	Missing []core.SymbolRecord
	// AbstractMissing lists abstract classes in the closure without an
	// implementation. Not compile-broken themselves — their concrete
	// subtypes appear in Missing — but listed because adding the
	// implementation there often fixes a whole subtree.
	AbstractMissing []core.SymbolRecord
	// Unverifiable lists closure types without a visible implementation
	// whose class-extends chain leaves the index (an external superclass may
	// provide the member). Deliberately separated from Missing: flagging a
	// working type as broken sends an agent to "fix" correct code.
	Unverifiable []core.SymbolRecord

	// ImplementedCount is the number of closure types that do carry a
	// compatible implementation (own or inherited) — evidence of coverage
	// without inflating the payload; ChangeImpact returns the full family.
	ImplementedCount int

	// DefaultProvided is true when the contract itself supplies a body every
	// subtype inherits (a Java default method, or a concrete method on a
	// class/abstract-class seed). No type is then compile-broken today, and
	// Missing reads as "inherits the default — breaks if the member becomes
	// abstract/required", which is the interface-evolution question that
	// motivates querying a defaulted member.
	DefaultProvided bool

	// Same contract-boundary reporting as ChangeImpactResult.
	ExternalSupers    []string
	OverridesExternal []string
	Completeness      string // "closed" | "project-local"
}

MissingImplementationsResult is the deterministic answer to "I added (or am adding) Type.method — which types claiming that contract do not implement it?": the companion operation to ChangeImpact for interface evolution. ChangeImpact returns the sites that must change when a signature changes; MissingImplementations returns the types the compiler will reject once the member is required. Computed in the engine so no agent has to orchestrate the traversal (closure → per-type member check → inheritance walk) over primitives.

type Neighbor added in v0.13.0

type Neighbor struct {
	Symbol     core.SymbolRecord
	EdgeType   core.EdgeType
	Direction  string // "out" = seed→symbol (callee, uses-type); "in" = symbol→seed (caller, test)
	Confidence float64
}

Neighbor is a symbol reached from a seed by exactly one typed edge.

type PolicySkips added in v0.11.0

type PolicySkips map[core.EdgeReason]int

PolicySkips counts, per resolver reason, the edges a policy excluded during a traversal — so consumers (certification) can cite the evidence they did not trust.

type RenameEdit added in v0.16.0

type RenameEdit struct {
	FilePath string
	Line     int    // 1-based
	Before   string // source line as indexed
	After    string // with the rename applied
	SiteID   string // containing symbol ID
	Site     string // "relpath:name" for relay
}

RenameEdit is one suggested line edit in a rename plan.

type RenamePlanResult added in v0.16.0

type RenamePlanResult struct {
	Query   string
	NewName string

	Edits     []RenameEdit // confirmed: apply as-is
	Ambiguous []RenameEdit // same-named non-family callee also in scope: verify receiver type first
	// Unresolved lists change-set sites for which no line edit could be
	// derived (empty indexed text, or the name not found in call position
	// on the recorded lines) — the agent must handle these manually.
	Unresolved []string

	SitesTotal        int // sites in the underlying change-impact set
	ExternalSupers    []string
	OverridesExternal []string
	Completeness      string
}

RenamePlanResult is the change-set of ChangeImpact converted into concrete line edits: declaration/override name lines plus family-resolved call lines, each with a suggested substitution. Precision-first: lines the graph cannot attribute to the family with certainty (the containing method also calls a same-named non-family method) are bucketed Ambiguous, never silently included or dropped. The agent's job becomes review-and-apply.

type TraversalPolicy added in v0.11.0

type TraversalPolicy struct {
	Name          string
	MinConfidence float64
	ExcludeReason map[core.EdgeReason]bool
}

TraversalPolicy decides which edges a consumer closure may walk, by confidence floor and resolver reason. Profiles let tests / impact / certification / diagnostic consumers opt into different strictness instead of one hard-coded threshold, and make the choice explainable (every excluded edge has a reason). See roadmap Wave 4 / Sweep #4.

func (TraversalPolicy) Allows added in v0.11.0

func (p TraversalPolicy) Allows(e core.Edge) bool

Allows reports whether an edge passes the policy.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL