Skip to content

fix(ingest): a C++ member call with explicit template arguments minted no call reference - #243

Merged
joyful-ii-V-I merged 2 commits into
mainfrom
lane/template-call-edges
Sep 17, 2026
Merged

joyful-ii-V-I merged 2 commits into
mainfrom
lane/template-call-edges

Conversation

@joyful-ii-V-I

@joyful-ii-V-I joyful-ii-V-I commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator

Defect

A C++ member call whose callee carries explicit template arguments minted no call reference at all:
r.get<K>( 1 ), p->get<K>( 1 ), x.template get<K>(), this->template get<K>(). The callee parses as
field_expression field: (template_method …) — inside a dependent_name behind the template keyword — and no C++
reference pattern bound either shape. The drop happened at extraction, before ambiguous=/unresolved= could count
it.

Measured 2026-09-16 on main 3bf884e2, a four-line repro:

struct R { template<class E> E get( int n ) { return E( n ); } int plain( int n ) { return n; } };
enum class K : unsigned char { A, B };
int useTemplate( R& r ) { return int( r.get<K>( 1 ) ); }
int usePlain( R& r ) { return r.plain( 1 ); }

--callers=get --no-cache → count="0"; --callers=plain → count="1". Every verb reading the call graph
under-counted these calls (--callers, --uses, --impact, --safe-delete), and --quality-delta could call a
method reached only this way kind="dead-code".

Two more wrong answers in the same family, on the qualified dependent form (which did extract):

  • X::template make<int>() minted a reference named template make, which resolves to nothing.
  • X::template Rebind<int>::f() keyed its qualifier as template Rebind, so the canonical tier missed and the call
    split over a same-named definition in another scope.

Free f<T>( x ) and qualified ns::f<T>( x ) (the std::get<0>( t ) shape) were already bound; the gate keeps them
as controls.

Change

Measured

Pre-fix vs fixed binary on this repo's src/ (169 files, --no-cache, map header + ripwire_probe reference count):

references edges ambiguous unresolved
pre-fix (f8e6087c) 168,457 18,308 7,788 1,677
fixed 168,463 18,309 7,788 1,677

The six new references are exactly the r.pod<T>() reads in src/gitoracle.h's loadOracleCache:
--uses=pod 1 → 7, and --callers=pod now names loadOracleCache beside Reader::str.

On a template-heavy tree the effect is three orders of magnitude larger. Same binaries (fixed = built_from=1171f7757),
llvm-project 4d5358b1d, clang/include + clang/lib, 2,515 files:

references edges ambiguous unresolved
pre-fix (f8e6087c) 1,855,925 409,860 81,601 3,893
fixed 1,866,100 (+10,175) 413,767 (+3,907, +0.95%) 82,573 (+972) 3,893

--callers=getAs 48 → 492, --callers=hasAttr 45 → 377. On clang/lib/AST (155 files) the reference delta
(246,367 → 248,394, +2,027) equals the new shape's --match hit count exactly (2,027, hits_capped="0"), so extraction
moved only the intended class.

The new sites inherit the plain member call's resolution, wrong binds included. FD->hasAttr<PackedAttr>() in
ASTContext::getDeclAlign (ASTContext.cpp:1878) binds Type::hasAttr(attr::Kind) at lib/AST/Type.cpp:2026, not
Decl::hasAttr<T>() (DeclBase.h:585), with no amb=. In a reduced five-file repro the plain FD->plainAttr() binds
Type::plainAttr(int) the same way on f8e6087c. A resolver defect this change widens the reach of; not fixed here.

Gates

test/cppqualcheck.sh §12 — new corpus test/cppqualtmplfix/member.cpp. It has one hand-read literal per
spelling: member dot and arrow, x.template, p->template, this->template, nested >> arguments, a chained
receiver, X::template, X::Y::template, and a comment after the keyword. It also has four controls the old
patterns already bound, receiver/arity/qualifier decoys, the fixture header (symbols=43 edges=19 ambiguous=0 unresolved=0), and a repo-root arm (--callers=pod names loadOracleCache).

Arm (g), added from the review (F4): the spellings still not bound, each a literal zero behind a source-presence
guard — r.f<0>( x ) (two comparisons; exactly one role="read" row), r.Base::f<T>() and p->Base::f<T>() (the
plain r.Base::f() is pinned 0 too: the qualified-field family), and r.operator()<T>(). These pass on both binaries by
construction: fences for a future widening.

Red first:

  • pre-fix binary: 77 PASS / 19 FAIL. The 19 are every new check except the four controls, the determinism arm and
    (g)'s six absence pins. Header edges=6 ambiguous=1.

  • mutation build, the same tree with three one-line reversions (8 FAIL), each mechanism reddening its own arms:

    • receiverOf reading the raw parent → tqDecoyCaller binds the decoy :110.
    • skipTemplateDisambiguator inert → the three dependent --uses read 0, the probe name arm fails, and
      tqCallRebind splits onto :133.
    • callArity's hop bound 4 → 3 → tqDepArityCaller splits over both overloads.

    Reverted: the diff is byte-identical to before and the rebuilt binary is byte-identical to the fixed one.

  • fixed: 96/96 plain; ALL PASS with asan/ripwire.

test/callformcheck.sh row 11 — b.template memberTmpl<int>() was pinned documented-absent (literal 0 +
probeBlind); it now pins 1 + probeSees. Red on the pre-fix binary: 2 FAIL; green on the fix.

Also run: qextractionkeycheck ALL PASS, qschemetripcheck ALL PASS after the re-pin, printffmtparitycheck ALL PASS
(42 verbs), manifestcheck, chainguardcheck, cudacheck ALL PASS; docs/gatecount_build.py --check (618,
unchanged — no new gate script) and docs/limits_build.py --check clean; --edit-check on receiverOf,
immediateScope and captureTagsFacts: status="unchanged" incompatible="0".

G1: LSAN_OPTIONS=suppressions=lsan_suppressions.txt ./asan/ripwire over test/cppqualtmplfix, test/callformfix/cpp,
a scratch deep-dependent corpus, and src/, plus asan/ripwire_probe on the fixture: rc 0, zero sanitizer lines.

--quality-delta=$(git merge-base origin/main HEAD)..HEAD: regressions="0" gating="0" (api-new-surface="3" —
the three new helpers).

Full suite, one run each, nothing else in flight, python3 test/pargates.py . ./build/ripwire -j 6:

  • at 1171f775: gates=632 pass=630 skip=2 fail=0 wall=800.9s
  • at 6b234717: gates=632 pass=630 skip=2 fail=0 wall=837.8s (queued 2,520 s behind two peer suites)

The two skips are the environmental argvdiffcheck and editchecknotecheck (asan/ is present and fresh, so
g1freshcheck ran and passed).

Not fixed here

  • Resolver misbinds the new sites inherit from the plain member call (see Measured). Parameter-type narrowing
    specifically is fix(resolve): a member call through a typed parameter was pinned to the caller's own class #248's (train 2, ahead of this PR), so the fixture keeps a LOCAL receiver for the climb arm.
  • Rust member turbofish w.m::<T>() has the same extraction drop (review F3) — a follow-up lane, not this PR.
  • a.b < c > (d) now mints a call named b (F5); X::template operator()<T>() still binds nothing (F6). Both rare.

