feat(code-graph-incremental): linking phase

What does this MR do and why?

Fourth slice of code-graph-incremental, stacked on !2629 (merged). A canonical tree is now linked: definitions, calls resolved through local types, and uses of imported names become edges inside the file. Linked files then go on the graph together with a File row for every file that was not parsed, tagged with why (excluded extension, binary, over budget, unreadable). Nothing is wired to the CLI or server yet.

Relates to #1284. Reference implementation: !2454 (closed).

Testing

cargo test -p code-graph-incremental: 35 tests. New in tests/link.rs: linking the Python fixture yields the expected DEFINES, CALLS (g = Greeter(); g.greet() resolves through the local type) and IMPORTS edges, all inside one file; every file gets a tree and unparsed ones carry their reason; a file killed by the rewrite budget keeps a row spanning its size, tagged skip_timeout_walk, with no edges. The SSA engine's own tests came along in ssa.rs.

cargo clippy -p code-graph-incremental --all-targets -- -D warnings: clean.

Performance Analysis

No runtime change: nothing calls this crate yet.

  • This merge request does not introduce any performance regression. If a performance regression is expected, explain why.
Agent context: long-form analysis, file-by-file walkthroughs, profiler output, alternatives considered

What lands

src/ssa.rs                 SSA engine (Braun et al.): reaching definitions over the canonical tree
src/linker.rs              link(tree, env, run) -> local edges; drives the SSA engine
src/pipeline/phases.rs     Link (ItemPhase, Canonical -> LinkedFile), Insert (Workset -> DirtyGraph), listed_file
src/shared/tags.rs         linker.rs joins the "engine-read tag keys live in tags.rs" check
tests/link.rs

Files are copied from !2454 (closed) at their final shape. Listed loses its allow(dead_code): Insert reads it. file_tree.rs is read only by Resolve and moves with it to MR 5.

Base branch is michaelusa/code-graph-incremental-dsl (!2629 (merged)); retarget to main once that merges.

MR stack

MR Contents
!2620 (merged) runner, budgets, errors, canonical alphabet, artifact and graph types
!2627 (merged) Tree, Interner, tree-sitter languages, Env, inventory, Prepare + Each + Parse
!2629 (merged) DSL engine, Rewrite + Canonicalize, Env.rules, Python rules
4 (this) SSA, linker, Link + Insert
5 resolver, file tree, Resolve
6 export engine + export.yaml, Display + Export + Emit, index template; YAML suites through the integration-tests-codegraph runner with an engine switch; CI job
7 State save/load, Remap, reindex template, incremental suites
8 remaining language rule files
9 orbit index --engine incremental, full index through the existing DuckDB sink
10 snapshot next to the DuckDB file, changed paths from git, incremental CLI
11 default flip per language; old pipeline and its fixtures retire

%{all_commits}

Merge request reports

Loading
Loading