Skip to content

fix(registry): stop external package imports binding to project homonyms - #1766

Open
Yyunozor wants to merge 3 commits into
DeusData:mainfrom
Yyunozor:fix/1355-external-import-shadow
Open

fix(registry): stop external package imports binding to project homonyms#1766
Yyunozor wants to merge 3 commits into
DeusData:mainfrom
Yyunozor:fix/1355-external-import-shadow

Conversation

@Yyunozor

Copy link
Copy Markdown
Contributor

Addresses the external-import sub-case of #1355: the caller's own source already says the callee is not a project symbol.

Complements #1386, which guards the Python side of the same issue with a generic-name list. This one keys on import evidence rather than on names and is not language-gated; the repro and tests here are TypeScript. Both land at the same two emission sites — happy to rebase onto #1386 whenever it lands.

Reproduction

src/queries.ts does import { eq, sql } from "drizzle-orm"; src/text-utils.ts exports unrelated local eq/sql helpers. On main (34d18ae):

buildQuery  eq   …src.text-utils.eq   unique_name
buildQuery  sql  …src.text-utils.sql  unique_name

Two fabricated CALLS edges, identical under CBM_INDEX_SINGLE_THREAD=1 and CBM_WORKERS=4. The TS-LSP is not at fault: normalize, imported relatively from the very module the guess picked, resolves via lsp_ts_import @ 0.95. It declines the external names; the textual fallback fires regardless.

Cause

drizzle-orm is outside the indexed tree, so cbm_pipeline_resolve_import_node returns NULL, no IMPORTS edge is written, and the import map has no key for eq. Strategies 1-2 miss and resolve_name_lookup binds by simple name. Confidence does not separate the cases: the fabricated edge reaches 0.75 when the file also imports from the target's module.

Fix

cbm_suppress_external_import_shadow() — a pure predicate beside the existing cbm_perl_* / cbm_tsjs_* / cbm_suppress_cross_language_* guards. It drops the edge only when the callee is a bare identifier, the strategy is a project-wide guess (suffix_match / unique_name / field_type_hint / fuzzy), the file imports that name from a non-relative specifier, and no import-map key binds it.

Relative specifiers are excluded on purpose: they name a path inside the tree, so a missing IMPORTS edge there is an in-project gap and the fallback may still be right.

Verification

  • scripts/test.sh: branch 7569 / 1 / 8, parent 7565 / 1 / 8. Delta is exactly the 4 new tests; the pre-existing failure (test_cli.c:8914) is identical on both sides.
  • Red on the parent: the new pipeline test fails with the buildQuery → eq edge present, on both resolvers.
  • npm workspaces, pnpm-workspace.yaml, tsconfig paths, barrel and ./x.js imports keep their edges; Java import static and Python from pkg import f are untouched.

Known limitation

