Repository navigation
fix: a C# verbatim identifier is not a duplicate-qn marker (#2017) - #2113
Conversation
|
@greptileai review |
|
Warning Review limit reachedNext included review available in 1 second. View limit detailsLimit details: You’ve used all 8 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Repository: vitali87/code-graph-rag/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Scope note, so the boundary is explicit rather than an oversight. Three sites already had a CORRECT marker-stripping implementation before this PR and are left untouched: They are still three more spellings of one grammar, which is the property #2017 is about — so I have filed #2114 rather than widening this PR into working code. Each needs a different entry point ( What this PR does change is every reader that was WRONG: eight in production plus two in |
|
@coderabbitai review CodeRabbit is rate limited on this head and has not reviewed it.
Third time today across #2106, #2110 and this PR, so recording the shape rather than just re-triggering: the check bucket reads The test I am using per bot, for anyone auditing behind me:
Greptile and Copilot are still outstanding at |
|
🐇 ✏️ Learnings added
|
|
|
Pushed The peer session on #1912 hit a test that passed for the wrong mechanism, which prompted me to re-examine my own. I found my structural check was keyed to one literal spelling — Replaced it with an AST matcher over any
suffix = marker.split(cs.DUP_QN_MARKER, 1)[1] # [1], not [0]
line_text = suffix.split(cs.DUP_QN_COLUMN_MARKER, 1)[0]For Fixed with Mutation-verified: reverting it reddens 3 tests (2 behavioural + the AST check). The marked-non-verbatim test correctly stays green — that path works either way, so it is a no-regression pin, not a defect test. 41 tests now. Re-triggering the bots at this head since the push invalidated the 5/5 anchored to @greptileai review |
|
Gate status at Satisfied: Greptile 5/5 anchored to Outstanding: Copilot has produced no review on this PR at all, and no Timeline Two things keep this from being a conclusion:
So: request status unknown, review absent. I am not retrying a third time — the CLAUDE.md is explicit that impatience here produced three retries and a false failure report on a previous occasion. The only signal that settles it is a review whose Not blocking on it either: I will say plainly that Copilot has not reviewed this PR rather than treat its silence as approval. |
|
Pre-checked the two SonarCloud rules that failed on my other PRs today, so the queue wait is not also a surprise wait.
Identical on every file. That is the expected result for this change — it replaces inline logic with helper calls, which can only reduce branching in the caller — but the absolute counts look alarming on their own, and the baseline comparison is what makes them readable. Caveat stated rather than glossed: ruff's C901 is CYCLOMATIC complexity while S3776 is COGNITIVE. Related metrics, not the same one, so this is corroboration and Sonar remains the authority.
Neither is a substitute for the gate. Both are cheap, and the failure mode they prevent — discovering a Sonar failure after a long queue wait, fixing it, moving the head, and discarding the review anchors — costs a full cycle each time. Current state: Greptile 5/5 genuine at |
|
Sharper than the CodeQL case: this one died in The Two failures now, on two PRs, from the same exhausted installation quota, hitting unrelated jobs at unrelated stages. Around 35 workflow runs have been queued concurrently all evening, which is the obvious source. Not acting on either. I have also stopped polling the API from this session while the quota recovers: more calls against a saturated installation make the condition worse for every session working this repo, not better. Standing position, unchanged on the merits: Greptile 5/5 genuine at |
|



Closes #2017.
The defect
function_registrydisambiguates definitions that share a qualified name by appending@<line>, and_<col>after that when a same-named twin already holds that line. C# spells a keyword-colliding name with a leading@—@event,@lock,@class— so it is the same character in both roles.Every reader that recovered the written name with
qn.split(cs.DUP_QN_MARKER, 1)[0]cut at the first@without checking what followed:Box@12BoxBoxBox@12_5BoxBox@event''@eventpkg.@eventpkg.pkg.@event@event@12''@eventScope
The issue names
_natural_qn; the grep found eight production readers sharing the spelling:graph_updater._natural_qn,dead_code,call_processor,call_resolver(two sites),class_ingest/method_override,class_ingest/mixin,function_ingest.Plus two in the eval oracle (
evals/cgr_graph.py), which grades by "the written name" — precisely what the bug destroys, so a C# fixture with a verbatim-named base class would mis-grade. One of those was spelled across three lines, so a line-anchored grep would not have found it.Meanwhile three sites already had the correct form —
duplicates._DUP_QN_MARKER_RE,trace/resolution._natural_qualified_name, and themixinpartial key that #2014 fixed. The codebase held both answers at once, which is what this consolidates.method_override.pyis worth singling out: its comment already named this exact failure — "would empty out a C# verbatim identifier like@event" — directly above the line that committed it. The hazard was documented and not avoided, so grepping for the concept found the site and it read as handled.The fix
codebase_rag/utils/qn_markers.pyholds the single definition. Two properties matter:DUP_QN_MARKER,DUP_QN_COLUMN_MARKER), so a change to either cannot silently stop the stripping.@event@12) keep its name and lose its marker. A last-@reader without the digit check gets this one wrong too.@1still strips to'', and that is correct: no language here permits an identifier starting with a digit, so it cannot be a verbatim name.A behavioural change beyond the split
call_processorandcall_resolverusedif cs.DUP_QN_MARKER not in last: return ...as an early exit before splitting. That guard is true for@event— it carries the character without a marker — so those sites would have gone on to add a second candidate identical to the first. They now compare against the stripped form and skip the redundant probe.Evidence
Tests were written against the unfixed readers first and confirmed red:
The failing set matched what I predicted before running, which is the check that catches a test failing for an unrelated reason. After the fix: 15/15.
Regression: 642 passed, 3 skipped across the marker-adjacent areas (dead code, overrides, duplicates, partials, call resolution). The 2 errors are the documented Docker/Memgraph baseline on a machine without Docker, identical on
main.Every test drives a shipped reader rather than the helper. A helper that is correct in isolation says nothing about a caller that never invokes it, which is the failure mode that let this bug survive #2014.
Reader coverage
greptile-localreturned 4/5 with one P2: only one of the routed readers was tested. Fixed — three are now driven behaviourally, chosen because they are reachable without graph fixtures:graph_updater._natural_qncall_processor._scope_qn_candidates—pkg.@eventnow yields['pkg.@event'], where before it yielded['pkg.@event', 'pkg.']and the second candidate was the corrupted namedead_code._is_root— the issue's provenance case, a second Goinit@51staying a rootThe remaining five are methods on parser classes whose fixtures would cost more than the assertion is worth. Those get a parametrised structural backstop asserting each module reaches the shared grammar and no longer carries the broken spelling. It is deliberately the weakest thing in the file and the docstring says so.
Mutation-verified rather than assumed. Reverting
call_processorto the pre-fix form reddens 4 tests (2 behavioural, 2 structural); revertingdead_codereddens 2 (structural only — honest evidence that its coverage rests on the backstop). Both restores were verified identical to HEAD afterwards.38 tests, up from 15.