Skip to content

Commit c38eead

Browse files
committed
fix(check-adr-symbol-anchors): the verdict may not claim a census wider than the vocabulary it read
The green line ended `0 line anchors survive.` -- unqualified, and measured false while it printed. Nine pointers of the class the #13556 ruling deleted were live in `docs/adr/**` in two spellings this corpus does not judge: the path-less bare colon continuation (three in one record, the path in a different table cell from the number) and the `L` pin, bare in prose and as a markdown link-target fragment (six across two records). The reading was right; the sentence spoke for the whole class instead of for what it read. So the repair is the CLAIM. `summaryLine()` now names the vocabulary it judged and states that the two path-less spellings are opt-in and off here. Widening instead was MEASURED and is not taken in this change: `pathlessLineCitations: true` on this corpus yields 17 findings across 6 records, 2 of them an ADR's dev-server ports -- correct prose whose only remedy is the maintainer-only exemption marker. The self-test's new battery holds the claim in three parts, and the middle one is the light-on-a-literal control: the corpus DECLARES the narrower vocabulary; the shared grammar really does see the wider one on the same text when asked (so the caveat is a measurement, not a hedge over a rule that matches nothing); and the sentence names both halves and can no longer end in the unqualified form. Flipping the declaration now forces the verdict to be re-stated in the same edit. Battery floor 17 -> 22. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8b92846 commit c38eead

1 file changed

Lines changed: 77 additions & 7 deletions

File tree

‎scripts/check-adr-symbol-anchors.mjs‎

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ import { dirname, join } from 'node:path';
8585

8686
import { gitFreeEnv } from './git-env.mjs';
8787
import { isEntrypoint } from './invoked-as.mjs';
88-
import { ANCHOR_GRAMMAR, defineCorpus, sweepCorpus } from './symbol-anchors.mjs';
88+
import { ANCHOR_GRAMMAR, defineCorpus, extractAnchors, sweepCorpus } from './symbol-anchors.mjs';
8989

9090
/* ── The declared path population (#13519 / check-declared-population-live) ───
9191
* These literals ARE the population this gate reads, and the self-test holds
@@ -137,11 +137,50 @@ export function runCheck(root = process.cwd()) {
137137
process.exit(1);
138138
}
139139

140-
console.log(
141-
`✅ check-adr-symbol-anchors: ${counts.anchors} anchors across ${counts.docs} records resolve — ` +
142-
`${counts.symbol} symbol (${counts.declaration} declaration, ${counts.literal} literal), ` +
143-
`${counts.fileLevel} file-level, ${counts.crossRepo} cross-repo, ${counts.exempt} exempt, ` +
144-
`${counts.continuation} continuation. 0 line anchors survive.`,
140+
console.log(summaryLine(counts));
141+
}
142+
143+
/* ── The verdict may not claim a census wider than the vocabulary it read ──
144+
*
145+
* This line used to end `0 line anchors survive.` -- full stop, no
146+
* qualifier -- and that sentence was measured FALSE while it printed green.
147+
* Nine line pointers were live in `docs/adr/**` at the time, in spellings this
148+
* corpus does not judge: the path-less bare colon continuation (three in one
149+
* record, where the path sat in a different table cell from the number) and the
150+
* `L` pin, both bare in prose and written as a markdown link-target fragment
151+
* (six across two records). The measurement was true, the SENTENCE was not: the
152+
* gate's vocabulary is narrower than the class the #13556 ruling deleted, and
153+
* the verdict spoke for the class.
154+
*
155+
* ⭐ So the repair is the CLAIM, not the reading. The two path-less spellings
156+
* live in the shared grammar already and are OPT-IN per corpus
157+
* (`scripts/symbol-anchors.mjs#defineCorpus`, `pathlessLineCitations`), and
158+
* turning them on HERE was measured before this was written: 17 findings across
159+
* 6 records, of which 2 are an ADR's dev-server ports -- correct prose no
160+
* author can repair, whose only remedy is the maintainer-only exemption marker.
161+
* Widening is therefore a decision with a price tag and not this sentence's to
162+
* make; what this sentence owes is to stop reading as though the decision had
163+
* already gone the other way.
164+
*
165+
* ⛔ Do NOT restore the unqualified form. The self-test pins all three halves
166+
* -- that the corpus DECLARES the narrower vocabulary, that the shared grammar
167+
* really does see the wider one when asked (so the caveat is a measurement and
168+
* not a hedge), and that this sentence names both -- so a future author who
169+
* flips the declaration is made to re-state the claim in the same edit.
170+
*/
171+
export const JUDGED_LINE_SPELLINGS =
172+
'path-anchored, backticked continuation, fenced comment header, tilde';
173+
export const UNJUDGED_LINE_SPELLINGS =
174+
'the two path-less spellings, which continue a filename named earlier in the sentence';
175+
176+
export function summaryLine(counts) {
177+
return (
178+
`✅ check-adr-symbol-anchors: ${counts.anchors} anchors across ${counts.docs} records resolve — `
179+
+ `${counts.symbol} symbol (${counts.declaration} declaration, ${counts.literal} literal), `
180+
+ `${counts.fileLevel} file-level, ${counts.crossRepo} cross-repo, ${counts.exempt} exempt, `
181+
+ `${counts.continuation} continuation. 0 line anchors survive in the ${JUDGED_LINE_SPELLINGS} `
182+
+ `spellings this corpus judges — ⚠️ NOT a census of the deleted class: ${UNJUDGED_LINE_SPELLINGS}, `
183+
+ 'are opt-in and are OFF here (#18899).'
145184
);
146185
}
147186

