Repository navigation
fix(ci): pair gate resolves declared Pairs-with on an empty surface; record gate strips comments; chart freeze hardening - #7526
Conversation
…; record gate strips comments; chart freeze refuses ancestors and malformed records - check-cross-repo-pair.py: a declared `Pairs-with:` is resolved even when no public type, member or project path left (#7397); malformed declarations fail there too. - check-record-signatures.py: strip // and /* */ comments before counting primary constructor parameters (#7366); census found one live mis-parse (NodeCompilationResult). - check-chart-freeze.py: refuse a non-deletion at an ancestor of a frozen path, and validate the whole status token and the path fields of a saved listing (#7391). Each new self-test case fails against the previous logic and passes now. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved scanner bugs can hide records and let constructor-arity changes pass undetected, while the chart-freeze checker also accepts invalid scored deletions.
3 open issues
What changed in this PR
This PR hardens three CI gates that protect cross-repository landing order, record constructor compatibility, and frozen deployment paths.
Changes:
- Resolves declared
Pairs-with:references even when no public-surface removal is detected. - Strips comments before parsing record signatures and adds regression cases.
- Rejects replacements above frozen paths and strengthens saved-diff validation, with updated tests and documentation.
| File | Description |
|---|---|
src/MeshWeaver.Documentation/Data/Architecture/CrossRepoPairGate.md |
Documents declaration enforcement and comment-aware record parsing. |
src/MeshWeaver.Documentation/Data/Architecture/ChartOwnershipAndRunnerPool.md |
Explains ancestor protection and strict saved-diff validation. |
scripts/check-record-signatures.py |
Adds comment stripping and record-signature regression cases. |
scripts/check-cross-repo-pair.py |
Checks declared counterparts on empty removal reports. |
scripts/check-chart-freeze.py |
Adds ancestor checks, status validation, and regression cases. |
Review effort: Balanced
…reeze refuses scored deletions A mis-bounded literal left text outside any string, where a '/*' opened a phantom comment that hid every later record, so an arity change passed. A raw literal now closes at its own quote count, and interpolation holes are scanned as code. The chart-freeze status reader scores only C/R/M and caps the score at 100, so D100 is refused instead of exempted as a deletion. New self-test cases fail on the previous logic; the src census is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
| if c in "\"'": | ||
| j = _skip_literal(text, j) | ||
| continue |
There was a problem hiding this comment.
Not changing this in round 3. It is a real lexer gap, but you only reach it with a block comment that holds a } INSIDE an interpolation hole and is followed by a literal /* in that same hole. That is far outside how this tree writes C#. Extending the hand lexer to cover comments in holes is hardening beyond this PR's scope, which is the comment stripping for ordinary code that #7366 asked for. I filed it to triage together with the raw-literal case on the sibling thread (rbuergi/Feedback/20261029-record-gate-lexer-comments-and-raw-literals-in-holes), with both repro shapes and a regression-case plan.
| if run >= 3 and not verbatim: | ||
| close = text.find('"' * run, i + run) | ||
| return n if close == -1 else close + run |
There was a problem hiding this comment.
Same answer as the sibling thread. A raw interpolated string whose hole holds another raw literal that contains /* is valid C#, but nothing in this tree is written that way, and following raw-interpolation holes recursively (dollar count included) is a lexer extension rather than a fix to what this PR changes. It is in the same triage item as the comment-in-hole case: rbuergi/Feedback/20261029-record-gate-lexer-comments-and-raw-literals-in-holes.
Test Results 24 files 24 suites 56m 20s ⏱️ Results for commit 4e072a2. |


Three CI gate scripts each passed a case they exist to catch. Each fix ships with self-test cases. Every new case fails against the previous logic (checked by mutating the fix back out) and passes now.
check-cross-repo-pair.py: a declaredPairs-with:is resolved even when no public surface left. The gate returned "no cross-repo pair to gate" before it parsed the body, so a dependency-only or pin-only removal held nothing even when it declared its counterpart (#7205, #7179). Now:Pairs-with:naming a pull request is resolved under the usual merged-into-default-branch verdict, whatever the detector found;Pairs-with: none — …, or no declaration, on an empty surface still passes.Before the fix, 3 of 45 self-tests failed. After it, all 45 pass.
check-record-signatures.py: comments are no longer counted as parameters.//and/* */are stripped before parameters are counted, on both sides of the comparison. String and char literals are kept verbatim, so a//inside"https://…"survives.src/found 837 public records, and ONE parsed differently:NodeCompilationResult, which read as 10 parameters for its real 9. So the defect is live today, not latent.//inside a string default, and a commented-out record. With the strip removed, 3 fail.check-chart-freeze.py: two gaps closed.deploy/aksreplaced by a symlink) is now refused.--diff-filelisting is read strictly: the whole status token must be valid, and every path field must be present and non-empty.DgarbageandR100with no destination used to pass.Before the fix, 4 of 26 cases failed. After it, all 26 pass.
--base origin/mainis still clean.Doc pages updated:
Architecture/CrossRepoPairGate.md(the declaration section, and a new "Comments are not parameters" section) andArchitecture/ChartOwnershipAndRunnerPool.md.Not established, and not changed here:
check-type-forwards.py(_positional_parameters) has the same comment blindness. OnNodeCompilationResultit indexes two phantom members,Structuredandtable. That script is a subject of the parser-delta control, so a change to its counts needs its own declared pull request. It is filed for triage separately.Pairs-with: none — CI scripts and docs only; no public C# surface, project path or package pin changes
Closes #7397
Closes #7366
Closes #7391
🤖 Generated with Claude Code