A bare specifier that does name in-project code but fails to materialize an IMPORTS edge (the workspace case in #1732) now loses its same-name fallback edge instead of keeping it at reduced confidence. A natural follow-up would consult the package map first.

Copilot AI lite review requested due to automatic review settings August 20, 2026 15:19
@Yyunozor
Yyunozor requested a review from DeusData as a code owner August 20, 2026 15:19
@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds a registry-level suppression guard to prevent project-wide fallback resolution from creating fabricated CALLS edges when the caller explicitly imports a homonymous symbol from an external (non-indexed) package.

Changes:

  • Introduces cbm_suppress_external_import_shadow() to suppress fallback-resolved edges for bare identifiers that are imported from non-relative specifiers but do not bind in the import map.
  • Applies the guard consistently in both sequential (pass_calls.c) and parallel (pass_parallel.c) emission paths.
  • Adds focused unit + pipeline tests reproducing #1355 and validating behavior for sequential vs parallel indexing.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_registry.c Adds unit tests for the new suppression predicate’s contract and edge cases.
tests/test_pipeline.c Adds an end-to-end fixture + assertions to verify the regression is fixed in both sequential and parallel resolvers.
src/pipeline/registry.c Implements cbm_suppress_external_import_shadow() plus helpers.
src/pipeline/pipeline.h Exposes the new suppression predicate in the public pipeline header.
src/pipeline/pass_parallel.c Invokes the guard in the parallel call-resolution emission path.
src/pipeline/pass_calls.c Threads file_imports into resolution and invokes the guard in the sequential emission path.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/test_pipeline.c Outdated
Comment on lines +4744 to +4746
char *old_workers = getenv("CBM_WORKERS");
char *saved_workers = old_workers ? strdup(old_workers) : NULL;
char *old_single = getenv("CBM_INDEX_SINGLE_THREAD");
Comment thread tests/test_pipeline.c Outdated
Comment on lines +4739 to +4742
/* Enough files that CBM_WORKERS can take the fused-parallel path; the same
* tree is then indexed by each resolver in turn, because the guard lives at
* two independent emit sites (pass_calls.c and pass_parallel.c). */
write_external_import_shadow_fixture(tmp, 50);
Comment thread src/pipeline/registry.c Outdated
Comment on lines +460 to +463
* "/abs/x") rather than an external package. Package specifiers are everything
* else — "drizzle-orm", "rxjs/operators", "@scope/pkg". */
static bool specifier_is_relative(const char *module_path) {
return module_path && (module_path[0] == '.' || module_path[0] == '/');
@DeusData DeusData added bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges maintainer-notes Internal observations and improvement notes priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. labels Aug 24, 2026
@DeusData

Copy link
Copy Markdown
Owner

Thank you for the detailed reproduction, the sequential and parallel coverage, and for documenting the known workspace tradeoff explicitly. This changes project-wide import-resolution behavior, so we are reviewing the approach carefully and will come back with a maintainer decision before asking you to rework anything. Our review queue is currently full, so this may take a little time. Thank you for your patience and for making the tradeoff visible.

@DeusData

DeusData commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Reviewed. The predicate is well built, the reproduction is convincing, and there is a standing constraint on this class of change that decides the timing rather than the merit.

The predicate itself

I traced it, and the conjunction is tight in the right way: strategy limited to the four project-wide guesses, callee must be a bare identifier (no ., no ::), the file must have imports, the import map must not bind the name, and only then the external-specifier check. same_module, import_map, qualified_suffix, callee_suffix and every lsp_* strategy are untouched — which is the property that matters most here, because a blocked high-confidence match does not vanish, it demotes.

Excluding relative specifiers on purpose is the right line. A relative path names something inside the tree, so a missing IMPORTS edge there is an in-project gap where the fallback may still be correct. Getting that distinction the wrong way round would have been an easy and quiet mistake.

And the reproduction earns its conclusion. drizzle-orm's eq/sql binding to unrelated local helpers, identical under CBM_INDEX_SINGLE_THREAD=1 and CBM_WORKERS=4, with normalize from the very same module resolving correctly at 0.95 via lsp_ts_import — that last detail is what rules out "the TS-LSP is broken" and isolates the textual fallback. Confidence reaching 0.75 on a fabricated edge closes off the threshold answer too.

What holds it up

This PR is one of a named cluster — #1128, #1324, #1386, #1702 and this one — and there is a standing decision that they are judged against one shared census rather than one at a time, because whichever lands first shifts the baseline the others are measured on. You already spotted the nearest neighbour yourself: #1386 guards the Python side of the same issue and lands at the same two emission sites.

So this is a sequencing constraint, not a verdict.

Concretely, what would clear it. A change of this shape was accepted recently on four things together, and yours currently shows two of them:

  1. Upstream strategies provably untouched — you have this, and I verified it.
  2. Confidence demonstrably cannot substitute — you have this, with the 0.75 figure.
  3. A measured, per-language blast radius on real graphs — not yet. Edge counts before and after on a few real repositories, split by language, with the removals read by hand, is what turns "this removes fabricated edges" into a number someone can act on.
  4. No per-language seam available — this is the one I would push on. You apply the predicate at pass_calls.c and pass_parallel.c, where the file language is known, so a gate is available and you chose not to use it. Your reason is a real one — the gate is import evidence rather than a name list, and evidence generalises — but it is worth arguing explicitly rather than in passing, because the default here is per-language.

One interaction to check while you are at it: you drop field_type_hint, and #1907 deliberately keeps it for Go on the grounds that a Go struct field carries a declared type, so the hint is receiver-aware there rather than heuristic. I think your conjunction spares Go in practice — Go imports packages, not bare symbols, so the external-binding test should not fire — but that is my reasoning, not a measurement, and it belongs in your census.

Two smaller things

Your known limitation is real and honestly stated. A bare specifier that does name in-project code but fails to materialise an IMPORTS edge — the workspace case in #1732 — now loses its fallback rather than keeping it at reduced confidence. Consulting the package map first, as you suggest, is the right follow-up shape.

Your test / test-msan red is not yours. That job failed building its Docker image: apt-get install clang-22 from apt.llvm.org returned exit 100. No test ran. I have seen the same image build fail on an unrelated PR today, so it is a property of that lane.

A bare call whose name the calling file imports from a package outside the
indexed tree was bound to whatever project symbol shared the simple name.
An `import { eq, sql } from "drizzle-orm"` plus an unrelated local module
exporting `eq`/`sql` produced two CALLS edges from the caller into that
module, strategy unique_name — the same defect on the sequential and the
fused-parallel resolver. The TS-LSP is not involved: it declines the
external names, and the textual registry fallback fires anyway.

The package materializes no node, so resolve_import_node returns NULL, no
IMPORTS edge is written, and the per-file import map carries no key for the
name. Strategies 1-2 miss and resolve_name_lookup binds the call by simple
name. Confidence does not separate the cases: the fabricated edge lands at
0.75 whenever the file also imports anything from the target's module.

Add cbm_suppress_external_import_shadow(), a pure predicate beside the
existing perl/tsjs/cross-language guards and called at the same two emit
sites. It drops the edge only when the callee is a bare identifier, the
strategy is a project-wide guess (suffix_match / unique_name /
field_type_hint / fuzzy), the file imports that exact local name from a
non-relative specifier, and no import-map key binds it. Relative specifiers
are excluded on purpose: they name a path inside the tree, so a missing
IMPORTS edge there is an in-project resolution gap and the fallback can
still be right. A name imported both relatively and from a package keeps
its edge, independently of extraction order.

Addresses the external-import sub-case of DeusData#1355.

Signed-off-by: Yyunozor <yyunozor@icloud.com>
- specifier_is_relative() now also recognizes Windows drive-letter
  (C:\ / C:/) and UNC (\\server\share) specifiers as in-tree, not
  external packages. pr-smoke runs this pipeline on Windows, and the
  previous POSIX-only check ('.' / '/') classified those specifiers as
  external, which could suppress a real edge on that platform only.
  Added external_import_shadow_windows_relative_specifier_kept
  (tests/test_registry.c): red before this fix, green after.
- old_workers / old_single in the DeusData#1355 pipeline test are now
  const char*, matching getenv()'s read-only contract.
- The pad_files literal (50) is now a named
  EXTERNAL_IMPORT_SHADOW_PARALLEL_PAD constant with a comment tying it
  to MIN_FILES_FOR_PARALLEL (a private #define in pipeline.c, not
  reachable for a static_assert from tests), so a future bump to that
  threshold can't silently drop the fixture back onto the
  sequential-only path.

Signed-off-by: Yyunozor <yyunozor@icloud.com>
…ort guard

A per-language blast-radius census on twelve public repositories found one
regression class in the DeusData#1355 guard, and it is not per-language: it is
per-topology. In a workspace monorepo a BARE specifier can still name code
inside the indexed tree. `import { eq } from "drizzle-orm"` written inside
the drizzle-orm repository is a sibling package, not a dependency.

Measured on drizzle-team/drizzle-orm at b7862528, full index, both
resolvers: the guard removed 2609 CALLS edges. Resolving each removed
edge's specifier against the repository's own package manifests puts 1377
of them (52.8%) on the file the specifier actually names. 690 of those are
strict: the specifier names a subpath, that subpath maps to one directory,
and the target file is inside it. The other 687 come from the bare package
root, where the check can only confirm the target is somewhere in the
package, so read 690 as the defensible floor. Only 373 removed edges
pointed at a third-party package, which is the defect DeusData#1355 reports.

The same census on eleven other repositories (flask, scrapy, express,
zustand, got, cobra, gin, chi, ripgrep, gson, jq) removed 12 CALLS edges in
total: nine fabricated, one lost (a documentation example importing the
repository's own published name), two weak links between a shell command
and a manifest key. The regression is specific to trees that ship the
package they import.

Consult the pipeline package map before calling a specifier external. It is
keyed by the `name` of every manifest found in the tree, so a workspace
registers each of its own packages there, and a subpath specifier is walked
back one slash at a time ("drizzle-orm/pg-core" -> "drizzle-orm"). A
specifier the tree itself claims is now treated exactly like a relative
one -- kept.

The check is deliberately a NAME test rather than a resolution test. A
workspace package usually points `main` at a build artifact ("./index.cjs")
that is not checked in, so asking whether the entry file exists in the
graph answers "no" for exactly the monorepos this has to protect. Whether
the tree claims the name is decidable from the manifest alone. Passing NULL
restores the previous specifier-shape-only contract, which is what the unit
tests exercise.

After the change the same census removes 391 edges on drizzle-orm, 375 of
them CALLS, and every one resolves to a third-party package; of the other
eleven repositories only got changes, recovering its self-referencing edge.

Signed-off-by: Yyunozor <yyunozor@icloud.com>
@Yyunozor
Yyunozor force-pushed the fix/1355-external-import-shadow branch from f78bfe2 to 797a11a Compare September 4, 2026 21:56
@Yyunozor

Yyunozor commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the review. I ran the census. It found a regression class in my
own patch, so I will start with that.

Summary

  • Twelve public repositories, eight languages, indexed with main (2f9828d6) and this branch. Go, Rust, Java and C are byte-identical; a traced binary shows the predicate never fires there.
  • One regression class, in TypeScript workspaces. On drizzle-orm the published patch removed 2609 CALLS edges, and 690 of them (1377 by a looser reading) were real in-project links: inside a monorepo, import { eq } from "drizzle-orm" names a workspace sibling, not a dependency.
  • The fix, in the new commit, consults cbm_pipeline_get_pkgmap() before calling a specifier external. That is the follow-up shape you named, moved into the fix. drizzle-orm now removes 375 edges, all third-party, 0 regressions; the other eleven repositories are unchanged.
  • The blast radius is per topology, not per language. A per-language gate would have caught nothing. Caveat: one TypeScript workspace measured.
  • fix(pipeline): suppress weak short-name matches for Go selector calls #1907, measured on cobra, gin and chi: #1907 alone and #1907 + this PR produce byte-identical graphs, and every field_type_hint edge in main survives in all four builds.
  • Tests: registry pipeline 337 passed / 0 failed (parent 330 / 0, delta = the 7 added tests). Full suite: 7821 passed / 1 failed, and that failure is identical on the bare parent.
  • Rebased onto 2f9828d6 (106 commits). If you would rather judge the cluster against the version you already read, say so and I will split the package-map commit out.
Full census: per-repository tables, edges read by hand, the #1907 fixture, caveats

3. Measured blast radius, per language

Twelve public repositories, one index with main (2f9828d6) and one with this
branch, both binaries built from source. Edge counts come from the produced
SQLite graph.

language repo before after delta CALLS removed
Python pallets/flask 7420 7419 -1 1
Python scrapy/scrapy 47943 47942 -1 1
TypeScript (pnpm workspace) drizzle-team/drizzle-orm 54338 51723 -2615 2609
TypeScript (single package) pmndrs/zustand 1803 1800 -3 3
TypeScript (single package) sindresorhus/got 5314 5310 -4 4
JavaScript expressjs/express 2169 2166 -3 3
Go spf13/cobra 6065 6065 0 0
Go gin-gonic/gin 12389 12389 0 0
Go go-chi/chi 5043 5043 0 0
Rust (cargo workspace) BurntSushi/ripgrep 24035 24035 0 0
Java google/gson 42207 42207 0 0
C jqlang/jq 7569 7569 0 0

Go, Rust, Java and C are byte-identical before and after. I also built a traced
binary that logs every time the predicate fires. On those four languages it
fires zero times.

drizzle-orm is the problem. I classified all 2609 removed CALLS edges
mechanically: read the import statement in the source file, resolve the
specifier against the repository's own package manifests, compare to the target
file.

verdict n
regression — target IS the file the specifier names 1377 (52.8%)
correction — in-tree package, but wrong sibling file 855
correction — real third-party package (the #1355 bug) 373
import not found (.cjs require()) 4

The 1377 are not all equally strong evidence, so here is the split. In 690 the
specifier names a subpath (drizzle-orm/pg-core), which maps to one directory
(drizzle-orm/src/pg-core/), and the target file sits inside it — a strict
match. In the other 687 the specifier is the bare package root
(drizzle-orm), so the only thing I can check is that the target sits inside
that package; I did not resolve the root's re-exports, so treat that half as
the weaker evidence.

I read 14 of them by hand. pgTable imported from drizzle-orm/pg-core was
bound to drizzle-orm/src/pg-core/table.ts. That is the correct definition, and
my guard removes it. Same for sqliteTable, mysqlTable, varchar,
interval, singlestoreEnum, sql, eq, gt, like, relations,
hammingDistance. The reason is simple: inside the drizzle-orm repository,
import { eq } from "drizzle-orm" names a workspace sibling, not a dependency.

The other eleven repositories removed 12 CALLS edges in total: express 3,
zustand 3, got 4, flask 1, scrapy 1, and zero everywhere else. I read all 12.

  • 9 fabricated. express: createError from http-errors twice, Router
    from router once. zustand: render from @testing-library/react three
    times, all bound to a local ErrorBoundary.render. got: delay from
    node:timers/promises three times.
  • 1 loss. got: got imported from 'got' in a documentation example. That
    is the repository's own published name, so it is the same class as drizzle.
  • 2 debatable. flask and scrapy shell scripts where a CLI tool name was
    linked to a manifest key (pre-commit -> pyproject.toml, coverage ->
    codecov.yml). Weak in both directions.

9 + 1 + 2 = 12.

4. Why there is no per-language gate

The census answers this better than an argument would. The blast radius is not
per language. It is per topology.
The one regression class lives in
TypeScript, which is the language the fix targets. A is_typescript gate would
have caught nothing.

What separates the safe repositories from drizzle-orm is not the language. It is
whether the import map binds. scrapy writes from scrapy.utils.job import job_dir — absolute self-imports, exactly the risky shape — and the import map
binds them, so the predicate returns early and never reaches the specifier test.
drizzle-orm's map does not bind, because drizzle-orm/package.json points
main at ./index.cjs, a build artifact that is not checked in.

So the correct seam is the package map, which is what you called the right
follow-up shape. I moved it into the fix rather than leaving it as a follow-up,
because 690 lost edges on the strict half alone is not a limitation, it is a
defect.

The new commit consults cbm_pipeline_get_pkgmap() before calling a specifier
external. The map is keyed by the name of every manifest in the tree, so a
workspace registers each of its own packages; a subpath is walked back one slash
at a time (drizzle-orm/pg-core -> drizzle-orm). It is deliberately a name
test and not a resolution test, because the declared entry file is usually not
in the repository — an entry lookup answers "no" for exactly the monorepos this
has to protect. Passing NULL restores the previous contract, which is what the
unit tests use.

Same census after the change:

repo before after delta CALLS removed regressions
drizzle-orm 54338 53947 -391 2609 -> 375 1377 -> 0
got 5314 5311 -3 4 -> 3 1 -> 0
express, zustand, flask, scrapy unchanged (3, 3, 1, 1) 0
cobra, gin, chi, ripgrep, gson, jq 0 0 0

got is the only one of the eleven that changes: the self-referencing got edge
comes back. flask's net delta reads 0 rather than -1, but that is not the guard
— its one CALLS removal stands, and an unrelated HANDLES edge reappeared
through the upstream drift described at the end.

All 375 resolve to a third-party package. I read 10: test from vitest,
union from zod, Database from better-sqlite3, createPool from
mysql2, beforeEach from vitest. The 2 "import not found" are CommonJS
require('better-sqlite3') and require('postgres'), so also third-party.

Tests: scripts/test.sh --suites 'registry pipeline' gives 337 passed 0 failed
on the branch and 330 passed 0 failed on bare 2f9828d6. Delta is exactly the 7
tests added.

Each emission site has its own red proof. Replacing cbm_pipeline_get_pkgmap()
with NULL in pass_calls.c alone fails on sequential == 4; doing it in
pass_parallel.c alone fails on parallel == 4; doing both fails on the
sequential assertion first. 336 passed 1 failed in each case, and after each one
both files are restored from the commit and checked by sha256. clang-format
22.1.4 reports the same replacement counts on branch and parent for all six
files.

The #1907 interaction

Your reasoning holds, and here is the measurement. Numbers below are from my
run — please read the absolute totals as such, for a reason I give right after
the table.

repo main this PR #1907 both
cobra 6065 6065 6056 6056
gin 12389 12389 12030 12030
chi 5043 5043 4973 4973

The absolute totals do not travel between indexing sessions. Four fresh
indexations of cobra and chi with the same main binary on my machine agree
exactly (chi 5043 edges / 1456 CALLS / 122 field_type_hint, four times out of
four). An independent replay in another session got chi 5132 / 1521 / 118 and
cobra 6135, with the difference concentrated in the LSP-resolved strategies
(lsp_type_dispatch and unresolved calls). So the counts are stable within a
session and not reproducible across sessions, and I do not know why.

What does hold in both sessions is the comparison, which is what the question
is about. Within one session: main and this PR are identical at the sha256 of
the whole edge set on all three repositories, and #1907 and #1907 + this PR
are identical to each other. And every field_type_hint edge present in main
is still present in all four builds — 122 in chi and 13 in gin in my run, 118
in chi in the other, unchanged in each case.

So my drop-list naming field_type_hint never reaches a Go edge. The
conjunction fails earlier: a Go field_type_hint match is a selector call, and
a Go import binds a package identifier, not a member name. Zero dot-imports in
the 219 Go files measured.

The seam does exist. I built a fixture with import "github.com/unindexed/render"
plus a bare render("hello") call and a project function render. main
produces the fabricated edge, this PR removes it, #1907 leaves it (the call is
bare, so is_method is false), both together behave like this PR. That shape is
not valid Go — the identifier would be both a package and a function — but if it
ever appears, the guard fires in the right direction.

Two notes

The branch was 106 commits behind, so I rebased it onto 2f9828d6. Upstream had
added cbm_suppress_weak_local_binding_call at the same anchors; both sides are
kept.

The known limitation is now narrower but still real. A bare specifier that names
in-tree code with no manifest declaring that name — an unusual bundler alias,
for instance — still loses its fallback. The package map does not see it.

The "per topology, not per language" claim rests on one workspace. drizzle-orm
is the only monorepo of that shape in the census. ripgrep is a cargo workspace
and gson is a multi-module Maven build, and neither fired — but the reason is
call shape (Type::method, Type.method are not bare identifiers), not proof
that the topology is safe there. A Rust repository with many
use crate::...::{function} imports plus bare calls would be the test I have
not run.

Rebasing this changes the diff you already traced. If you would rather judge the
cluster against the version you read, say so and I will split the package-map
commit out.

Repository SHAs used: drizzle-orm b7862528, zustand b57db4f8, got
687eb7dc, express 023767fe, flask d318b683, scrapy ebfb0491, cobra
adbc8813, gin dcaa4296, chi ae6be746, ripgrep 3fce3b5b, gson
b3f4ca20, jq 9d241e27.

Measurement caveats. Running the same main binary twice on flask differs by 21
lines, all HANDLES edges to __route__ANY__/. Separately, the Go absolutes
move between indexing sessions as described above, in the LSP-resolved
strategies. Both drifts are upstream and unrelated to this diff, but together
they mean absolute edge counts in this comment should be read as one run's
figures, not as constants; the before/after comparisons within a session are the
part that reproduced. Full suite on this branch: 7821 passed, 1 failed, 7 skipped, 141/141 suites;
bare parent 2f9828d6 on the same machine: 7813 passed, 2 failed. The delta is
exactly the 7 tests this branch adds. The one branch failure is
tests/test_cli.c:9502 (VS Code-only install detection) and it fails the same
way on the bare parent, so it is this machine, not the diff. The parent's second
failure is the test_mcp.c:12540 timing flake (4 of 5 parent runs, 1 of 4 branch
runs).

@Yyunozor

Yyunozor commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

One correction to my last note: I have since run the full suite on this branch (797a11a1), not only registry pipeline.

Branch: 7821 passed, 1 failed, 7 skipped, 141/141 suites. Bare parent 2f9828d6 on the same machine: 7813 passed, 2 failed. The delta is exactly the 7 tests this branch adds.

The one failure on the branch is tests/test_cli.c:9502 (VS Code-only install detection). It fails the same way on the bare parent, so it is this machine, not the diff. The parent's second failure is the test_mcp.c:12540 timing flake; it failed in 4 of 5 parent runs and 1 of 4 branch runs, so it is not related to the diff either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working maintainer-notes Internal observations and improvement notes parsing/quality Graph extraction bugs, false positives, missing edges priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants