Skip to content

Give Rust and Python real cross-file calls and stop fabricating Python imports - #28

Merged
Phoenixrr2113 merged 1 commit into
mainfrom
fix/batch-three-lang-extraction
Aug 21, 2026
Merged

Phoenixrr2113 merged 1 commit into
mainfrom
fix/batch-three-lang-extraction

Conversation

@Phoenixrr2113

Copy link
Copy Markdown
Owner

What this fixes

Batch three, wave two: cross-file call resolution for non-TypeScript languages, with honesty as the design constraint. Resolve what per-file import analysis can prove, drop what it cannot, never fabricate.

Python

  • Import resolution existence-checks every candidate in Python's own order (module file, then package init.py) instead of returning the first plausible path. Phantom File nodes at paths that never existed are gone.
  • Bare-dot imports (from . import mod) try the submodule file before the package init fallback, fixing a wrong edge, and namespace aliases (import pkg as p) are recorded correctly.
  • Cross-file CALLS edges now exist for imported names and module-qualified calls.

The generic engine (Python plus ~35 tier-2 languages)

The shared call extractor accepts the file's imports as context and emits the callee's defining file, always under the name declared at that file rather than the local alias, so the edge binds to a real node.

Rust

Resolves mod-declared siblings (both foo.rs and foo/mod.rs forms), use crate:: paths anchored at the nearest Cargo.toml, self and super, and aliased items, all verified with existence checks. External crates stay unresolved. Method calls deliberately get no bare-call fallback to avoid coincidental name matches.

Go

Deliberately emits no cross-file callees: Go calls address a package (a directory), not a file, and per-file analysis cannot know which file declares a symbol. Guessing would create wrong edges, so the behavior is locked by tests and the honest fix (a project-wide package symbol table pre-pass) is recorded on the ledger.

Pipeline

Call edges are built from the resolved callee file when present instead of structurally forcing every non-TS edge to be same-file, which is what made cross-file resolution impossible for all these languages.

Review process

Two adversarial rounds of live-index attacks. Round one found the alias blocker independently in both the generic and Rust extractors (the unit tests had enshrined the wrong expectation), plus two adjacent Python bugs. Round two verified all fixes with hostile probes, including a target file declaring both the alias and the real name as separate functions, and a composition sweep across nine fixtures with zero dangling callees and zero phantom files.

Verification

  • pnpm turbo build 21/21, pnpm turbo test 34/34, pnpm release:check passes.
  • Test counts: core 246, plugin-python 60, plugin-rust 62, plugin-go 52, plugin-generic 8 (new test infra).

Known gaps deliberately not in this PR (ledger)

  • Go cross-file and same-package calls need a project-wide package symbol table.
  • from . import mod2; mod2.something() attribute calls produce no edge (missing, not wrong).
  • Tier-2 config languages benefit only where their import extraction yields real resolved paths.

🤖 Generated with Claude Code

…n imports

Python import resolution now checks that a candidate actually exists on
disk (module file, then package __init__.py, in Python's own order)
instead of returning the first plausible-looking path, so phantom File
nodes at paths that never existed are gone. Bare-dot imports (from .
import mod) try the submodule file before falling back to the package
__init__, and namespace aliases (import pkg as p) record the alias.

The shared generic call extractor is import-aware: calls to imported
names and module-qualified calls now emit the callee's defining file,
and always under the name DECLARED at that file, never the local alias,
so the edge actually binds. Rust resolves mod-declared siblings, crate
paths anchored at the nearest Cargo.toml, self and super, and aliased
use items, all existence-verified; external crates stay unresolved.
Go deliberately emits no cross-file callees: its calls address a
package directory, not a file, and guessing is worse than absence; the
honest fix needs a project-wide package symbol table, recorded on the
ledger. The pipeline honors the resolved callee file instead of
structurally forcing every non-TS call edge to be same-file.

Two adversarial review rounds drove out the alias blocker (found
independently in both extractors) plus two adjacent Python bugs, all
verified by live-index runs; the composition sweep across nine fixtures
found zero dangling callees and zero phantom files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
v0-landing-page-build Skipped Skipped v0 Aug 21, 2026 5:13pm

@Phoenixrr2113
Phoenixrr2113 merged commit 5dccd51 into main Aug 21, 2026
12 checks passed
@Phoenixrr2113
Phoenixrr2113 deleted the fix/batch-three-lang-extraction branch August 21, 2026 17:20

This branch was previously deployed

1 inactive deployment
Preview — 9cb65aa0 Deployed Aug 21, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant