Skip to content

Commit cc2e39e

Browse files
claude[bot]claude
andauthored
test(scripts): batch 6b — assertion floors for nine scripts/** self-tests (sink repair + hoisted battery) (#15248)
* test(scripts): floor check-pnpm-acquisition's self-test with a battery roster `cases` with no failing entry was this self-test's only success condition, so "every case held" and "the cases never ran" printed the same line. Batch 6b of the roster-floor transplant, two shapes at once: - the sink repair PR #15156 landed: the concise arrow `const t = (name, ok, detail) => cases.push(...)` gains a block body and registers the case before recording it. `cases.push` receives exactly the arguments it always did -- no case is rewritten, reordered or re-judged. - the single hoisted battery PR #15217 landed: this file carries no named section banner, so it declares ONE battery opened at the top of the self-test body, floor at the measured count (12), and pins the roster's own size at 1. No comment is promoted to a section head. A breach files into the self-test's own `cases` sink, so the existing verdict reds on it with no verdict line rewritten; the #13798 handshake is untouched. Cases before == after: 12 == 12, measured on runs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk * test(scripts): floor check-skill-frame-freshness's self-test with a battery roster `failed === 0` was this self-test's only success condition, so "every case held" and "the cases never ran" printed the same line. Batch 6b, two shapes at once: - the sink repair PR #15156 landed: the 12 inline `cases.push({...})` sites route through ONE block-bodied in-body helper, `addCase`, which registers the case and then performs the identical push. The case object is passed through untouched and the loop that runs the cases is not touched at all -- no case is rewritten, reordered or re-judged. - the single hoisted battery PR #15217 landed: this file carries no named section banner (its `--- n/m: ... ---` comments label fixtures, not sections), so it declares ONE battery opened at the top of the self-test body, floor at the measured count (12), roster size pinned at 1. No comment is promoted to a section head. A breach files into the self-test's own `failed` counter, so the existing verdict reds on it with no verdict line rewritten; the #13798 handshake is untouched. Normal mode stays green on the tree. Cases before == after: 12 == 12, measured on runs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 368a82e commit cc2e39e

2 files changed

Lines changed: 220 additions & 13 deletions

File tree

scripts/check-pnpm-acquisition.mjs

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,39 @@ function withFixture(files, fn) {
361361
}
362362
}
363363

364+
// ── The self-test's own battery roster and floor (#13489) ─────────────────
365+
//
366+
// `cases` with no failing entry used to be this self-test's ONLY success
367+
// condition, so "every case held" and "the cases never ran" printed the same
368+
// line. Closed the way PR #13487 validated on check-doc-authoring: what is
369+
// pinned is the registered NAMES, not a number. The floor requires the OPENED
370+
// set to equal the DECLARED set with each battery at or above its own count.
371+
//
372+
// This file declares ONE battery, opened at the top of the self-test body. It
373+
// carries no named section banner, and ⛔ a comment is NOT promoted to a
374+
// section head — that is a judgement per comment this transplant does not
375+
// make. The hoisted single battery is the shape PR #14896, PR #15003 and
376+
// PR #15217 landed for exactly this case.
377+
//
378+
// ⛔ A pinned TOTAL is not the repair: a battery dropping from 9 cases to 3
379+
// keeps a total "right" the moment a sibling grows.
380+
//
381+
// The count is a FLOOR, not an equality — adding cases is ordinary work and
382+
// must not red. A battery BELOW its floor means cases stopped running; the
383+
// remedy is to find what stopped registering.
384+
const SELF_TEST_BATTERIES = Object.freeze({
385+
'check-pnpm-acquisition self-test': 12,
386+
});
387+
388+
// DELETING an entry silences that battery's floor exactly as effectively as
389+
// zeroing it, so the roster's own size is pinned too.
390+
const SELF_TEST_BATTERY_FLOOR = 1;
391+
392+
// The key an assertion is filed under when no battery is open. It is not a
393+
// declared battery, so it reds by the same set difference rather than silently
394+
// inflating whichever battery happened to run last.
395+
const UNATTRIBUTED_BATTERY = '(no battery open)';
396+
364397
// Set by `selfTest()` only after its verdict is printed, and read at the
365398
// dispatch: a `return` that leaves the function above that line prints nothing
366399
// and still exits 0 — a self-test that never finished, reported as one that
@@ -369,8 +402,28 @@ function withFixture(files, fn) {
369402
let selfTestReachedVerdict = false;
370403

371404
export function selfTest() {
405+
// The battery ledger this self-test's floor is evaluated against (#13489).
406+
// `battery()` opens a battery; every case below is attributed to the one most
407+
// recently opened, so a section that stops running stops registering and
408+
// names ITSELF at the floor rather than going quiet.
409+
const batterySeen = new Map();
410+
let openBattery = null;
411+
const battery = (name) => {
412+
openBattery = name;
413+
};
414+
const registerCase = () => {
415+
const b = openBattery ?? UNATTRIBUTED_BATTERY;
416+
batterySeen.set(b, (batterySeen.get(b) ?? 0) + 1);
417+
};
418+
battery('check-pnpm-acquisition self-test');
372419
const cases = [];
373-
const t = (name, ok, detail) => cases.push({ name, ok: Boolean(ok), detail });
420+
// The concise arrow this sink used to be gains a block body so the case is
421+
// registered before it is recorded. `cases.push` still receives exactly the
422+
// arguments it always did: no case is rewritten, reordered or re-judged.
423+
const t = (name, ok, detail) => {
424+
registerCase();
425+
cases.push({ name, ok: Boolean(ok), detail });
426+
};
374427

375428
const kinds = (r) => r.problems.map((p) => p.kind).sort();
376429
const mechs = (r) => r.sites.map((s) => s.mech).sort();
@@ -548,6 +601,53 @@ export function selfTest() {
548601
},
549602
);
550603

604+
// ── The floor: every declared battery RAN, and ran its cases (#13489) ────
605+
//
606+
// Evaluated after every battery has had its chance and BEFORE the verdict, so
607+
// the success line below can only be printed by a run in which the set of
608+
// batteries that registered cases EQUALS the set declared. A set difference
609+
// names WHICH battery stopped; a count says only that something did.
610+
//
611+
// A breach is filed into this self-test's OWN sink, so the existing verdict
612+
// reds on it with no verdict line rewritten.
613+
const floorFailure = (message) => { cases.push({ name: message, ok: false }); };
614+
const declaredBatteries = Object.keys(SELF_TEST_BATTERIES);
615+
let floorBreached = false;
616+
if (declaredBatteries.length < SELF_TEST_BATTERY_FLOOR) {
617+
floorBreached = true;
618+
floorFailure(
619+
`SELF_TEST_BATTERIES declares ${declaredBatteries.length} batteries, below the pinned `
620+
+ `${SELF_TEST_BATTERY_FLOOR} — a battery deleted from the roster takes its own floor with it.`,
621+
);
622+
}
623+
for (const [name, count] of batterySeen) {
624+
if (declaredBatteries.includes(name)) continue;
625+
floorBreached = true;
626+
floorFailure(
627+
`self-test battery "${name}" registered ${count} case(s) but is not declared in `
628+
+ 'SELF_TEST_BATTERIES — a case attributed to no declared battery is one nothing floors.',
629+
);
630+
}
631+
for (const name of declaredBatteries) {
632+
const count = batterySeen.get(name) ?? 0;
633+
if (count >= SELF_TEST_BATTERIES[name]) continue;
634+
floorBreached = true;
635+
floorFailure(
636+
count === 0
637+
? `self-test battery "${name}" DID NOT RUN — 0 cases registered, ${SELF_TEST_BATTERIES[name]} pinned. `
638+
+ 'The verdict below would have claimed those cases hold.'
639+
: `self-test battery "${name}" registered ${count} case(s), below its pinned floor of `
640+
+ `${SELF_TEST_BATTERIES[name]} — cases that used to run no longer do.`,
641+
);
642+
}
643+
if (floorBreached) {
644+
floorFailure(
645+
'A battery at or below its floor means cases STOPPED RUNNING — the battery is the bug, not the '
646+
+ 'number. Find what stopped registering (an early return, a deleted block, a guard that now '
647+
+ 'skips) and restore it.',
648+
);
649+
}
650+
551651
const failed = cases.filter((c) => !c.ok);
552652
for (const c of failed) console.error(` x ${c.name}${c.detail ? ` -- ${c.detail}` : ''}`);
553653
if (failed.length) {

scripts/check-skill-frame-freshness.mjs

Lines changed: 119 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,40 @@ function setOriginMain(dir, sha) {
811811
git(['update-ref', 'refs/remotes/origin/main', sha], { cwd: dir });
812812
}
813813

814+
// ── The self-test's own battery roster and floor (#13489) ─────────────────
815+
//
816+
// `failed === 0` used to be this self-test's ONLY success condition, so "every
817+
// case held" and "the cases never ran" printed the same line. Closed the way
818+
// PR #13487 validated on check-doc-authoring: what is pinned is the registered
819+
// NAMES, not a number. The floor requires the OPENED set to equal the DECLARED
820+
// set with each battery at or above its own count.
821+
//
822+
// This file declares ONE battery, opened at the top of the self-test body. It
823+
// carries no named section banner (its `--- n/m: ... ---` comments label
824+
// fixtures, not sections), and ⛔ a comment is NOT promoted to a section head —
825+
// that is a judgement per comment this transplant does not make. The hoisted
826+
// single battery is the shape PR #14896, PR #15003 and PR #15217 landed for
827+
// exactly this case.
828+
//
829+
// ⛔ A pinned TOTAL is not the repair: a battery dropping from 9 cases to 3
830+
// keeps a total "right" the moment a sibling grows.
831+
//
832+
// The count is a FLOOR, not an equality — adding cases is ordinary work and
833+
// must not red. A battery BELOW its floor means cases stopped running; the
834+
// remedy is to find what stopped registering.
835+
const SELF_TEST_BATTERIES = Object.freeze({
836+
'check-skill-frame-freshness self-test': 12,
837+
});
838+
839+
// DELETING an entry silences that battery's floor exactly as effectively as
840+
// zeroing it, so the roster's own size is pinned too.
841+
const SELF_TEST_BATTERY_FLOOR = 1;
842+
843+
// The key a case is filed under when no battery is open. It is not a declared
844+
// battery, so it reds by the same set difference rather than silently
845+
// inflating whichever battery happened to run last.
846+
const UNATTRIBUTED_BATTERY = '(no battery open)';
847+
814848
// Set by `selfTest()` only after its verdict is printed, and read at the
815849
// dispatch: a `return` that leaves the function above that line prints nothing
816850
// and still exits 0 — a self-test that never finished, reported as one that
@@ -819,6 +853,20 @@ function setOriginMain(dir, sha) {
819853
let selfTestReachedVerdict = false;
820854

821855
function selfTest() {
856+
// The battery ledger this self-test's floor is evaluated against (#13489).
857+
// `battery()` opens a battery; every case below is attributed to the one most
858+
// recently opened, so a section that stops running stops registering and
859+
// names ITSELF at the floor rather than going quiet.
860+
const batterySeen = new Map();
861+
let openBattery = null;
862+
const battery = (name) => {
863+
openBattery = name;
864+
};
865+
const registerCase = () => {
866+
const b = openBattery ?? UNATTRIBUTED_BATTERY;
867+
batterySeen.set(b, (batterySeen.get(b) ?? 0) + 1);
868+
};
869+
battery('check-skill-frame-freshness self-test');
822870
const real = realFrameFiles();
823871
const twoAxis = twoAxisFrameFiles();
824872
const temps = [];
@@ -835,6 +883,15 @@ function selfTest() {
835883
};
836884

837885
const cases = [];
886+
// ONE block-bodied helper for the sink the 12 inline `cases.push({...})`
887+
// sites below used to write to directly. It registers the case and then
888+
// performs the identical push: the case object is passed through untouched,
889+
// so no case is rewritten, reordered or re-judged, and the loop that runs
890+
// them is not touched at all.
891+
const addCase = (c) => {
892+
registerCase();
893+
cases.push(c);
894+
};
838895

839896
// --- 1/2: the SAME stale tree, judged online vs offline -------------------
840897
// The pair is the whole point of the degradation contract: identical fixture,
@@ -843,21 +900,21 @@ function selfTest() {
843900
const { dir, a: stale, b: current } = linear('stale', twoAxis, real);
844901
git(['checkout', '-q', stale], { cwd: dir });
845902
setOriginMain(dir, current);
846-
cases.push({
903+
addCase({
847904
label: 'stale tree + authoritative ref → ERROR naming the stale files (the #5866 shape)',
848905
run: () => evaluate({ root: dir, ref: current }),
849906
expect: 'error',
850907
wants: [/STRUCTURALLY BEHIND/, SAMPLE_FRAME_FILE_RX, /3 axes: long-term-soundness/, /4 axes: business-need/, new RegExp(REMEDY.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))],
851908
});
852-
cases.push({
909+
addCase({
853910
label: 'the SAME stale tree, fetch impossible → degrades to WARN, exit 0, same diagnosis',
854911
run: () => evaluate({ root: dir }),
855912
expect: 'warn',
856913
wants: [/STRUCTURALLY BEHIND/, SAMPLE_FRAME_FILE_RX],
857914
alsoAssert: (v) => (v.clamped ? null : 'expected the verdict to be marked as clamped'),
858915
});
859916
// The independence proof: the sync gate is GREEN on this very fixture.
860-
cases.push({
917+
addCase({
861918
label: 'the sync gate is GREEN on that same stale tree — the two invariants are independent',
862919
run: () => {
863920
const copies = COPIES.map((c) => ({ ...c, text: twoAxis.get(c.file) }));
@@ -873,7 +930,7 @@ function selfTest() {
873930
{
874931
const { dir, b: current } = linear('fresh', twoAxis, real);
875932
setOriginMain(dir, current);
876-
cases.push({
933+
addCase({
877934
label: 'tree equals origin/main → OK',
878935
run: () => evaluate({ root: dir, ref: current }),
879936
expect: 'ok',
@@ -888,7 +945,7 @@ function selfTest() {
888945
const { dir, a: older, b: newer } = linear('wording', real, wording);
889946
git(['checkout', '-q', older], { cwd: dir });
890947
setOriginMain(dir, newer);
891-
cases.push({
948+
addCase({
892949
label: 'tree is BEHIND in commits but the frame is unchanged → OK (bytes are not the criterion)',
893950
run: () => evaluate({ root: dir, ref: newer }),
894951
expect: 'ok',
@@ -902,7 +959,7 @@ function selfTest() {
902959
const base = git(['rev-parse', 'HEAD~1'], { cwd: dir }).stdout.trim();
903960
git(['checkout', '-q', local], { cwd: dir });
904961
setOriginMain(dir, base);
905-
cases.push({
962+
addCase({
906963
label: 'HEAD already contains the ref → the difference is a LOCAL edit, WARN not ERROR',
907964
run: () => evaluate({ root: dir, ref: base }),
908965
expect: 'warn',
@@ -917,7 +974,7 @@ function selfTest() {
917974
git(['rm', '-q', SAMPLE_FRAME_FILE], { cwd: dir });
918975
const without = commitAll(dir, 'drop a framework file');
919976
setOriginMain(dir, current);
920-
cases.push({
977+
addCase({
921978
label: 'a framework file exists on the ref but not in the tree → ERROR',
922979
run: () => evaluate({ root: dir, ref: current }),
923980
expect: 'error',
@@ -936,7 +993,7 @@ function selfTest() {
936993
writeFiles(dir, real);
937994
commitAll(dir, 'tree adds it');
938995
setOriginMain(dir, refSha);
939-
cases.push({
996+
addCase({
940997
label: 'a framework file exists here but not on the ref → WARN, both readings stated',
941998
run: () => evaluate({ root: dir, ref: refSha }),
942999
expect: 'warn',
@@ -950,7 +1007,7 @@ function selfTest() {
9501007
const { dir, b: current } = linear('anchors', real, moved);
9511008
git(['checkout', '-q', git(['rev-parse', 'HEAD~1'], { cwd: dir }).stdout.trim()], { cwd: dir });
9521009
setOriginMain(dir, current);
953-
cases.push({
1010+
addCase({
9541011
label: 'the ref\'s copy no longer parses with our anchors → ERROR, read as staleness',
9551012
run: () => evaluate({ root: dir, ref: current }),
9561013
expect: 'error',
@@ -964,7 +1021,7 @@ function selfTest() {
9641021
const { dir, b: current } = linear('broken-here', broken, real);
9651022
git(['checkout', '-q', git(['rev-parse', 'HEAD~1'], { cwd: dir }).stdout.trim()], { cwd: dir });
9661023
setOriginMain(dir, current);
967-
cases.push({
1024+
addCase({
9681025
label: 'our own copy does not parse → ERROR pointing at check:skill-frame-sync',
9691026
run: () => evaluate({ root: dir, ref: current }),
9701027
expect: 'error',
@@ -978,7 +1035,7 @@ function selfTest() {
9781035
temps.push(dir);
9791036
writeFiles(dir, twoAxis);
9801037
commitAll(dir, 'stale tree, no remote-tracking ref anywhere');
981-
cases.push({
1038+
addCase({
9821039
label: 'no origin/main reference at all → WARN and pass, stating that nothing was proven',
9831040
run: () => evaluate({ root: dir }),
9841041
expect: 'warn',
@@ -992,7 +1049,7 @@ function selfTest() {
9921049
temps.push(dir);
9931050
writeFiles(dir, real);
9941051
commitAll(dir, 'only commit');
995-
cases.push({
1052+
addCase({
9961053
label: '--ref names a rev that does not exist → ERROR (never silently judged against something else)',
9971054
run: () => evaluate({ root: dir, ref: 'v99.99.99-nope' }),
9981055
expect: 'error',
@@ -1041,6 +1098,56 @@ function selfTest() {
10411098
for (const dir of temps) rmSync(dir, { recursive: true, force: true });
10421099
}
10431100

1101+
// ── The floor: every declared battery RAN, and ran its cases (#13489) ────
1102+
//
1103+
// Evaluated after every battery has had its chance and BEFORE the verdict, so
1104+
// the success line below can only be printed by a run in which the set of
1105+
// batteries that registered cases EQUALS the set declared. A set difference
1106+
// names WHICH battery stopped; a count says only that something did.
1107+
//
1108+
// A breach is filed into this self-test's OWN `failed` counter, so the
1109+
// existing verdict reds on it with no verdict line rewritten.
1110+
const floorFailure = (message) => {
1111+
failed += 1;
1112+
console.error(` ✗ ${message}`);
1113+
};
1114+
const declaredBatteries = Object.keys(SELF_TEST_BATTERIES);
1115+
let floorBreached = false;
1116+
if (declaredBatteries.length < SELF_TEST_BATTERY_FLOOR) {
1117+
floorBreached = true;
1118+
floorFailure(
1119+
`SELF_TEST_BATTERIES declares ${declaredBatteries.length} batteries, below the pinned `
1120+
+ `${SELF_TEST_BATTERY_FLOOR} — a battery deleted from the roster takes its own floor with it.`,
1121+
);
1122+
}
1123+
for (const [name, count] of batterySeen) {
1124+
if (declaredBatteries.includes(name)) continue;
1125+
floorBreached = true;
1126+
floorFailure(
1127+
`self-test battery "${name}" registered ${count} case(s) but is not declared in `
1128+
+ 'SELF_TEST_BATTERIES — a case attributed to no declared battery is one nothing floors.',
1129+
);
1130+
}
1131+
for (const name of declaredBatteries) {
1132+
const count = batterySeen.get(name) ?? 0;
1133+
if (count >= SELF_TEST_BATTERIES[name]) continue;
1134+
floorBreached = true;
1135+
floorFailure(
1136+
count === 0
1137+
? `self-test battery "${name}" DID NOT RUN — 0 cases registered, ${SELF_TEST_BATTERIES[name]} pinned. `
1138+
+ 'The verdict below would have claimed those cases hold.'
1139+
: `self-test battery "${name}" registered ${count} case(s), below its pinned floor of `
1140+
+ `${SELF_TEST_BATTERIES[name]} — cases that used to run no longer do.`,
1141+
);
1142+
}
1143+
if (floorBreached) {
1144+
floorFailure(
1145+
'A battery at or below its floor means cases STOPPED RUNNING — the battery is the bug, not the '
1146+
+ 'number. Find what stopped registering (an early return, a deleted block, a guard that now '
1147+
+ 'skips) and restore it.',
1148+
);
1149+
}
1150+
10441151
if (failed > 0) {
10451152
console.error(`\n✗ check-skill-frame-freshness self-test failed (${failed} case(s)).`);
10461153
process.exit(1);

0 commit comments

Comments
 (0)