test(scripts): assertion floors for nine self-tests — #13799 batch 8a (b5 hoisted single battery) - #15308
Merged
Merged
Conversation
…ngle battery `SELF-TEST PASSED (n cases)` was printed on `process.exitCode !== 1` alone, so a self-test whose four cases never registered printed the same line as one where every case held. Recipe b5 (PR #15217): ONE battery opened at the top of the self-test body, named `publish-smoke-pack self-test`, floor = the count measured on a run (4), `SELF_TEST_BATTERIES` size pinned at 1, `registerCase()` called from the existing `check(name, fn)` helper's block body, and a verdict that refuses a below-floor / DID-NOT-RUN / undeclared battery through the same sink the cases use (a `FAIL` line plus the failing exit code). No comment is promoted to a section head; no assertion condition is touched; the verdict handshake (`SELF_TEST_VERDICT`) is unchanged. Floor measured, not counted: the roster was first pinned at 9999 and the breach line named `registered 4 case(s)`. Part of #13799 Co-authored-by: Claude <noreply@anthropic.com>
The b5 recipe (PR #15217) applied to the remaining eight census rows of #13799 batch 8a. Each file gets ONE battery opened at the top of its self-test body, named `BASENAME self-test`, with the floor read off a run (the roster pinned at 9999 first, the breach line naming N), the roster's own size pinned at 1, `registerCase()` called from the block body of the helper the file already has, and a verdict refusing below-floor / DID NOT RUN / undeclared batteries through the file's own failure sink. Floors measured on a run: check-adr-symbol-anchors 17, symbol-anchors 51, check-i18n-walk-parity 23, check-test-completeness 67, checklist-select 17, release-rehearsal-clone 32, render-release-coverage-anchor 10, run-with-stall-guard 41. Two of them are the census's own warning coming true: symbol-anchors has 40 static `assert(` sites but registers 51 (loops), and render-release-coverage-anchor has 8 static `expect(` sites but registers 10. A floor counted from the source would have been wrong in both. Where the helper is module-level (check-adr-symbol-anchors, symbol-anchors, render-release-coverage-anchor) the case sites call a thin in-body wrapper that registers and then defers to the existing assertion, exactly as PR #15156 landed for that shape; no assertion condition is touched. checklist-select also stops transcribing its case count: the success line's hand-typed `17` is now read off a counter (#15305). It renders the same text today, which is what makes the byte comparison across the change readable. check-test-completeness scopes its floor to the loud run, because `selfTest({ quiet: true })` also runs on every production invocation of that gate, where nothing claims a self-test verdict. Part of #13799 Fixes #15305 Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Sep 4, 2026
baozhoutao
marked this pull request as ready for review
September 4, 2026 10:39
baozhoutao
enabled auto-merge
September 4, 2026 10:39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #13799
Fixes #15305
Batch 8a of the
scripts/**assertion-floor card: the b5 hoisted-single-battery recipe (settled by PR #15217, ACCEPT5536823391) transplanted into the nine census rows (5538556734) that already carry a block-bodied assertion helper and fewer than two named section banners.Each file gets ONE battery, opened at the top of its self-test body and named
BASENAME self-test; the floor is the case count measured on a run;SELF_TEST_BATTERIES's own size is pinned at 1;registerCase()is called from the block body of the helper the file already had; and the verdict refuses a below-floor, DID-NOT-RUN or undeclared battery through the file's own failure sink. No comment is promoted to a section head, no assertion condition is touched, and every verdict handshake is kept exactly as it landed.Branch head for every run quoted below:
9ecea9ca2. Base for every byte comparison: an installed worktree detached at the dispatch pin5b09356b7.The nine
scripts/check-adr-symbol-anchors.mjsassert(), print + exit 1scripts/symbol-anchors.mjsassert(), print + exit 1scripts/check-i18n-walk-parity.mjseq(what, got, want),failureslistN case(s) failedbecomesN failure(s) (cases and floor)scripts/check-test-completeness.mjseq()that throwsscripts/checklist-select.mjseq()that exitsscripts/pm/release-rehearsal-clone.mjst(name, cond, extra),failurestallyN failure(s)becomesN failure(s) (cases and floor)scripts/publish-smoke-pack.mjscheck(name, fn)thunkSELF-TEST FAILED, no count)scripts/render-release-coverage-anchor.mjsexpect(what, ok)N of M assertion(s)becomesN failure(s) (cases and floor) of M assertion(s)scripts/run-with-stall-guard.mjscheck(label, cond, detail),failureslistN self-test case(s) failedbecomesN failure(s) (cases and floor)Total floored: 262 cases. Nothing deferred — all nine matched their census row (block-bodied helper present, roster 0, handshake present).
⭐ Two floors are the census's own warning coming true, and both would have been WRONG if counted from the source.
symbol-anchorshas 40 staticassert(sites but registers 51 (loops);render-release-coverage-anchorhas 8 staticexpect(sites but registers 10 (a loop over three rendered bodies). The census flagged the second and predicted 40 for the first — so row 26's floor is a correction to the census table, measured the same way row 23's was.Where the helper is module-level (rows 1, 2, 8) the case sites now call a thin in-body wrapper that registers and then defers to the existing assertion, whose semantics are untouched — the shape PR #15156 landed for exactly this case. Call sites moved: 17, 40 and 8 respectively; no condition, no message and no argument changed.
checklist-selectalso stops transcribing its count (#15305). The success line's hand-typed17is now read off a counter incremented ineq:console.log('✓ checklist-select self-test: 17 cases pass.');console.log(`✓ checklist-select self-test: ${cases} cases pass.`);The rendered line is unchanged today, because the transcribed 17 was accurate — which is what lets the two-mode byte comparison below read as clean rather than as a wash. It stops being accurate the moment a case is added, which is the defect.
check-test-completenessscopes its floor to the loud run.selfTest({ quiet: true })runs on every production invocation of that gate, where nothing claims a self-test verdict; the floor exists to stop a green SELF-TEST VERDICT being printed over cases that never ran, so it is evaluated exactly where that verdict is printed. Proven below, not asserted.Proof
Floors measured, never counted. For each file the roster was first pinned at an unreachable
9999and the breach line read off the run — e.g.self-test battery "symbol-anchors self-test" registered 51 case(s), below its pinned floor of 9999. The floor was then set to that number.27 ablation legs, three per file, mutation and restore both proven on disk. Every leg proves the mutation landed by counting the removed text and the injected text and by the blob hash moving; restores are
git checkout HEAD -- ABSOLUTE_PATHin afinally, proven by blob-hash equality with the HEAD blob and an emptygit diff HEAD(an empty hash reads as failure, never as "nothing to compare"). These are plain.mjsscripts run from source, so nodistleg applies.... self-test DID NOT RUN — 0 cases registered, N pinnedand... self-tst registered N case(s) but is not declaredregisterCase()removedDID NOT RUN — 0 cases registered, N pinned, with every original case still passing (the four files that print per-case lines show 4 / 32 / 10 / 41 ok lines and exactly the 2 floor failures; the five fail-fast files reach the floor block at all only because every case passed)SELF_TEST_BATTERIES declares 0 batteries, below the pinned 1andregistered N case(s) but is not declared— the size-1 pin is load-bearing in both directionsA fourth leg for
check-test-completeness: withregisterCase()ablated,--self-testexits 1 onDID NOT RUN, while the production invocation still exits 3 with output byte-identical to the base tree's. The floor cannot fire on the quiet call.Both modes vs the installed base worktree at
5b09356b7, stdout and stderr compared separately.--self-test, 9/9: eight byte-identical on both streams;release-rehearsal-cloneidentical except one elapsed-milliseconds line (90 msvs97 ms) that also differs base-against-base on a repeat run — control shown, and identical once that number is masked.render-release-coverage-anchordiffers only in itsSwept ISO-TIMESTAMPline, which also differs base-against-base;release-rehearsal-clonediffers only in the worktree path it echoes on line 1, an artefact of comparing two directories.check-i18n-walk-parity's production path refuses as PREREQUISITE NOT MET in an unbuilt tree (identical on both sides). It was therefore re-measured properly: with@objectstack/specand@objectstack/clibuilt, the base file and the branch file were run against the same built tree — stdout and stderr byte-identical, both exit 0,11 declared group(s), 8 walked, 3 exempted.The instrument, before and after (
node scripts/measure-self-test-floor.mjs --json, run in each tree): baseROSTER 133 / NONE 34 / COUNT 2becomes branchROSTER 142 / NONE 25 / COUNT 2. NONE drops by exactly 9, nothing enters NONE, and the symmetric difference between the dropped set and this batch's worklist is empty.extractWatchHintsover all nine, computed in both trees fromscripts/pm/dispatch-gates.mjs: identical, 9/9. Battery names carry spaces, so they cannot pass its admission test.check:watch-hint-literalexits 0.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no path list passed — the script takes its own change set), re-derived after the last commit with an unchanged family. Exit codes captured by redirect before any pipe. 30 commands, 30 exit 0, plus the always-runs tail:check:pm-dispatch-gatesin the foreground (1381 cases pass, exit 0),check:self-test-wiredand its--self-test,node scripts/check-self-test-workflow-commands.mjsand its--self-test,check:declared-population-live,check:ratchet-remedy-authority,check:watch-hint-literal,check:nul-bytes— all exit 0.Whole-repo
pnpm lint(eslint . --no-inline-config) exits 0; no narrowing claimed. A control-byte scan over the nine edited files and over every body posted for this batch returns no hits.The derivation prints a STALE-TREE notice: the branch is 4 commits behind
origin/main, and the 9 files it names as changed are batch 7a/7b's scripts. The intersection oforigin/main's movement with this diff is empty andgit merge-treeagainstorigin/mainreports no conflict, so the branch is deliberately not merged forward.Scope
Exactly nine files under
scripts/, no other path.skip-changesetapplied — nothing here is published from any package.Generated by Claude Code