Skip to content

fix(registry): drop unique_name CALLS across language boundaries - #1702

Open
rudi193-cmd wants to merge 4 commits into
DeusData:mainfrom
rudi193-cmd:fix/1572-unique-name-language
Open

rudi193-cmd wants to merge 4 commits into
DeusData:mainfrom
rudi193-cmd:fix/1572-unique-name-language

Conversation

@rudi193-cmd

Copy link
Copy Markdown
Contributor

What does this PR do?

Follow-on to #1647 / #725. That PR dropped suffix_match CALLS when caller language ≠ target file language and left unique_name (candidates == 1) for this issue.

Python from unittest.mock import patch was binding to a unique TSX function patch via unique_name. The same helper now drops unique_name under the same rules: JS/TS/TSX stay one family; same_module / import_map / lsp_* stay.

Not in this PR: treating unittest.mock as an external specifier, IMPORTS-edge cleanup, #1555 receiver disambiguation, or #1128.

Checklist

  • Every commit is signed off (git commit -s) — required, CI rejects
    unsigned commits (DCO, see CONTRIBUTING.md)
  • Tests pass locally (scripts/test.sh --suites registry,pipeline)
  • Lint passes (make -f Makefile.cbm lint-ci)
  • New behavior is covered by a test (reproduce-first for bug fixes)

Fixes #1572

Made with Cursor

@rudi193-cmd
rudi193-cmd requested a review from DeusData as a code owner August 18, 2026 01:37
@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.

@rudi193-cmd

Copy link
Copy Markdown
Contributor Author

CI red on this PR is not the #1572 change.

Every failing shard dies on the same two tests, both predating this branch:

  • cli_zero_argument_tool_never_reads_stdin_issue1359
  • cli_stdin_args_gate_tracks_tool_schema_issue1359

list_projects now advertises pagination properties (offset, limit, include_details) on main. The #1359 gate treats “has properties” as “read stdin”, so cli list_projects is allowed to slurp stdin again and the tests that pinned “no properties / no stdin” go red. Sibling PRs off the same main (#1697, #1698, #1699) fail the same way.

Windows shard 2/2 also has an unrelated UTF-8 compare (raw-??????? content vs raw-Русский content in test_mcp.c).

scripts/test.sh --suites registry,pipeline was green locally for the unique_name tests. Not folding a #1359 schema-gate fix into this PR.

@DeusData DeusData added bug Something isn't working 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. labels Aug 18, 2026
@DeusData

Copy link
Copy Markdown
Owner

Thank you for keeping this to the remaining unique_name cross-language case and explicitly excluding the adjacent import, receiver, and external-specifier work. That is the atomic boundary we need. The reported CI failures are also correctly left out of this diff rather than being bundled into the resolver fix. It is labeled as a high-priority graph-quality bug; the final review will verify same-language-family behavior and the negative cross-language cases before any merge decision.

@DeusData

DeusData commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Picking this up, and doing the review that was promised on 18 August rather than leaving you waiting further. Sorry it took two weeks.

Your CI diagnosis was right, and there is now an extra fact you could not have had. Both of those tests — cli_zero_argument_tool_never_reads_stdin_issue1359 and cli_stdin_args_gate_tracks_tool_schema_issue1359 — pass on the current tree. I ran the full suite an hour ago: 7781 passed, 7 skipped, 0 failed, with both of those green. So the base defect you identified has since been fixed, and a rebase should clear your red without you touching anything.

One caveat before you rebase: main does not currently compile. Two changes landed the same type short-name index into type_registry.h and git merged them into duplicate struct members, so anything built against main right now fails. #1993 is the repair. Rebase after that lands, not before, or you will trade one unexplained red for another.

The review

The two things the 18 August note said would be verified before any merge decision — same-language-family behaviour, and the negative cross-language cases — both hold.

The production change is two lines: unique_name joins suffix_match in the strategy allowlist of the existing cbm_suppress_cross_language_suffix_match. Nothing else in registry.c moves. That is the right shape for this repo — a per-language-gated helper wired at both pass_calls.c and pass_parallel.c, rather than a restriction inside cbm_registry_resolve itself.