@@ -177,7 +216,7 @@ function assert(cond, msg) { if (!cond) { console.error(`❌ check-adr-symbol-an
177216
// not red. A battery BELOW its floor means cases stopped running; the remedy is
178217
// to find what stopped registering.
179218
const SELF_TEST_BATTERIES = Object.freeze({
180-
'check-adr-symbol-anchors self-test': 17,
219+
'check-adr-symbol-anchors self-test': 22,
181220
});
182221

183222
// DELETING an entry silences that battery's floor exactly as effectively as
@@ -300,6 +339,37 @@ export function selfTest() {
300339
check(CENSUS_13556.rotRateIsLowerBound === true, 'the 72.1% figure is a LOWER bound and must be declared as one');
301340
check(CENSUS_13556.totalSurface === CENSUS_13556.distinctLineAnchors + CENSUS_13556.continuationAnchors, 'the declared surface must be the sum of its parts');
302341

342+
// 6. ⭐ The verdict's CLAIM, held against the vocabulary it actually read
343+
// (#18899). The three cases are one argument in three parts, and none of
344+
// them is worth anything without the other two:
345+
//
346+
// (a) the narrower vocabulary is this corpus's DECLARATION, not an
347+
// accident of the grammar -- so the caveat names a choice;
348+
// (b) the shared grammar really does see the wider vocabulary when it
349+
// is asked to, on the SAME text -- so (a) is a measurement and the
350+
// caveat is not a hedge against a rule that matches nothing;
351+
// (c) the printed sentence names both halves, and ⛔ no longer ends in
352+
// the unqualified census claim that was measured false.
353+
//
354+
// ⚠️ (b) is the light-on-a-literal control, and it is the case that makes
355+
// this battery worth running: without it, (a) and (c) would both hold just
356+
// as well on a day when `pathlessLineCitations` had stopped matching
357+
// anything at all, and the caveat would be documenting a dead rule.
358+
const pathlessProbe = 'The mirror of :626 and the pin L198 both continue a filename named earlier.';
359+
const asDeclared = extractAnchors(pathlessProbe, { pathlessLineCitations: CORPUS.pathlessLineCitations });
360+
const widened = extractAnchors(pathlessProbe, { pathlessLineCitations: true });
361+
check(CORPUS.pathlessLineCitations === false,
362+
'the narrower vocabulary must be this corpus\'s DECLARATION — flip it and the verdict below must be re-stated in the same edit');
363+
check(widened.lineAnchors.length === 2,
364+
`the shared grammar must SEE both path-less spellings when asked, or the verdict's caveat documents a dead rule — got ${widened.lineAnchors.length}`);
365+
check(asDeclared.lineAnchors.length === 0,
366+
`and must not see them under this corpus's declaration, or the caveat is simply wrong — got ${asDeclared.lineAnchors.length}`);
367+
const verdict = summaryLine({ anchors: 1, docs: 1, symbol: 1, declaration: 1, literal: 0, fileLevel: 0, crossRepo: 0, exempt: 0, continuation: 0 });
368+
check(verdict.includes(JUDGED_LINE_SPELLINGS) && verdict.includes(UNJUDGED_LINE_SPELLINGS),
369+
'the verdict must name BOTH the vocabulary it judged and the one it did not');
370+
check(!/line anchors survive\.\s*$/.test(verdict),
371+
'the verdict must not end in the unqualified claim `0 line anchors survive.` — that sentence printed green while nine pointers of the deleted class were live');
372+
303373
// ── The floor: every declared battery RAN, and ran its cases (#13489) ────
304374
//
305375
// Evaluated after every battery has had its chance and BEFORE the verdict, so

0 commit comments

Comments
 (0)