feat(code-graph-incremental): resolve imports and calls across files

What does this MR do and why?

Fifth slice of code-graph-incremental, stacked on !2631 (merged). Files now resolve against each other: an import points at the definition it names in another file, and calls, inheritance and member calls through imported types become cross-file edges. An import with no matching file stays dangling. A file that overruns its resolve budget keeps the edges it already has and is reported. Nothing is wired to the CLI or server yet.

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

Testing

cargo test -p code-graph-incremental: 38 tests. New in tests/resolve.rs: on a two-file Python repo, imports and calls resolve across files (s = Store(); s.get() through the imported type, class Child(Store) as EXTENDS); import missing points at nothing; under a zero resolve budget both files are reported, imports remain and inheritance is the edge that is lost.

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/resolver.rs            Resolver: visible names per file, import requests, file index, two passes
src/file_tree.rs           ProjectTree: __root/__dir/__file/__package tree, manifests parsed in, prefixes and aliases
src/pipeline/phases.rs     Resolve (DirtyGraph -> Resolved)
tests/resolve.rs

Files are copied from !2454 (closed) at their final shape. The stub Resolver/FileIndex and their allow(dead_code) are replaced by the real file; Tree::node_mut loses its allow (Resolve writes resolved source-path symbols back).

Resolution runs in two passes. The import pass is global and links every import to its definition. The second pass runs per dirty file under file_resolve_ms and adds inheritance, decorators, destructuring, and member calls that the import pass cannot produce; that is the pass a kill drops, which is what the budget test asserts.

Base branch is michaelusa/code-graph-incremental-link (!2631 (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
!2631 (merged) SSA, linker, Link + Insert
5 (this) resolver, project 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