Skip to content

fix(resolve): bind imported members, cross-module Go calls and initializers - #215

Merged
sunerpy merged 1 commit into
mainfrom
fix/tier6-surface-fixes
Aug 20, 2026
Merged

sunerpy merged 1 commit into
mainfrom
fix/tier6-surface-fixes

Conversation

@sunerpy

@sunerpy sunerpy commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Tier 6 of the post-v1.5.0 upstream sync — eight independent surface defects, batched because each is small and none shares a design with another. Every one was reproduced on a real index before the fix.

An explicit Python import was ignored (#1518)

Worse than upstream's framing, which blames line-wrapped parenthesized import lists — the single-line form fails identically, and produces a false edge plus a missing one from the same cause:

pkg/mod.py      def real_target(): return 1
pkg/decoy.py    def real_target(): return 99
app.py          from pkg.mod import real_target       → caller()
app2.py         from pkg.mod import real_target as aliased → caller2()

before:  caller  -> real_target@pkg/decoy.py      ← bound to the DECOY
         caller2 -> (no edge at all)
after:   caller  -> real_target@pkg/mod.py
         caller2 -> real_target@pkg/mod.py        edges to decoy: 0

Root cause is neither of upstream's: the import's dotted source was never mapped to a path, and the fallback gated on an is_exported flag our Python extractor never sets. Both halves failed, so the reference fell through to name matching. The fix is gated narrowly so reference/golden/python/'s function-ref edges are untouched.

Go calls across module boundaries (#1521)

Two modules, ex/b requiring ex/a: 0 calls edges before, Use -> Helper@a/lib.go after. A module was identified by path without knowing its directory; modules are now located by walking each file's ancestors for a go.mod, and the longest matching path wins so ex/abc is not mistaken for a child of ex/a. Pinned by a file-order-independence test and that segment negative.

Declaration initializers (#1510, upstream PR #1511)

export const value = target(); attributed the call to the file, so callers target answered with a filename:

before:  file:d.ts       -> function:target
after:   constant:value  -> function:target

Controls pin that function-local initializers stay attributed to the function, and that a multi-declarator statement attributes per declarator.

The rest

  • #1524 — index . inside a subdirectory rebuilt the parent index silently, reporting files the user did not ask about. It now warns, on sync/uninit/unlock too.
  • #1512 — callers/callees/impact accept --file. Matching is segment-aligned, so other.ts never selects my_other.ts, and an unmatched filter is an error listing the defining files rather than an empty result that would read as "this symbol is dead".
  • #1504 — the explore note stated a call budget nothing enforced, which made agents stop early. It now says there is no limit; a test bans all four cap phrasings and asserts the replacement is present, so the wording cannot creep back.
  • #671 — MCP instructions list the 38 languages we actually support, generated from the Language registry rather than copied prose. This is the one golden this change regenerates (mcp/initialize.json, one field appended), verified against the live server.
  • fix(cli): enable self_update zip extraction for Windows releases #23 — installer gains VS Code, Copilot CLI and JetBrains targets. While testing I broke all three config contracts at once and found the --print-config assertion did not catch a broken install, so it now reads the written file instead.

Verification

  • make ci green: 132 suites / 3304 passed / 0 failed (baseline 129 / 3231).
  • CURRENT_EXTRACTION_VERSION still 7; no schema, NodeKind or EdgeKind change; crates/codegraph-resolve/src/frameworks/ untouched.
  • Extraction goldens (all 15 corpora) byte-identical; reference/ movement is only mcp/initialize.json.
  • reference/golden/erlang/edges.json still holds its 2 legitimate recursive calls self-edges.

Self-index delta — controlled, same source, old vs new binary

edge_from_file:calls   4 → 3
edge:calls         22715 → 22716

Exactly two edges, both intended. file:sample.astro → method:fetch became constant:posts@sample.astro → method:fetch — #1510 working. And a new edge RunCheckoutFlow@…/e2e/flow.go → Double@…/math.go: that fixture has a go.mod nested under crates/codegraph-cli/tests/fixtures/go_test_convention/ with none at the repo root, so this repository's own tree was a latent instance of #1521.

One finding worth separate attention

The codegraph-bench golden suite writes JSON from the committed colby.db and compares it to the committed JSON — so it guards database↔JSON consistency but never re-runs the extractor, and therefore cannot detect an extraction change on its own. I confirmed both halves: corrupting colby.db does fail the suite, and no test in that crate invokes the extractor. Real byte-stability requires regenerating from the corpora, which is what the tiers that changed extraction did. Regenerating also surfaces three diffs (godot/schema.sql, mini/refs.json, mini/schema.sql) that are pre-existing on clean main and unrelated to this change; mini/refs.json gaining a this.value function_ref row looks like content drift rather than ordering noise and deserves its own look.

…lizers

Eight independent surface defects, batched because each is small and none
shares a design with another.

An explicit Python import was ignored. `from pkg.mod import real_target`
resolved to a same-named function in an unrelated module, and the `as aliased`
form produced no edge at all — a false edge and a missing one from the same
cause: the import's dotted source was never mapped to a path, and the fallback
required an `is_exported` flag our Python extractor never sets, so the reference
fell through to name matching.

Go calls across module boundaries produced nothing, because a module was
identified by path without knowing which directory it lived in. Modules are now
located by walking each file's ancestors for a `go.mod`, and the longest
matching module path wins, so `ex/abc` is not mistaken for a child of `ex/a`.

A call in a declaration initializer was attributed to the file rather than the
declarator, so `callers` answered with a filename. It now names the constant.

A mutating command that retargets an ancestor index says so; previously
`index .` inside a subdirectory rebuilt the parent silently. `callers`,
`callees` and `impact` accept `--file` to disambiguate same-named definitions,
and an unmatched filter is an error listing the defining files rather than an
empty result that would read as "this symbol is dead".

The explore note no longer states a call budget nothing enforces, which made
agents stop early; it now says there is no limit. MCP instructions list the
languages we actually support, generated from the language registry rather than
copied prose, which is the one golden this change regenerates. The installer
gains VS Code, Copilot CLI and JetBrains targets.
@sunerpy
sunerpy merged commit ffb97d1 into main Aug 20, 2026
5 checks passed
@sunerpy
sunerpy deleted the fix/tier6-surface-fixes branch August 20, 2026 08:33
@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.69679% with 15 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/codegraph-resolve/src/import_resolver.rs 92.30% 8 Missing ⚠️
...tes/codegraph-cli/src/installer/targets/copilot.rs 98.99% 6 Missing ⚠️
crates/codegraph-extract/src/walker.rs 98.64% 1 Missing ⚠️

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #215      +/-   ##
==========================================
+ Coverage   95.25%   95.30%   +0.04%     
==========================================
  Files         137      139       +2     
  Lines       74928    76041    +1113     
==========================================
+ Hits        71375    72473    +1098     
- Misses       3553     3568      +15     
Files with missing lines Coverage Δ
crates/codegraph-cli/src/installer/registry.rs 98.60% <100.00%> (+0.02%) ⬆️
crates/codegraph-cli/src/installer/types.rs 100.00% <100.00%> (ø)
crates/codegraph-cli/src/main.rs 90.85% <100.00%> (+0.29%) ⬆️
crates/codegraph-mcp/src/engine.rs 97.60% <100.00%> (+0.04%) ⬆️
crates/codegraph-mcp/src/instructions.rs 100.00% <100.00%> (ø)
crates/codegraph-mcp/src/rmcp_handler.rs 92.67% <100.00%> (ø)
crates/codegraph-mcp/src/server.rs 97.01% <100.00%> (ø)
crates/codegraph-resolve/src/context.rs 98.47% <100.00%> (+0.33%) ⬆️
crates/codegraph-resolve/src/snapshot_context.rs 97.24% <100.00%> (-0.80%) ⬇️
crates/codegraph-resolve/src/types.rs 100.00% <100.00%> (ø)
... and 3 more

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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