Skip to content

Commit 35c4358

Browse files
committed
wip(scripts): the checklist declares the tilde range and counts append-only hits unjudged
Claude-Session: https://claude.ai/code/session_01PPd7QqomCKXskDb8wkVgDV Co-authored-by: Claude <noreply@anthropic.com>
1 parent ce79cd8 commit 35c4358

2 files changed

Lines changed: 161 additions & 12 deletions

File tree

‎scripts/check-platform-checklist.mjs‎

Lines changed: 151 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,12 @@ const SELF_TEST_BATTERIES = Object.freeze({
11291129
// case that a citation both grammars already agreed on keeps its verdict, the
11301130
// over-firing refusal on this ledger's own colon-then-digit neighbours, and
11311131
// the live reading with its control.
1132-
[BATTERY_LINE_CITATION_BINDING]: 9,
1132+
//
1133+
// 9 → 18 at #24894: the tilde-range declaration (D4), the card's own pins
1134+
// through this corpus's declarations (C1 to C3), and the append-only filter
1135+
// driven both ways on a synthetic document (E1 to E5), its ⛔ not-wider case
1136+
// included.
1137+
[BATTERY_LINE_CITATION_BINDING]: 18,
11331138
// 40 → 42 at #18107, and the SHAPE of the battery changed under it: the 25
11341139
// detector/resolver cases that pinned this file's own forked grammar moved
11351140
// into `scripts/symbol-anchors.mjs`'s battery (93 → 122 there) and 27 took
@@ -1700,6 +1705,79 @@ export const NEIGHBOURING_MAP: Readonly<Record<string, string>> = Object.freeze(
17001705
// carries none of its own. `selfTestLineCitationBinding` below is that, driven
17011706
// live in both directions on a synthetic corpus — the citation is a finding
17021707
// with the declaration, and is not one without it.
1708+
//
1709+
// ⭐ Two spellings still went through (#24894), and the fix took the same exit:
1710+
// the core was widened, ⛔ no detector came back here. The COMMA form — a
1711+
// path, a comma, a line spec, no space — is now a row of the shared path-
1712+
// anchored grammar for every corpus, and the bare TILDE RANGE is the core's
1713+
// fourth corpus declaration, `tildeRangeCitations`, which this corpus makes.
1714+
// This ledger had accumulated 42 comma citations before a hand sweep moved
1715+
// them to symbol anchors; nothing refused the 43rd.
1716+
//
1717+
// What stays LOCAL is one thing the core cannot know: which text in THIS
1718+
// ledger is append-only. A `history[*]` row quotes what an item used to say,
1719+
// and `FOLLOW-UPS.md` is the sweeps' decision register ("append, never
1720+
// rewrite"); both were written before any gate read these two spellings, and
1721+
// rewriting a record to pass a gate falsifies the record. So a finding in the
1722+
// two NEW spellings inside that text is counted and NOT judged
1723+
// (`appendOnlyLineCitation`). ⛔ It is a filter on the sweep's findings, keyed
1724+
// on WHERE a finding sits — never a grammar, and never wider than the two
1725+
// spellings: a colon-form citation in a history row is judged exactly as
1726+
// before, because no measured population needs it excused.
1727+
1728+
/* The documents of this family that are append-only as a whole. A path under
1729+
* `CHECKLIST_REL`, compared against a finding's `doc`. */
1730+
const APPEND_ONLY_DOCS = Object.freeze([`${CHECKLIST_REL}/FOLLOW-UPS.md`]);
1731+
1732+
/**
1733+
* The 1-based line ranges of every `"history"` array in one JSON document,
1734+
* inclusive at both ends. A character walk that tracks string state, so a
1735+
* bracket or the word inside a string value is payload — never a parse that
1736+
* would lose the line numbers the sweep reports findings against.
1737+
*/
1738+
function historyLineRanges(text) {
1739+
const ranges = [];
1740+
const open = [];
1741+
let line = 1;
1742+
let inString = false;
1743+
let escaped = false;
1744+
let stringStart = -1;
1745+
let lastString = null;
1746+
let key = null;
1747+
for (let i = 0; i < text.length; i += 1) {
1748+
const c = text[i];
1749+
if (c === '\n') line += 1;
1750+
if (inString) {
1751+
if (escaped) escaped = false;
1752+
else if (c === '\\') escaped = true;
1753+
else if (c === '"') { inString = false; lastString = text.slice(stringStart + 1, i); }
1754+
continue;
1755+
}
1756+
if (c === '"') { inString = true; stringStart = i; continue; }
1757+
if (c === ':') { key = lastString; continue; }
1758+
if (c === '[' || c === '{') { open.push({ history: c === '[' && key === 'history', start: line }); key = null; continue; }
1759+
if (c === ']' || c === '}') {
1760+
const top = open.pop();
1761+
if (top?.history) ranges.push([top.start, line]);
1762+
key = null;
1763+
continue;
1764+
}
1765+
if (c === ',') key = null;
1766+
}
1767+
return ranges;
1768+
}
1769+
1770+
/**
1771+
* Is this sweep finding one of the two #24894 spellings, sitting in text this
1772+
* ledger keeps append-only? `readDoc` answers a finding's `doc` with its text,
1773+
* so the self-test can drive the rule on a synthetic document.
1774+
*/
1775+
function appendOnlyLineCitation(finding, readDoc) {
1776+
if (finding.kind !== 'line-anchor' || !(finding.comma || finding.tildeRange)) return false;
1777+
if (APPEND_ONLY_DOCS.includes(finding.doc)) return true;
1778+
if (!finding.doc.endsWith('.json')) return false;
1779+
return historyLineRanges(readDoc(finding.doc)).some(([from, to]) => finding.line >= from && finding.line <= to);
1780+
}
17031781

17041782
/**
17051783
* ⛔ NOT a grammar, and not a detector — the two things this limb used to be.
@@ -1735,13 +1813,19 @@ function selfTestLineCitationBinding() {
17351813
&& !/\bfunction\s+findLineCitations\w*\b/.test(OWN_SOURCE));
17361814
t('D3 CONTROL for D2 — the same source read DOES find the declaration, so a green above is "no fork" and not "the read returned nothing"',
17371815
/pathlessLineCitations:\s*true/.test(OWN_SOURCE) && /sweepCorpus\(CORPUS, ROOT\)/.test(OWN_SOURCE));
1816+
t('D4 the corpus DECLARES the tilde range too — this ledger wrote one, and without the declaration the shared grammar does not read it',
1817+
CORPUS.tildeRangeCitations === true);
17381818

17391819
// ── the binding, BOTH DIRECTIONS on the SAME text ────────────────────────
17401820
//
17411821
// ⭐ The declaration is read off `CORPUS` rather than written as a literal,
17421822
// so deleting it from the registration fails B1 instead of leaving a case
17431823
// that passes on a flag nothing reads.
1744-
const declared = { unspannedAnchors: CORPUS.unspannedAnchors, pathlessLineCitations: CORPUS.pathlessLineCitations };
1824+
const declared = {
1825+
unspannedAnchors: CORPUS.unspannedAnchors,
1826+
pathlessLineCitations: CORPUS.pathlessLineCitations,
1827+
tildeRangeCitations: CORPUS.tildeRangeCitations,
1828+
};
17451829
const cited = 'ManifestSchema id :140 and the leg ~L7246-7331';
17461830
t('B1 ON — a path-less citation in THIS ledger’s shape is read as a line anchor by the shared grammar, through the declarations this corpus makes',
17471831
extractAnchors(cited, declared).lineAnchors.length === 2,
@@ -1759,11 +1843,60 @@ function selfTestLineCitationBinding() {
17591843
t('B4 the neighbours this ledger is full of stay silent under the declaration — an HTTP status, a config literal, a URL port, a clock time and JSON quoted in prose',
17601844
extractAnchors('status:409 {maxRetries:3} http://localhost:3000/_console/ 08:00 {"scannedTypes":1}', declared).lineAnchors.length === 0);
17611845

1846+
// ── #24894: the two spellings that went through, in THIS ledger's shape ──
1847+
// The card's own pins, through this corpus's declarations. The grammar's
1848+
// full battery (every neighbour, both directions) is the core's.
1849+
const lineRaws = (text, opts = declared) => extractAnchors(text, opts).lineAnchors.map((l) => l.raw);
1850+
t('C1 the COMMA form is refused — a path, a comma and a line, and a path, a comma and a range',
1851+
lineRaws('see foo.ts,123 and foo.ts,123-140').join() === 'foo.ts,123,foo.ts,123-140',
1852+
JSON.stringify(lineRaws('see foo.ts,123 and foo.ts,123-140')));
1853+
t('C2 the TILDE RANGE is refused through this corpus’s declaration, and is NOT read without it',
1854+
lineRaws('createColumn ~7354-7368').join() === '~7354-7368'
1855+
&& lineRaws('createColumn ~7354-7368', { ...declared, tildeRangeCitations: false }).length === 0);
1856+
t('C3 a COUNT after a file name and a history index are admitted — the loose comma is prose',
1857+
lineRaws('pinned by foo.test.ts, 12 cases; see history[1]').length === 0);
1858+
1859+
// ── #24894: append-only text is counted, not judged ──────────────────────
1860+
// ⭐ Driven on a synthetic document through the SAME rule the live loop
1861+
// uses, in both directions: the same spelling one array over IS judged.
1862+
const fixtureDoc = `${CHECKLIST_REL}/areas/fixture.json`;
1863+
const fixture = [
1864+
'{', // 1
1865+
' "items": [', // 2
1866+
' {', // 3
1867+
' "fixtures": { "knownGaps": ["createColumn ~7354-7368"] },', // 4 judged
1868+
' "history": [', // 5
1869+
' { "revision": 1, "change": "had foo.ts,123 [sic]" },', // 6 quoted
1870+
' { "revision": 2, "change": "cut createColumn ~7354-7368" }', // 7 quoted
1871+
' ],', // 8
1872+
' "verify": "then foo.ts,123 again"', // 9 judged
1873+
' }', // 10
1874+
' ]', // 11
1875+
'}', // 12
1876+
].join('\n');
1877+
const readFixture = (doc) => (doc === fixtureDoc ? fixture : '');
1878+
const findingAt = (line, extra) => ({ kind: 'line-anchor', doc: fixtureDoc, line, raw: 'x', comma: false, tildeRange: false, ...extra });
1879+
t('E1 the history array is found by its lines, and a bracket inside a string value does not end it',
1880+
JSON.stringify(historyLineRanges(fixture)) === '[[5,8]]', JSON.stringify(historyLineRanges(fixture)));
1881+
t('E2 a comma citation and a tilde range INSIDE a history row are not judged',
1882+
appendOnlyLineCitation(findingAt(6, { comma: true }), readFixture)
1883+
&& appendOnlyLineCitation(findingAt(7, { tildeRange: true }), readFixture));
1884+
t('E3 CONTROL — the same two spellings OUTSIDE the history array ARE judged',
1885+
!appendOnlyLineCitation(findingAt(4, { tildeRange: true }), readFixture)
1886+
&& !appendOnlyLineCitation(findingAt(9, { comma: true }), readFixture));
1887+
t('E4 FOLLOW-UPS.md is append-only as a whole, for the two new spellings only',
1888+
appendOnlyLineCitation({ kind: 'line-anchor', doc: APPEND_ONLY_DOCS[0], line: 1, comma: true }, readFixture)
1889+
&& !appendOnlyLineCitation({ kind: 'line-anchor', doc: `${CHECKLIST_REL}/README.md`, line: 1, comma: true }, readFixture));
1890+
t('E5 ⛔ NOT wider than the two spellings — a colon-form citation in a history row is still judged',
1891+
!appendOnlyLineCitation(findingAt(6, {}), readFixture)
1892+
&& !appendOnlyLineCitation({ kind: 'line-anchor', doc: APPEND_ONLY_DOCS[0], line: 1 }, readFixture));
1893+
17621894
// ── the LIVE reading, so the zero above the console line prints is a
17631895
// reading and not an instrument that stopped ──────────────────────────
17641896
const liveSweep = sweepCorpus(CORPUS, ROOT);
1765-
const liveLineAnchors = liveSweep.findings.filter((f) => f.kind === 'line-anchor');
1766-
t('B5 the live family carries NO line citation — the class the migration deleted has not come back',
1897+
const readLive = (doc) => readFileSync(join(ROOT, doc), 'utf8');
1898+
const liveLineAnchors = liveSweep.findings.filter((f) => f.kind === 'line-anchor' && !appendOnlyLineCitation(f, readLive));
1899+
t('B5 the live family carries NO judged line citation — the class the migration deleted has not come back',
17671900
liveLineAnchors.length === 0,
17681901
liveLineAnchors.map((f) => `${f.doc}:${f.line} ${f.raw}`).join(', '));
17691902
t('B6 CONTROL for B5 — the same sweep over the same family DID read anchors, so the zero above is a reading and not a sweep that reached nothing',
@@ -1916,6 +2049,12 @@ function selfTestLineCitationBinding() {
19162049
// projection is a corpus saying its judged text is authored PROSE; this
19172050
// one declares none and sweeps its documents raw. That test is
19182051
// mechanical, and this registration passes it.
2052+
// `tildeRangeCitations: true` (#24894) The third path-less spelling, a bare
2053+
// approximate range continuing a filename already named; this ledger
2054+
// carried one in an item's fixtures until a hand sweep re-pointed it.
2055+
// Legal here by the same registration test as the option above. The
2056+
// measurement of what it reads in the corpora that do NOT declare it is
2057+
// with the grammar, `scripts/symbol-anchors.mjs#TILDE_RANGE_CITATION`.
19192058
//
19202059
// The dotted `#Outer.member` form this ledger's grammar carried is now the
19212060
// shared grammar's, and `sweepCorpus` requires EVERY segment to resolve — the
@@ -1934,6 +2073,7 @@ const CORPUS = defineCorpus({
19342073
excludeDirs: ['runs'],
19352074
unspannedAnchors: true,
19362075
pathlessLineCitations: true,
2076+
tildeRangeCitations: true,
19372077
});
19382078

19392079
// ── The residual the binding measured (#16898) ────────────────────────
@@ -3534,8 +3674,14 @@ for (const [doc, c] of sweep.byDoc) {
35343674
anchorCounts.set(rel, c.declaration + c.literal);
35353675
}
35363676

3677+
// The two #24894 spellings inside append-only text: counted and printed, NOT
3678+
// judged (see `appendOnlyLineCitation`).
3679+
let appendOnlyCitations = 0;
3680+
const readSweptDoc = (doc) => readFileSync(join(ROOT, doc), 'utf8');
3681+
35373682
for (const f of sweep.findings) {
35383683
const rel = relToChecklist(f.doc);
3684+
if (appendOnlyLineCitation(f, readSweptDoc)) { appendOnlyCitations += 1; continue; }
35393685
if (f.kind === 'unresolved-symbol') {
35403686
const anchor = `${f.path}#${f.symbol}`;
35413687
// On the measured residual? Then this is one of the 56 the binding
@@ -3640,7 +3786,7 @@ console.log(
36403786
` traps: ${TRAPS.size} documented, ${usedTraps.size} in use;` +
36413787
` provisioning: ${recipeTotal} area recipes, ${recipeRefs} item references resolved (${qualifiedRefs} area-qualified), ${recipesReferenced}/${recipeTotal} recipes referenced;` +
36423788
` meta-URL spelling: ${metaCallsScanned} \`call\` strings scanned against ${FOLDED_META_SPELLINGS.size} folded spellings;` +
3643-
` line citations: 0 survive across ${sweep.counts.docs} swept documents — \`file:line\`, a bare \`:NNN\` continuation and an \`L\` pin are all judged by \`symbol-anchors.mjs\`, through the same registration;` +
3789+
` line citations: 0 survive across ${sweep.counts.docs} swept documents — \`file:line\`, the comma form \`file,line\`, a bare \`:NNN\` continuation, an \`L\` pin and a tilde range \`~NNN-MMM\` are all judged by \`symbol-anchors.mjs\`, through the same registration (${appendOnlyCitations} comma or tilde-range citation(s) in append-only text — \`history\` rows and FOLLOW-UPS.md — counted, not judged);` +
36443790
` symbol anchors: ${anchorsResolved}/${anchorsScanned} resolved by \`symbol-anchors.mjs\` (the ONE resolver, reached as a REGISTERED corpus) across ${sweep.counts.docs} swept documents against ${sweep.counts.citedSources} cited sources` +
36453791
`, ${anchorsResidual} on the named #16898 residual, ${Object.keys(anchorFloors).length} file floors held;` +
36463792
` (self-checks: ${trapControl.checked} trap-vocabulary + ${provisioningControl.checked} provisioning-resolve + ${unreferencedControl.checked} unreferenced-recipe + ${metaCallControl.checked} meta-call-spelling + ${citationControl.checked} line-citation-binding + ${symbolAnchorControl.checked} symbol-anchor + ${plannedStatusControl.checked} planned-status assertions).`,

‎scripts/symbol-anchors.mjs‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,9 @@ const LINE_SPEC = '\\d+(?:\\s*[-–—]\\s*\\d+)?(?:\\s*[,/]\\s*\\d+(?:\\s*[-–
389389
* colon. ⛔ Tight, exactly as the tilde: a comma followed by a SPACE is a list
390390
* or a count after a file name (a test file, a comma, a space, `12 cases`), and
391391
* the loose form was measured to admit three such counts in that ledger. The
392-
* tight form was measured over all five registered corpora before it became a
393-
* row for every corpus, not an option: 11 hits, all in the checklist's
392+
* tight form was measured over all five registered corpora, on `7b047b4483`
393+
* in this repository, before it became a row for every corpus rather than an
394+
* option: 11 hits, all in the checklist's
394395
* `FOLLOW-UPS.md`, and ZERO in `docs/adr/**`, `scripts/**`,
395396
* `packages/spec/src/**` and the `isSystem` census page -- so nothing that
396397
* passed anywhere else can start failing on this row alone, and a citation
@@ -485,11 +486,13 @@ const PATHLESS_L_CITATION = new RegExp('(?<![A-Za-z0-9_])~?L(\\d{2,}(?:-\\d+)?)(
485486
* until a hand sweep re-pointed it, and nothing would have stopped the next.
486487
*
487488
* ⛔ Its OWN declaration, and default OFF, both as MEASUREMENTS. Taken on
488-
* `7b047b4483` in this repository, the tight shape below reads 6 tokens across
489-
* the four corpora that do not declare it: four in `scripts/**` comment prose
490-
* (three durations or counts and one approximate month) and two in
491-
* `docs/adr/**` (one count, one dated read position in a record's prose). In
492-
* prose it is a quantity first; in the checklist's data it is a line pin.
489+
* `7b047b4483` in this repository with the option forced on, it reads 5
490+
* tokens across the four corpora that do not declare it: three in `scripts/**`
491+
* comment prose, every one a duration or a count, and two in `docs/adr/**`,
492+
* one a count and one a dated read position in a record's prose. An
493+
* approximate month in `scripts/**` matched the shape and is refused by the
494+
* ascending rule below. In prose it is a quantity first; in the checklist's
495+
* data it is a line pin.
493496
*
494497
* ⚠️ The shape is tight for the same reason the path-less colon form is: with
495498
* no path in front of it the boundaries ARE the safety margin. No whitespace

0 commit comments

Comments
 (0)