Skip to content

Commit 9a3dfac

Browse files
claude[bot]claude
andauthored
test(scripts): floor five table-driven self-tests on their own row labels (#13799 batch 7a) (#15288)
Recipe A, as settled by the batch 7 pilot: each row's own label in the literal `cases` table becomes a declared battery with a floor of 1, `registerCase()` is the FIRST statement of the driving loop body, and the roster is a LITERAL the table is checked against with its own size pinned at the row count. Files and batteries: check-refd-timer-probe 11, check-skill-compatibility-version 18, check-skill-frame-sync 13, check-skills-token-ratchet 64, check-widget-option-census 16. No assertion condition touched, no control flow rewritten, no comment promoted to a section head, the verdict handshake kept as landed per file. The red-run failure line now reads `N failure(s) (cases and floor)`; the green line is unchanged. Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5b09356 commit 9a3dfac

5 files changed

Lines changed: 637 additions & 5 deletions

‎scripts/check-refd-timer-probe.mjs‎

Lines changed: 114 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,56 @@ export const refdTimeouts = () =>
271271
// handshake is a flag rather than a returned sentinel.
272272
let selfTestReachedVerdict = false;
273273

274+
// ── The self-test's own battery roster and floor (#13489) ──────────────────
275+
//
276+
// A zero failure count used to be this self-test's ONLY success condition, so
277+
// "every case held" and "the cases never ran" printed the same line. Closed the
278+
// PR #13487 way: what is pinned is the registered NAMES, not a number.
279+
//
280+
// This self-test is TABLE-DRIVEN — one literal `cases` table, one loop over it,
281+
// and a sink (`failed += 1`) that writes only when a case FAILS. Routing THAT
282+
// sink through `registerCase()` would register a case only when it fails: a
283+
// fully green run would register 0 and every battery would read DID NOT RUN, the
284+
// floor inverted rather than installed. So the roster is the table's own rows.
285+
// Each row's own `label` is a declared battery, verbatim, with a floor of 1, and
286+
// `registerCase()` is the FIRST statement of the driving loop body — so the case
287+
// is attributed to the row actually being run, whatever that row asserts
288+
// afterwards. It stays first even where the body carries `continue`: the floor
289+
// asserts REACH, and placing it after a guard reintroduces the very inversion
290+
// this shape exists to avoid. There is no `battery()` opener: for a table-driven
291+
// self-test the ROW is the battery, so attribution is the loop variable rather
292+
// than a most-recently-opened section.
293+
//
294+
// ⛔ A pinned TOTAL is not the repair, and neither is a roster DERIVED from the
295+
// table: `cases.length` moves with the table, so a deleted row would delete its
296+
// own floor. The roster below is a LITERAL the table is checked against, which
297+
// is what lets a deleted or renamed row name ITSELF in the refusal.
298+
//
299+
// The counts are a FLOOR, not an equality — a row that grows into several
300+
// registrations must not red. 1 is the honest floor for a table row: the loop
301+
// reaches it exactly once per run.
302+
const SELF_TEST_BATTERIES = Object.freeze({
303+
'the approved module may read the probe → GREEN': 1,
304+
'a raw probe in another package → RED, naming file and line': 1,
305+
'a COMMENT naming the probe → GREEN (prose explains the rule; it does not break it)': 1,
306+
'a BLOCK comment is masked, and a real hit AFTER it keeps its line number → RED at :5': 1,
307+
'a DESTRUCTURED probe → RED': 1,
308+
'a NAMED IMPORT from node:process → RED': 1,
309+
'a BRACKETED member access → RED': 1,
310+
'a .md page discussing the probe is not scanned → GREEN': 1,
311+
'the approved module missing → RED even though no file breaks the rule': 1,
312+
'the approved module present but no longer reading the probe → RED': 1,
313+
'two raw sites → two problems, each named': 1,
314+
});
315+
316+
// DELETING an entry silences that battery's floor exactly as effectively as
317+
// zeroing it, so the roster's own size is pinned too. This pin is also half of
318+
// the duplicate-label refusal: two rows sharing a label collapse to ONE key in
319+
// the literal above, so the roster falls below this number; the table
320+
// cross-check in the floor block is the other half, and names WHICH label
321+
// collided.
322+
const SELF_TEST_BATTERY_FLOOR = 11;
323+
274324
function selfTest() {
275325
const cases = [
276326
{
@@ -374,8 +424,15 @@ function selfTest() {
374424
},
375425
];
376426

427+
// The ledger this self-test's floor is evaluated against (#13489).
428+
const batterySeen = new Map();
429+
const registerCase = (name) => {
430+
batterySeen.set(name, (batterySeen.get(name) ?? 0) + 1);
431+
};
432+
377433
let failed = 0;
378434
for (const c of cases) {
435+
registerCase(c.label);
379436
const { problems } = judge(c.tree);
380437
const isRed = problems.length > 0;
381438
if (isRed !== (c.expect === 'red')) {
@@ -423,8 +480,64 @@ function selfTest() {
423480
console.log(' ✓ the gate excludes itself by identity, not by a listed exemption');
424481
}
425482

483+
// ── The floor: every declared row RAN, and ran its case (#13489) ───────
484+
//
485+
// Evaluated after every row has had its chance and BEFORE the verdict, so the
486+
// success line below can only be printed by a run in which the set of rows
487+
// that registered EQUALS the set declared. A set difference names WHICH row
488+
// stopped; a count says only that something did.
489+
const floorFailure = (message) => {
490+
console.error(`✗ self-test floor: ${message}`);
491+
failed += 1;
492+
};
493+
const declaredBatteries = Object.keys(SELF_TEST_BATTERIES);
494+
let floorBreached = false;
495+
if (declaredBatteries.length < SELF_TEST_BATTERY_FLOOR) {
496+
floorBreached = true;
497+
floorFailure(
498+
`SELF_TEST_BATTERIES declares ${declaredBatteries.length} batteries, below the pinned ` +
499+
`${SELF_TEST_BATTERY_FLOOR} — a battery deleted from the roster takes its own floor with it.`,
500+
);
501+
}
502+
const rowLabels = cases.map((c) => c.label);
503+
const duplicated = [...new Set(rowLabels.filter((name, i) => rowLabels.indexOf(name) !== i))];
504+
if (duplicated.length > 0) {
505+
floorBreached = true;
506+
floorFailure(
507+
`the cases table uses ${duplicated.map((n) => JSON.stringify(n)).join(', ')} as a row label more than once — ` +
508+
'two rows sharing a label are ONE battery, so the second can stop running while the first keeps the floor met.',
509+
);
510+
}
511+
for (const [name, count] of batterySeen) {
512+
if (declaredBatteries.includes(name)) continue;
513+
floorBreached = true;
514+
floorFailure(
515+
`self-test battery "${name}" registered ${count} case(s) but is not declared in ` +
516+
'SELF_TEST_BATTERIES — a case attributed to no declared battery is one nothing floors.',
517+
);
518+
}
519+
for (const name of declaredBatteries) {
520+
const count = batterySeen.get(name) ?? 0;
521+
if (count >= SELF_TEST_BATTERIES[name]) continue;
522+
floorBreached = true;
523+
floorFailure(
524+
count === 0
525+
? `self-test battery "${name}" DID NOT RUN — 0 cases registered, ${SELF_TEST_BATTERIES[name]} pinned. ` +
526+
'The verdict below would have claimed that case holds.'
527+
: `self-test battery "${name}" registered ${count} case(s), below its pinned floor of ` +
528+
`${SELF_TEST_BATTERIES[name]} — cases that used to run no longer do.`,
529+
);
530+
}
531+
if (floorBreached) {
532+
floorFailure(
533+
'A battery at or below its floor means cases STOPPED RUNNING — the battery is the bug, not the ' +
534+
'number. Find what stopped registering (a deleted row, a renamed label, a loop that no longer ' +
535+
'reaches it) and restore it.',
536+
);
537+
}
538+
426539
if (failed > 0) {
427-
console.error(`\n✗ check-refd-timer-probe self-test failed (${failed} case(s)).`);
540+
console.error(`\n✗ check-refd-timer-probe self-test: ${failed} failure(s) (cases and floor).`);
428541
process.exit(1);
429542
}
430543
console.log(`\n✓ check-refd-timer-probe self-test: ${cases.length} cases pass, negative controls included.`);

‎scripts/check-skill-compatibility-version.mjs‎

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,63 @@ function report(problems) {
478478
// handshake is a flag rather than a returned sentinel.
479479
let selfTestReachedVerdict = false;
480480

481+
// ── The self-test's own battery roster and floor (#13489) ──────────────────
482+
//
483+
// A zero failure count used to be this self-test's ONLY success condition, so
484+
// "every case held" and "the cases never ran" printed the same line. Closed the
485+
// PR #13487 way: what is pinned is the registered NAMES, not a number.
486+
//
487+
// This self-test is TABLE-DRIVEN — one literal `cases` table, one loop over it,
488+
// and a sink (`failed += 1`) that writes only when a case FAILS. Routing THAT
489+
// sink through `registerCase()` would register a case only when it fails: a
490+
// fully green run would register 0 and every battery would read DID NOT RUN, the
491+
// floor inverted rather than installed. So the roster is the table's own rows.
492+
// Each row's own `label` is a declared battery, verbatim, with a floor of 1, and
493+
// `registerCase()` is the FIRST statement of the driving loop body — so the case
494+
// is attributed to the row actually being run, whatever that row asserts
495+
// afterwards. It stays first even where the body carries `continue`: the floor
496+
// asserts REACH, and placing it after a guard reintroduces the very inversion
497+
// this shape exists to avoid. There is no `battery()` opener: for a table-driven
498+
// self-test the ROW is the battery, so attribution is the loop variable rather
499+
// than a most-recently-opened section.
500+
//
501+
// ⛔ A pinned TOTAL is not the repair, and neither is a roster DERIVED from the
502+
// table: `cases.length` moves with the table, so a deleted row would delete its
503+
// own floor. The roster below is a LITERAL the table is checked against, which
504+
// is what lets a deleted or renamed row name ITSELF in the refusal.
505+
//
506+
// The counts are a FLOOR, not an equality — a row that grows into several
507+
// registrations must not red. 1 is the honest floor for a table row: the loop
508+
// reaches it exactly once per run.
509+
const SELF_TEST_BATTERIES = Object.freeze({
510+
'the landed wording (exact 17.x pin) → GREEN': 1,
511+
'R1 — a stale major (17.x → 16.x, the #5245 drift) → RED naming file/declared/actual/fix': 1,
512+
'R3 — no `compatibility:` key at all → RED (absence is never a skip, #4690)': 1,
513+
'an empty `compatibility:` value → RED': 1,
514+
'no frontmatter at all → RED': 1,
515+
'R4 — wording switched to an unpinned range (#5245 option ②) → RED, not a silent no-op': 1,
516+
'R4b — zero pins repo-wide with every file exempt → RED via the anti-no-op assertion': 1,
517+
'R5 — an exemption naming a file that is not scanned → RED (anti-dormancy)': 1,
518+
'R7 — an exempt file whose written justification is gone → RED (exemption self-invalidates)': 1,
519+
'an exempt file that grows a pin → RED (the exemption is now dead config)': 1,
520+
'an exempt file whose pin is ALSO wrong → RED on the pin (exemptions never cover a claim)': 1,
521+
'R8 — a half-pinned line (one pinned, one bare mention) → RED on the bare one': 1,
522+
'a pin naming a package the workspace does not have → RED': 1,
523+
'R6 — an empty scan → RED, never a green skip (#4690, the whole point)': 1,
524+
'no workspace packages discovered → RED': 1,
525+
'multi-package line, both pinned correctly → GREEN': 1,
526+
'wording reflowed around a correct pin → stays GREEN': 1,
527+
'a prerelease major still reconciles by major (17.0.0-rc.5 ↔ 17.x) → GREEN': 1,
528+
});
529+
530+
// DELETING an entry silences that battery's floor exactly as effectively as
531+
// zeroing it, so the roster's own size is pinned too. This pin is also half of
532+
// the duplicate-label refusal: two rows sharing a label collapse to ONE key in
533+
// the literal above, so the roster falls below this number; the table
534+
// cross-check in the floor block is the other half, and names WHICH label
535+
// collided.
536+
const SELF_TEST_BATTERY_FLOOR = 18;
537+
481538
function selfTest() {
482539
console.log('check-skill-compatibility-version self-test\n');
483540

@@ -643,8 +700,15 @@ function selfTest() {
643700
},
644701
];
645702

703+
// The ledger this self-test's floor is evaluated against (#13489).
704+
const batterySeen = new Map();
705+
const registerCase = (name) => {
706+
batterySeen.set(name, (batterySeen.get(name) ?? 0) + 1);
707+
};
708+
646709
let failed = 0;
647710
for (const c of cases) {
711+
registerCase(c.label);
648712
let problems;
649713
try {
650714
({ problems } = runAllChecks(c.files, c.pkgs ?? PKGS, EXEMPT));
@@ -755,8 +819,64 @@ function selfTest() {
755819
for (const f of declFailures) console.error(` ✗ dispatch-gates declaration: ${f}`);
756820
failed += declFailures.length;
757821

822+
// ── The floor: every declared row RAN, and ran its case (#13489) ───────
823+
//
824+
// Evaluated after every row has had its chance and BEFORE the verdict, so the
825+
// success line below can only be printed by a run in which the set of rows
826+
// that registered EQUALS the set declared. A set difference names WHICH row
827+
// stopped; a count says only that something did.
828+
const floorFailure = (message) => {
829+
console.error(`✗ self-test floor: ${message}`);
830+
failed += 1;
831+
};
832+
const declaredBatteries = Object.keys(SELF_TEST_BATTERIES);
833+
let floorBreached = false;
834+
if (declaredBatteries.length < SELF_TEST_BATTERY_FLOOR) {
835+
floorBreached = true;
836+
floorFailure(
837+
`SELF_TEST_BATTERIES declares ${declaredBatteries.length} batteries, below the pinned ` +
838+
`${SELF_TEST_BATTERY_FLOOR} — a battery deleted from the roster takes its own floor with it.`,
839+
);
840+
}
841+
const rowLabels = cases.map((c) => c.label);
842+
const duplicated = [...new Set(rowLabels.filter((name, i) => rowLabels.indexOf(name) !== i))];
843+
if (duplicated.length > 0) {
844+
floorBreached = true;
845+
floorFailure(
846+
`the cases table uses ${duplicated.map((n) => JSON.stringify(n)).join(', ')} as a row label more than once — ` +
847+
'two rows sharing a label are ONE battery, so the second can stop running while the first keeps the floor met.',
848+
);
849+
}
850+
for (const [name, count] of batterySeen) {
851+
if (declaredBatteries.includes(name)) continue;
852+
floorBreached = true;
853+
floorFailure(
854+
`self-test battery "${name}" registered ${count} case(s) but is not declared in ` +
855+
'SELF_TEST_BATTERIES — a case attributed to no declared battery is one nothing floors.',
856+
);
857+
}
858+
for (const name of declaredBatteries) {
859+
const count = batterySeen.get(name) ?? 0;
860+
if (count >= SELF_TEST_BATTERIES[name]) continue;
861+
floorBreached = true;
862+
floorFailure(
863+
count === 0
864+
? `self-test battery "${name}" DID NOT RUN — 0 cases registered, ${SELF_TEST_BATTERIES[name]} pinned. ` +
865+
'The verdict below would have claimed that case holds.'
866+
: `self-test battery "${name}" registered ${count} case(s), below its pinned floor of ` +
867+
`${SELF_TEST_BATTERIES[name]} — cases that used to run no longer do.`,
868+
);
869+
}
870+
if (floorBreached) {
871+
floorFailure(
872+
'A battery at or below its floor means cases STOPPED RUNNING — the battery is the bug, not the ' +
873+
'number. Find what stopped registering (a deleted row, a renamed label, a loop that no longer ' +
874+
'reaches it) and restore it.',
875+
);
876+
}
877+
758878
if (failed > 0) {
759-
console.error(`\n✗ check-skill-compatibility-version self-test failed (${failed} case(s)).`);
879+
console.error(`\n✗ check-skill-compatibility-version self-test: ${failed} failure(s) (cases and floor).`);
760880
process.exit(1);
761881
}
762882
console.log(`\n✓ check-skill-compatibility-version self-test: ${cases.length} cases pass, plus 7 dispatch-gates declaration cases.`);

0 commit comments

Comments
 (0)