cross_language_unique_name_drops_py_vs_tsx asserts the cases that matter, including the ones a weaker suite would omit:

  • suppressed in both directions (Python → .tsx, TSX → .py), not just the one from the issue
  • not suppressed same-language
  • same_module, import_map and lsp_direct all explicitly not suppressed
  • JS/TS/TSX kept as one family, with .ts and .js callers of a .tsx target both asserted

That third bullet is the one I care most about, and you tested it. Every existing guard in this file deliberately preserves same_module, because a blocked high-confidence match does not disappear — it demotes into suffix_match, which picks a winner by import distance project-wide. A guard that gated same_module off could lose a correct edge and mint a wrong one in the same step. Yours cannot.

What actually holds it up

Not this PR's quality. It belongs to the call-resolution cluster — #1128, #1324, #1386, this one, #1766 — and there is a standing decision that they are judged against one shared census rather than one at a time. #1128 is the most global member, since it changes strategies inside cbm_registry_resolve while the others add suppressors downstream; whichever of them lands first shifts the baseline and makes the rest unjudgeable on their own numbers.

So this will not merge in isolation, and that is a sequencing constraint rather than a verdict on the change. I would rather tell you that plainly than let it sit silently for another fortnight.

Thank you for holding the scope where you did — excluding the import-edge cleanup, the receiver disambiguation and the external-specifier question was the right call, and it is why this one was quick to read.

@DeusData

DeusData commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Census done — this PR and #1766 were measured together on real graphs (ten languages, ~3.1M CALLS edges, every removed edge classified, three runs each; the two guards compose exactly: removed(both) = removed(#1766) ∪ removed(#1702) on nine corpora with zero additions, so the CALLS sets are deterministic). Widening the guard to unique_name is sound wherever the family rule is right: go −248, rust −128, kotlin −90, django −52, perl −13, ts −43 are all correct false bindings (sh / Makefile / toml / json / css → code — meilisearch's .zip() bound to a Cargo.toml zip 78×, koel's PHP noContent() bound to a .vue file 40×). Three places where the family rule is too coarse and the guard now removes true calls:

  1. C family. The CALLS guard honours only js_ts_family, while the sibling ref guard (registry.c:580) also honours c_cpp_family; .h files are CBM_LANG_CPP, so a C → header call counts as cross-language. dotnet/runtime: −18,866 CALLS (−1.82%), 8,613 of them C-family edges, about 7.5k of those true static-inline / prototype calls (5,443 in src/mono) — e.g. mini-runtime.c:3401 m_type_is_byref(sig->ret) → metadata-internals.h:1294.
  2. JVM family. Gradle/Groovy build scripts → Java build tools: 419 true calls lost in elasticsearch (54% of its removals) — e.g. server/build.gradle:307 t.getComponentName().set("server") → GenerateTestBuildInfoTask.
  3. Vue SFC → TS. ~35 true calls in koel — e.g. AiAssistantScreen.vue:90 playback().queueAndPlay() → QueuePlaybackService.ts:336.

Fix: reuse c_cpp_family in the CALLS guard, add a JVM family (java / kt / kts / groovy / gradle), and put vue / svelte / astro into the js_ts family. With those three the unique_name widening is a pure win on every corpus we measured. Please also rebase — tests/test_registry.c conflicts textually, the src side merges clean. Same sign-off, and this merges on green. Thank you for the patience while the numbers were produced; they are what makes this safe to land.

@rudi193-cmd
rudi193-cmd force-pushed the fix/1572-unique-name-language branch 3 times, most recently from 492e59a to 9e92e67 Compare September 23, 2026 09:15
@DeusData DeusData mentioned this pull request Sep 25, 2026
2 tasks done

@DeusData DeusData left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thank you, @rudi193-cmd, for a careful follow-through. All three family rules from the 5 September census are in, exactly as asked:

  • c_cpp_family now protects C → header calls;
  • jvm_family covers java / kt / kts / groovy / gradle (.gradle and .kts land there through the extension table);
  • vue / svelte / astro joined the JS/TS family.

Each comes with a test, and the branch merges cleanly with current main. Thank you for sticking with this through a long wait.