Pins moved

  • test/qschemetrip.hash — 24fd4dd9… → 01ea4c63… (kParserVer line; RE-PIN LOG entry in test/qschemetripcheck.sh)
  • kParserVer / kIngestParserVerMirror 96 → 99 on the branch; train 2 assigns the landing number (101)
  • test/cppqualcheck.sh §12 fixture header literal symbols=43 → 54 (commit 6b234717, the §12e block; edges stay 19)
  • test/callformcheck.sh row 11: literal 0 → 1

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed missing call and usage detection for C++ member functions invoked with explicit template arguments, including dot, arrow, dependent, and qualified forms.
    • Improved receiver and name resolution for these calls, including calls using the template disambiguator.
    • Corrected impact analysis, caller/usage results, safe-delete checks, and quality reports so affected methods are no longer incorrectly reported as unused.
  • Tests

    • Added comprehensive coverage for template-call extraction, resolution precision, and deterministic analysis results.

…d no call reference

`r.get<K>( 1 )`, `p->get<K>( 1 )` and `x.template get<K>()` produced no reference at all. The callee
parses as call_expression function: (field_expression field: (template_method name: (field_identifier)))
and, behind the `template` keyword, field: (dependent_name (template_method ...)). No C++ reference
pattern bound either shape, so the drop happened at EXTRACTION, before ambiguous=/unresolved= could see
it. Measured 2026-09-16 on main 3bf884e: a four-line repro answered --callers=get count="0" beside
--callers=plain count="1"; --quality-delta reported a method reached only this way as dead-code.

The same family had two more wrong answers on the QUALIFIED dependent form, which did extract:
`X::template make<int>()` minted a reference NAMED `template make` (resolves to nothing), and
`X::template Rebind<int>::f()` keyed its qualifier as `template Rebind`, so the canonical tier missed and
the call split over a same-named definition in another scope.

Fix:
- queries/cpp/tags.scm: one alternation pattern binds both member shapes, @name on the field_identifier.
- src/ingest_binds.h: receiverOf reads calleeAccessParent, which steps over template_method and
  dependent_name to the field_expression. Without it `other.pick<int>()` classified as a BARE call and
  the enclosing-class rule bound it to the caller's own same-named method.
- src/ingest_names.h: skipTemplateDisambiguator (keyword plus whitespace/comments), applied to the
  qualifier inside immediateScope and to the name in cppResplitRefName — the H4 re-split block moved out
  of captureTagsFacts, whose complexity is measured; behaviour is unchanged for every other spelling.