One thing has to change before we can merge, and I'd rather explain why than just ask. Commits 5770ed83, 8165c340 and f5ec03f0 go past what the census measured. cbm_suppress_cross_language_calls_edge drops every cross-family resolution except same_module and lsp_builtin*, including import_map and in-repo lsp_*. Those are the import- and type-aware strategies that the guard's own contract (registry.c:567-574) promises to keep. We only land suppressors that shed high-confidence edges across all languages per language and with a measured census, and we have no numbers for this one. Several true cross-language cases also fall outside the families:

  • CUDA calling functions declared in .h (it goes through the same C/C++ LSP but isn't in c_cpp_family);
  • Objective-C .m calling C functions in headers;
  • Scala calling Java;
  • inline HTML <script> calling .js.

As far as we can tell, the edges those commits were chasing in the #1572 fixture come from the Python LSP and import_map resolving the external unittest.mock.patch to the in-repo patch. That is the external-specifier problem you rightly scoped out in the PR description, and it deserves its own targeted fix rather than a cross-language veto.

Could you split the branch?

  • This PR keeps 508e8bdc + 0b2bddb8: the measured unique_name widening plus the three families.
  • A follow-up PR takes the LSP / import_map commits, together with the pipeline_..._issue1572 fixture test that needs them. It would target the external-specifier root cause, and we'll measure it on the same corpora.

Two small things while you're in there:

  • tests/test_registry.c:1011 and :1013 are past 100 columns, so make -f Makefile.cbm lint-ci will flag them;
  • the merge commit carries no Signed-off-by, so a plain rebase onto main avoids any DCO question.

After the split we'll re-run the census on the narrowed PR, and it merges on green. Thanks again. The family work is exactly what makes the unique_name fix safe to ship.

@DeusData

Copy link
Copy Markdown
Owner

One addition to the review above, @rudi193-cmd, now that we've decided it: please also widen the families in the narrowed PR, so the unique_name guard doesn't count these as cross-language:

  • CUDA → C/C++ family. .cu / .cuh go through the same C/C++ LSP, so CUDA calling a function declared in a .h is not a cross-language call.
  • Objective-C → C/C++ family. .m calling C functions declared in headers.
  • HTML → JS/TS callers. An inline <script> calling a function in a .js file.

A test per family, in the same style as your C, JVM and Vue ones, would pin them. We'll include these in the census re-run after the split. Thank you!

@rudi193-cmd
rudi193-cmd force-pushed the fix/1572-unique-name-language branch from 5557f0e to 8ffd03e Compare September 26, 2026 20:13
@rudi193-cmd

Copy link
Copy Markdown
Contributor Author

Per review feedback, this branch is now rebased onto main with DCO sign-off and narrowed to the measured #1572 scope only:

  • fix(registry): drop unique_name CALLS across language boundaries (508e8bd)
  • fix(registry): drop unused build_config_language helper (0b2bddb)
  • style(tests): wrap unique_name family ASSERT_FALSE lines for lint-ci

Removed from this PR: LSP / import_map homonym vetoes and the pipeline integration test — those belong in a follow-up that addresses external-specifier / Python LSP without widening cbm_suppress_cross_language_calls_edge beyond the guard contract.

Follow-up work is on rudi193-cmd:fix/1572-external-specifier-lsp (stacked on this branch); I can open a draft PR once #1702 lands or if you prefer it linked now.

@DeusData DeusData left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thank you, @rudi193-cmd. This is a really clean split. The branch now carries exactly the measured unique_name widening plus the C/C++, JVM and Vue/Svelte/Astro families. It's freshly rebased with every commit signed off, and the over-long test lines are fixed. Stacking the LSP / import_map work on fix/1572-external-specifier-lsp rather than folding it in is exactly the right shape. Please keep that as a separate draft for now; we'll measure it on its own.

We'd like to land this one first, with your name on it. Three things before the census re-run, each with the why:

  1. The three families from the 26 Sep addendum aren't in the code yet. c_cpp_family is still C/C++ only, and js_ts_family has no HTML. With unique_name in the guard, each of these would be dropped as cross-language:

    • a .cu file calling a function declared in a .h;
    • an Objective-C .m calling a C header function;
    • an inline HTML <script> calling a .js function.

    They're all true calls. CUDA and ObjC go through the same C/C++ front end, and inline scripts are JS; the weak-member gate in pass_calls.c already treats HTML that way. Could you add CBM_LANG_CUDA and CBM_LANG_OBJC to c_cpp_family, and CBM_LANG_HTML to js_ts_family, each with an assert in the style of your C, Groovy and Vue lines?

  2. .m targets are classified as MATLAB. The guard maps the target language from the filename (cbm_language_for_filename), and in the extension table .m is MATLAB. Objective-C is only detected from file content, during discovery (discover.c). So even with OBJC in the C family, an ObjC→ObjC call between two .m files reads as OBJC→MATLAB and would be dropped. The same applies to the other extensions whose language is decided by content: .cls, .inc, .cfc and .frm. The smallest safe fix is for the guard to return false (keep the edge) when the target's extension is one of those. A test with an ObjC caller and a .m target would pin it.

  3. pipeline_cross_language_unique_name_does_not_share_calls_issue1572 is still in tests/test_pipeline.c (and in the run list). Your note says it moved to the follow-up, and we think it belongs there. The patch edges in that fixture appear to come from the Python LSP / import_map resolving unittest.mock.patch, which this PR deliberately doesn't touch, so it would likely go red here. Could you move it to the stacked branch?

Once those are in, we'll re-run the census on the narrowed PR: the original corpora plus CUDA, Objective-C and HTML-inline-script repos. If it stays a pure win, this merges on green.

A heads-up so nothing surprises you later: we have a broader change of our own in the same area, not yet opened. It applies the same veto to the other name-only strategies, and it uses each file's detected language rather than its extension. We'll rebase it onto yours after this lands, so your work goes in first and ours builds on it.

Thanks again for your patience and care on this one!

rudi193-cmd and others added 4 commits September 27, 2026 07:53
Python `from unittest.mock import patch` to a unique TSX `patch`. Same
language-family guard; JS/TS/TSX stay one family.

Fixes DeusData#1572

Signed-off-by: rudi193-cmd <rudi193@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: rudi193-cmd <rudi193@gmail.com>
Widening unique_name to all callers made the helper dead code; -Werror
unused-function broke CI on the production build.

Signed-off-by: rudi193-cmd <rudi193@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: rudi193-cmd <rudi193@gmail.com>
Signed-off-by: rudi193-cmd <rudi193@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Add CUDA and Objective-C to c_cpp_family, HTML to js_ts_family, and
skip suppression when the target extension is content-disambiguated
(.m, .cls, .inc, .cfc, .frm). Move pipeline DeusData#1572 integration test
to the external-specifier follow-up branch.

Signed-off-by: rudi193-cmd <rudi193@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@rudi193-cmd

Copy link
Copy Markdown
Contributor Author

Addressed the 27 Sep review on fix/1572-unique-name-language (force-pushed, rebased on current main):

  1. Families: c_cpp_family now includes CBM_LANG_CUDA and CBM_LANG_OBJC; js_ts_family includes CBM_LANG_HTML. Registry unit tests added (CUDA→.h, ObjC→.h, HTML→.js).
  2. Content-disambiguated targets: guard returns false (keeps the edge) when the target basename ends in .m, .cls, .inc, .cfc, or .frm — pinned with ObjC caller → Foo.m.
  3. Pipeline fixture: removed pipeline_cross_language_unique_name_does_not_share_calls_issue1572 from this branch (still on fix/1572-external-specifier-lsp for the LSP/import_map follow-up).

Ready for your census re-run when CI settles.

@rudi193-cmd
rudi193-cmd force-pushed the fix/1572-unique-name-language branch from 8ffd03e to b46c6d4 Compare September 27, 2026 13:53
@DeusData

DeusData commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Thank you, @rudi193-cmd, for the September 27 follow-up and for working through the split and family cases we requested. We need more time to review the updated branch and complete the promised census. That next validation step is on the maintainer side; please do not spend time on routine rebases solely to keep this waiting PR fresh. We will follow up here when we have a concrete result or need a specific change. Thanks again for your patience.

This branch has not been deployed

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

Labels

bug Something isn't working 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.

Python stdlib import binds to a same-named TypeScript function (cross-language, strategy=unique_name) — poisons hotspots and Louvain clusters

2 participants