- kParserVer 96 -> 99 and kIngestParserVerMirror -> 99 in the same commit (open PRs #235 hold 97/98 and
  #233 98 — next-free rule); kCacheVersion stays 22. test/qschemetrip.hash re-pinned via UPDATE_GOLDEN=1
  with a RE-PIN LOG line; kQSnapCacheScheme stays 12.

Measured effect (pre-fix vs fixed binary, this repo's src/, 169 files, --no-cache): references 168,457 ->
168,463, edges 18,308 -> 18,309, ambiguous=/unresolved= unchanged. The six references are exactly the
`r.pod<T>()` reads in src/gitoracle.h's loadOracleCache: --uses=pod 1 -> 7.

Gate: test/cppqualcheck.sh §12 with a new corpus test/cppqualtmplfix/member.cpp — one hand-read literal
per spelling (member dot/arrow, x.template, p->template, this->template, nested `>>` arguments, a chained
receiver, X::template, X::Y::template, a comment after the keyword), four controls the old patterns
already bound (free, qualified, non-type argument, 3-segment static), receiver/arity/qualifier decoys, the
fixture header, and a repo-root arm (--callers=pod names loadOracleCache).
- RED on the pre-fix binary: 19 of the 24 new checks FAIL (71 PASS / 19 FAIL); header edges=6 ambiguous=1.
- RED on a MUTATION build (three one-line reversions of the fix, 8 FAIL): the raw parent in receiverOf
  binds tqDecoyCaller to the decoy :110; an inert skipTemplateDisambiguator zeroes the three dependent
  --uses, fails the probe name arm and splits tqCallRebind; callArity's hop bound 4 -> 3 splits
  tqDepArityCaller. Reverted; the rebuilt binary is byte-identical to the fixed one.
- GREEN: 90/90 plain and ALL PASS under the ASan build; sanitizer-clean over the fixture, callformfix/cpp
  and src/.
test/callformcheck.sh row 11 (`b.template memberTmpl<int>()`) was documented-absent at literal 0 with a
probeBlind; it now pins 1 with a probeSees (red on the pre-fix binary: 2 FAIL).

Not fixed here, and routed around in the fixture rather than pinned (both on main already, both shared by
the plain member call): Rule 2 reads no PARAMETER type, so a call on a `Target&` parameter inside a class
with a same-named method binds the enclosing class; and a typed receiver splits over a same-class overload
set with no arity prune.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 396c5d28-2da7-43dc-87f9-3e90a6be4ba3

📥 Commits

Reviewing files that changed from the base of the PR and between f8e6087 and 1171f77.

⛔ Files ignored due to path filters (1)
  • test/qschemetrip.hash is excluded by !test/*.hash
📒 Files selected for processing (11)
  • CHANGELOG.md
  • queries/cpp/tags.scm
  • src/ingest_binds.h
  • src/ingest_cache.h
  • src/ingest_names.h
  • src/ingest_sidecap.h
  • src/quality.h
  • test/callformcheck.sh
  • test/cppqualcheck.sh
  • test/cppqualtmplfix/member.cpp
  • test/qschemetripcheck.sh

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The parser now extracts C++ member calls with explicit template arguments, preserves receiver classification, removes template leakage from qualified names, updates parser identity values, and adds regression coverage.

Changes

C++ member template call handling

Layer / File(s) Summary
Call extraction and receiver classification
queries/cpp/tags.scm, src/ingest_binds.h
The C++ query now binds plain and dependent member-template call shapes. Receiver lookup skips template_method and dependent_name wrappers.
Qualified name normalization
src/ingest_names.h, src/ingest_sidecap.h
C++ reference re-splitting now removes the template disambiguator and preserves qualified names, including operator and comment-separated forms.
Versioning and regression validation
src/ingest_cache.h, src/quality.h, test/cppqualtmplfix/member.cpp, test/cppqualcheck.sh, test/callformcheck.sh, test/qschemetripcheck.sh, CHANGELOG.md
Parser identity values move from 96 to 99. Tests cover extraction, resolution, decoys, determinism, XML output, and cache scheme behavior. The changelog records the fix.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: andriytyurnikov

Merge Risk: ⚪ Minimal · up to 1171f

The member-template extraction update has matching version metadata and regression coverage, with no supported merge-blocking issue identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.88% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 43 functions across 9 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: fixing C++ member calls with explicit template arguments that failed to produce call references.
Full details: Docstring Coverage

Explanation

Docstring coverage is 34.88% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 43 functions across 9 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lane/template-call-edges

Comment @coderabbitai help to get the list of available commands.

@joyful-ii-V-I

Copy link
Copy Markdown
Collaborator Author

CodeRabbit pass read, head 1171f775. The review on open covered f8e6087c..1171f775, the whole diff, with no actionable comments, no nitpicks and no out-of-diff notes. Merge risk: Minimal. No fix commit follows, so no re-review is requested.

  • Docstring Coverage (34.88% < 80%): not a project rule. House style is a // rationale comment above each function, and the three new helpers have one: calleeAccessParent, skipTemplateDisambiguator and cppResplitRefName. The percentage also counts gate shell functions and pre-existing functions in the touched files.

CI is green on the same head: every release shard, both asan legs, rhel and fallback-emitter.

@joyful-ii-V-I joyful-ii-V-I added this to the 0.6.2 milestone Sep 16, 2026
@joyful-ii-V-I

Copy link
Copy Markdown
Collaborator Author

Independent review of 1171f775: NEEDS-FIX (small). The code is correct.

What was verified:

To fix:

  • F2 (conflict): CHANGELOG.md conflicts with main a55b118e (ci(release): Intel macOS binaries end with 0.6.1; the installer says so instead of failing on a missing asset #240's entry). Merge main; CI must re-run on the new head.
  • F1 (docs): "Measured" covers only src/ (+1 edge). On clang include+lib the change adds +10,175 references, +3,907 edges and +972 ambiguous, with unresolved unchanged. Please add that row, and say the new sites resolve the same way the plain member call does. Example: FD->hasAttr<PackedAttr>() binds Type::hasAttr(attr::Kind), and the plain spelling misbinds the same way on main (a separate resolver issue, not this PR's).
  • F4 (fold into the same push): pin the still-missed spellings at 0 in cppqualcheck §12: r.f<0>( x ) (parsed as a comparison), r.Base::f<T>(), r.operator()<T>().

Not in this PR:

  • F3: Rust x.m::<T>() has the same drop (--uses 0 vs 1). That goes to a follow-up lane.
  • F5/F6: a.b < c > (d) now mints a call named b, and X::template operator()<T> keeps its keyword. Both are rare.

CodeRabbit: 0 actionable; the docstring-coverage warning is declined.

Re-pins: kParserVer 99 is fine. Whichever of #243/#244/#235/#233 lands later re-bumps and re-pins qschemetrip.hash. #244 also edits receiverOf in ingest_binds.h; keep both edits, since the new C++ step is inert for TS/JS.

… no pin, and the CHANGELOG measured only src/

Review of #243 (F1, F4). Two gaps, no code change.

F4 — the family's documented-absent spellings were unpinned, although callformcheck.sh's own header says
those rows are the point: a later widening that starts binding one of them, correctly or not, moved no pin.
test/cppqualtmplfix/member.cpp gains a §12e block at the END (no existing line literal moves), and
test/cppqualcheck.sh gains arm (g): each spelling behind a SOURCE presence guard, then a literal zero.
- r.f<0>( x ) without `template`: tree-sitter reads two comparisons -> --callees=tqCallLiteralArg 0, and
  --uses=tqLiteralArgTmpl is exactly one role="read" row at member.cpp:158, no call row.
- r.Base::f<T>() and p->Base::f<T>() -> --callees=tqCallBaseQual 0; the plain twin r.Base::f() -> 0 too,
  so the gap is the qualified-field family, not a template one.
- r.operator()<T>() -> --callees=tqCallOperatorTmpl 0.
All six measure 0 on the pre-fix binary f8e6087 and on the fix alike: fences, not evidence. Header literal
symbols 43 -> 54 (3 structs, 4 member functions, 4 callers), edges stay 19. The first cut of the read-row
arm FAILED on the fix for a gate reason: `role="call"` also occurs in the full legend text, so the no-call
check now greps the <u> rows only.

F1 — the CHANGELOG's only measurement was this repo's src/ (+6 refs, +1 edge), which reads as negligible.
Measured with the pre-fix (f8e6087) and fix (built_from=1171f7757) binaries, --no-cache, map header plus
ripwire_probe's reference total, on llvm-project 4d5358b1d clang/include + clang/lib (2,515 files):
references 1,855,925 -> 1,866,100 (+10,175), edges 409,860 -> 413,767 (+3,907), ambiguous 81,601 -> 82,573
(+972), unresolved 3,893 unchanged; --callers getAs 48 -> 492, hasAttr 45 -> 377. On clang/lib/AST the
reference delta (246,367 -> 248,394, +2,027) equals the new shape's --match hits (2,027, hits_capped="0").
The entry now also says the new sites inherit the plain member call's resolution, wrong binds included:
FD->hasAttr<PackedAttr>() in ASTContext::getDeclAlign binds Type::hasAttr(attr::Kind) at lib/AST/Type.cpp:2026
with no amb=, and in the reviewer's reduced repro the plain FD->plainAttr() binds Type::plainAttr(int) on
f8e6087. Every number above re-measured in this lane, not copied from the review.

Wording that goes stale in train 2: #248 makes Rule 2 read parameter types, so "Rule 2 reads no parameter
type" is dropped from the CHANGELOG, and the gate/fixture comments now date it ("measured on main f8e6087
... #248 changes that").

Gates: cppqualcheck 96/96 plain and ALL PASS under asan/ripwire; pre-fix binary 77 PASS / 19 FAIL (the same
19 as before). callformcheck, gateexitcheck, manifestcheck ALL PASS; gatecount_build --check (618) and
limits_build --check clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@joyful-ii-V-I

Copy link
Copy Markdown
Collaborator Author

Disposition of the independent review of 1171f775: one push, one new commit, 6b234717 (tests and docs only; src/ unchanged).

  • F1 FIX (6b234717): the CHANGELOG and the PR body now carry the clang measurement. I re-measured it here with both binaries rather than copying it: llvm-project 4d5358b1d clang/include + clang/lib, refs +10,175, edges +3,907, ambiguous +972, unresolved unchanged; clang/lib/AST Δrefs 2,027 = shape hits 2,027. The entry also says the new sites inherit the plain member call's resolution, wrong binds included. I reproduced getDeclAlign's hasAttr<PackedAttr> → Type.cpp:2026, and the reduced plain plainAttr() repro on f8e6087c.
  • F4 FIX (6b234717): cppqualcheck §12 arm (g) pins six literal zeros, each behind a source-presence guard: r.f<0>( x ) (exactly one role="read" row), r.Base::f<T>(), p->Base::f<T>(), the plain twin r.Base::f(), and r.operator()<T>(). Results: pre-fix 77 PASS / 19 FAIL (the same 19), fix 96/96, asan ALL PASS.
  • F2: not done on this branch. The CI_HANDOFF train protocol supersedes it: lanes stop merging main, integration train 2 resolves the CHANGELOG conflict and assigns kParserVer.
  • F3 SKIP: the Rust member turbofish is a follow-up lane.
  • F5 SKIP. F6 SKIP: measured on the fix, X::template operator()<int>() extracts under the name operator (no keyword) and binds no edge.
  • F7 DECLINE: docstring coverage is not a house rule.
  • Also: the CHANGELOG no longer says Rule 2 reads no parameter type, because fix(resolve): a member call through a typed parameter was pinned to the caller's own class #248 changes that in the same train. The gate and fixture comments now date that measurement to f8e6087c.

Checks at 6b234717:

  • Full suite: gates=632 pass=630 skip=2 fail=0 (environmental skips only).
  • quality-delta (merge-base range): regressions="0" gating="0".
  • Generators: gatecount_build --check (618) and limits_build --check are clean.

No CodeRabbit re-review requested: this push is tests and docs.

@joyful-ii-V-I

Copy link
Copy Markdown
Collaborator Author

This PR is part of integration train 2b, #275, and will show as merged when that train lands.

@joyful-ii-V-I
joyful-ii-V-I merged commit befc4a7 into main Sep 17, 2026
1 check passed
aniruddhaadak80 pushed a commit to aniruddhaadak80/ripwire that referenced this pull request Sep 17, 2026
…ntity with the template arguments in its scope

`template <class T> void Box<T>::grow() {}` minted `sc="Box<T>"` beside the in-class declaration's
`sc="Box"`, so one member was two identities: --callers=Box::grow resolved to the declaration and
answered count="0" while `use( Box<int>& b ) { b.grow(); }` sat in plain sight, with --impact and
--uses the same. qualifierOf and enclosingScopeOf read the scope node's TEXT, so a multi-line list put
its line break into the census id, and `Slot<std::string>` (a `::` inside the list) was cut by
immediateScope to `string>`. The reference side had the twin at two segments: `Factory<int>::make()`
qualified as `Factory<int>`, keyed nothing, and split onto an unrelated `Decoy::make`.

Fix: a scope tree-sitter hands over as a `template_type` keeps only its `name:` child
(cppScopeSegmentText), in the qualified declarator, a class specialization's name, and each link of a
qualified class name (cppScopeNameText, which returns the written text unchanged when no link is a
template). Structural, so nothing inside the list can unbalance it.

Decision: a specialization's member keys the PRIMARY template's member (`template<> void
Box<int>::grow()` is one more definition of Box::grow, joined like an overload). The resolver does no
template-argument deduction, so no call site can reach a `Box<int>` identity; the argument spelling is
not canonical; Rust `impl<T> Foo<T>` and the C++ 3-segment ref re-split already strip. The full
argument is in the gate header.

kParserVer 96 -> 100 with kIngestParserVerMirror (97..99 are held by open lanes redhat-et#248/redhat-et#244, redhat-et#235/redhat-et#233,
redhat-et#243); kCacheVersion stays 22; qschemetrip re-pinned with a log entry. kMaxQualifierHops hoisted so the
two chain walkers share one cap (LIMITS.md unchanged at 212).

Measured (--pin-census, same corpus both binaries): dgl f0b7cc9, 343 C/C++/CUDA files — scope ids with
an argument list 156 -> 0; 77 of 32,628 decided sites change: 48 corrected targets + 1 wrong split
gone, 22 same id now split (primary + specialization both define the member: the join's cost,
disclosed as amb=), 6 mechanism label only; header edges 20,829 -> 20,745, ambiguous 1,891 -> 1,899.
This repo: 4 symbols move (dynamic_map.hpp node_rank specializations), no edge changes.

Gate: test/cpptmplscopecheck.sh (new, registered in regression.sh, shard weights, gate count 619).
Red on b1489df: 27 of 36 FAIL (the 9 passes are the control, presence guards, determinism and two
by-construction arms). Green: ALL PASS. Pin moved: test/stdqualcheck.sh §3 `hash<Mine>` -> `hash`
(fixture comment updated in place, line count unchanged).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aniruddhaadak80 pushed a commit to aniruddhaadak80/ripwire that referenced this pull request Sep 17, 2026
…ation/train-2b

Conflicts and resolutions (rerere disabled):
- src/graph.h (S6-C tie-break): redhat-et#254 capped the shared credit (`std::min( sharedLocality(...), localityCap )`) and redhat-et#256
  replaced sharedLocality with localityRank (doubled share + own-scope bonus). Combined: localityRank now takes the
  cap as `shareCap` and applies it before doubling. The cap binds only an untyped NamedVar receiver, the bonus only an
  unqualified bare or `this->` call, so no call meets both.
- src/resolve.h: adjacent insertions — train 2's receiver/std helpers (namesStdType … buildScopedRecvDecls) kept
  first, then redhat-et#256's localityRank and appendTemplateFamilyKey.
- src/ingest_sidecap.h + src/ingest_names.h, the redhat-et#243 x redhat-et#256 recipe (ffa17084/e24f6c51): redhat-et#243's deletion of the H4
  re-split block kept; inside redhat-et#243's cppResplitRefName both qualifier lines use cppRefQualifierText;
  cppResplitRefName moved below cppRefQualifierText; cppRefQualifierText steps over skipTemplateDisambiguator on its
  last segment (cppqualcheck §12 (d)'s tqCallRebind arm needs it).
- src/ingest_cache.h / src/quality.h: kParserVer and its mirror -> 102 (the PR declared 100; after redhat-et#243's 101).
- test/qschemetripcheck.sh: redhat-et#256's RE-PIN LOG entry renumbered to 102, above redhat-et#243's. test/qschemetrip.hash:
  placeholder kept, re-derived once on the final tree.
- test/regression.sh: loop is the union (cpptmplscopecheck + crashsweepcheck); docs/gatecount_build.py wrote 622.
- .github/pargates-shard-weights.json: union (cpptmplscopecheck.sh 4.4, crashsweepcheck.sh 15.0).
- CHANGELOG.md: main's side kept at the conflict; redhat-et#256's entry placed after redhat-et#243's, heading renumbered to 102.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aniruddhaadak80 pushed a commit to aniruddhaadak80/ripwire that referenced this pull request Sep 17, 2026
… no lane hashed the merged declaration lines

kParserVer and its mirror are 102 after the train's merge-order assignment (redhat-et#244 100, redhat-et#243 101, redhat-et#256 102); each lane's
pin hashed its own number over its own base. One RE-PIN LOG entry for the train; kCacheVersion 22 and
kQSnapCacheScheme 12 unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aniruddhaadak80 pushed a commit to aniruddhaadak80/ripwire that referenced this pull request Sep 17, 2026
…t#244's Lit* helpers and the gate-local runner idiom

--quality-delta=$(git merge-base origin/main HEAD)..HEAD on the train reported gating=10:
- 8 rows on PR redhat-et#244's model.h helpers isJsTsLitRecv / jsLitCtorName / isJsTsBuiltinCtor, which match short enum
  switches and OR-of-equality predicates elsewhere by shape, not by shared logic;
- 2 new-clone-of-reused-helper rows on the gate-local run()/cnt()/defs() idiom, whose count moved 3 -> 5 because
  redhat-et#243's and redhat-et#256's gates now share one tree. redhat-et#256's own ack at 3 is healed to 5.
Acked through the binary (--quality-ack --ack-only), ledger +10/-1; the range then reads gating=0 acked=13. Minor,
non-gating rows remain: buildGraph cx 780 -> 794, receiverOf cx 4 -> 12, collectFieldUseSites LOC 183 -> 189,
captureSpecializationHeader params=8.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aniruddhaadak80 pushed a commit to aniruddhaadak80/ripwire that referenced this pull request Sep 17, 2026
… reduced CI, redhat-et#270 std member uses) into integration/train-2b

Conflicts and resolutions (rerere disabled):
- src/resolve.h: the field lane (a23f4ec) split recordFlatRecvType into recordFlatRecvTypeFact + a thin Binding wrapper;
  redhat-et#270 reworded recordFlatRecvType's comment because collectFieldUseSites now calls it too. The field lane's split is
  kept and redhat-et#270's wording moves onto the wrapper, which redhat-et#270's call site (graph.h collectFieldUseSites) still uses.
- CHANGELOG.md: redhat-et#270's entry placed with main's entries, before this train's (redhat-et#243, redhat-et#256, field lane).
Shared products re-derived on the merged tree, neither side taken: kParserVer/mirror stay 102 (redhat-et#270 does not bump);
test/qschemetrip.hash 1b26f3c0 re-checks ALL PASS (no manifest function or declaration line changed); the gate loop
still names 622 (redhat-et#269 adds no gate script); docs/LIMITS.md matches.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aniruddhaadak80 pushed a commit to aniruddhaadak80/ripwire that referenced this pull request Sep 17, 2026
…'s head)

At the coordinator's direction 1b now sits on train 2b (redhat-et#243, redhat-et#244, redhat-et#256,
field-final-segment, plus 2b's own reconciles). When redhat-et#275 merges, 1b's diff
against main shrinks to its own delta. Main 13a1916 was already in 1b.

Conflicts, all shared products:
- test/regression.sh: the loop is the union.
- README.md, docs/EVALS.md, deck5: gate-count markers only (630 vs 625). Main's
  side is kept here and the count is regenerated in the next commit.

Everything that merged clean without a textual conflict is re-derived on the
merged build in the commits that follow, not trusted: the ack ledger,
qschemetrip (2b 31d4ca8d), kParserVer (102), cppqualcheck's readWholeFile,
hazardpatterncheck's registry, printf_parity, LIMITS/TUNING and shard weights.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

train-member Lands through an integration train; runs the light CI set

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant