tooling(scripts): assertion floors for the class-2 self-tests, one hoisted battery each (#13799 batch 5) - #15217
Merged
Conversation
… hoisted battery (#13799) The self-test decided success by `failures.length === 0` alone, so "every case held" and "the cases never ran" printed the same line. It carries no named section banner, and a comment is not promoted to a section head, so it declares ONE battery opened at the top of the body -- the hoisted shape PRs #14896 and #15003 landed for exactly this case. Floor 8, measured rather than transcribed: the roster was probed with a deliberately unreachable pin and the floor's own report named the registered count. Behaviour is unchanged -- `--self-test` stdout and stderr are byte-identical against origin/main, exit 0 both sides. Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk Co-authored-by: Claude <noreply@anthropic.com>
…e-limit self-tests (#13799) Both decided success by `failures.length === 0` alone. Neither carries the two named section banners the sectioning criterion needs, and a comment is not promoted to a section head, so each declares ONE battery opened at the top of its self-test body -- the hoisted shape PRs #14896 and #15003 landed. Floors 47 and 47, measured by probing the roster with an unreachable pin and reading the count the floor's own report names. `--self-test` stdout and stderr are byte-identical against origin/main for both, exit 0 on both sides. Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk Co-authored-by: Claude <noreply@anthropic.com>
…ps self-tests (#13799) check-spec-parsed-alias decided success by `failures.length === 0` alone. check-stack-collection-maps already COUNTED its assertions and printed the number -- but nothing compared it, so a case block that stopped running shrank the printed count and the gate stayed green: evidence, not proof. Neither carries the two named section banners the sectioning criterion needs, and a comment is not promoted to a section head, so each declares ONE battery opened at the top of its self-test body. Both floors measured at 18. The two hand-written verdict counts agree with the registered count on this tree (`18 assertions passed`, `18 assertions over synthetic sources`), so neither had drifted. `--self-test` stdout and stderr are byte-identical against origin/main for both, exit 0 on both sides. Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk Co-authored-by: Claude <noreply@anthropic.com>
…-tests (#13799) Both decided success by their sink alone (`failures.length === 0`, `failed === 0`), so "every case held" and "the cases never ran" printed the same line. tenant-chokepoint's blocks are headed by unmarked prose and label-desc-cap carries one banner, below the two the sectioning criterion needs; a comment is not promoted to a section head and a lone banner is not split, so each declares ONE battery opened at the top of its self-test body. label-desc-cap's sink is a counter rather than a list, so its floor prints the breach and folds it into `failed` -- the same refusal in that file's own idiom. Floors 17 and 44, measured by probing the roster with an unreachable pin. `--self-test` stdout and stderr are byte-identical against origin/main for both, exit 0 on both sides. Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk Co-authored-by: Claude <noreply@anthropic.com>
…rough self-tests (#13799) Neither carries the two named section banners the sectioning criterion needs, so each declares ONE battery opened at the top of its self-test body. Floors 41 and 18, measured by probing the roster with an unreachable pin. whole-set-label-write registers from `expect()` only. Its two trailing ledger loops walk WHOLE_SET_ACTIONS and ALLOWLIST and push straight to `failures`; they are left unregistered ON PURPOSE, because ALLOWLIST is meant to shrink and a floor that moved with it would red every legitimate removal -- the one habit these floors exist to prevent. The comment above the roster says so in place. wildcard-fallthrough refuses in place rather than collecting, so its floor refuses in place too.⚠️ Its verdict prints a TRANSCRIBED `17 cases` while the body has 18 assert call sites and registers 18 -- the literal had already drifted one low. It is left untouched so this change stays a pure no-op on output, and filed separately; the floor is what makes the drift harmless. `--self-test` stdout and stderr are byte-identical against origin/main for both, exit 0 on both sides. Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk Co-authored-by: Claude <noreply@anthropic.com>
baozhoutao
marked this pull request as ready for review
September 4, 2026 06:48
baozhoutao
enabled auto-merge
September 4, 2026 06:48
baozhoutao
pushed a commit
that referenced
this pull request
Sep 4, 2026
…y 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
baozhoutao
pushed a commit
that referenced
this pull request
Sep 4, 2026
…-test `cases.filter((c) => !c.cond)` was this self-test's only success condition, so "every case held" and "the cases never ran" printed the same line (#13489). Class-1 sink repair, the PR #15156 shape: the concise-arrow `ok` sink gains a block body that calls `registerCase()` before the unchanged `cases.push`. No assertion condition is inverted or rewritten. Class-2 roster, the PR #15217 shape: ONE battery hoisted to the top of the self-test body, floor at the measured 23, `SELF_TEST_BATTERIES` size pinned at 1. No comment was promoted to a section head. Case count before == after, measured by pinning the roster to an unreachable value and reading the breach line: 23. `--self-test` stdout and stderr are byte-identical to the base tree's, exit 0 on both. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
baozhoutao
pushed a commit
that referenced
this pull request
Sep 4, 2026
…attery 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
baozhoutao
pushed a commit
that referenced
this pull request
Sep 4, 2026
`cases.filter((c) => !c.ok)` was this self-test's only success condition, so "every case held" and "the cases never ran" printed the same line (#13489). Class-1 sink repair, the PR #15156 shape: the concise-arrow `t` sink gains a block body that calls `registerCase()` before the unchanged `cases.push`. No assertion condition is inverted or rewritten. Class-2 roster, the PR #15217 shape: ONE battery hoisted to the top of the self-test body, floor at the measured 20, `SELF_TEST_BATTERIES` size pinned at 1. The file's single named section banner is NOT split on, and no comment was promoted to a section head. Case count before == after, measured by pinning the roster to an unreachable value and reading the breach line: 20 — which agrees with the count the existing verdict line prints. `--self-test` stdout and stderr are byte-identical to the base tree's, exit 0 on both. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
baozhoutao
pushed a commit
that referenced
this pull request
Sep 4, 2026
`problems.length` / `failed` were these self-tests' only success condition, so "every case held" and "the cases never ran" printed the same line (#13489). Class-1 sink repair via the THUNK route PR #15198 measured, because each sink write is failure-only: routing failure-only writes through a helper would floor zero cases on a green run, which is no floor at all. `check(() => { ... })` registers the case and then runs the existing site VERBATIM, so registration happens whether or not the site fires and no assertion condition is inverted or rewritten. Per-iteration registration through a block-bodied helper is the landed shape (check-doc-frontmatter, check-test-source-alias both call their helper from inside a `for`). Class-2 roster, the PR #15217 shape: ONE battery hoisted to the top of each self-test body, floor at the measured count, roster size pinned at 1. No comment was promoted to a section head; a single banner was not split on. Floors, each measured by pinning the roster to an unreachable value and reading the breach line -- never transcribed: check-meta-type-normalized 4 (4 thunked sites) check-org-identifier 31 (agrees with its printed `cases.length + 1`) check-error-code-casing 51 (agrees with its printed 46 + 5) `--self-test` stdout and stderr byte-identical to the base tree's on all three, exit 0 both sides; normal mode also byte-identical where the gate has one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
baozhoutao
pushed a commit
that referenced
this pull request
Sep 4, 2026
…ests Same repair as the previous commit: the THUNK route PR #15198 measured, because every sink write in these three is failure-only, plus PR #15217's single hoisted battery with the roster size pinned at 1. Floors, each measured by pinning the roster to an unreachable value and reading the breach line -- never transcribed: check-console-intercept-disarm 11 (its printed 10 cases + the real-tree floor) check-examples-live-imports 36 (agrees with its printed `cases.length`) check-optional-error-sink-contract 66 (its printed 19 + 9x4 spellings + the reject side + 9 derivation + the `run` reference pin) check-examples-live-imports' one sink site is an if/ELSE, so it is wrapped by hand rather than by a brace matcher that would stop at the `if` block's own closing brace; the branches are reindented, not rewritten. ⛔ check-optional-error-sink-contract's two assertions over `baseline.entries` are deliberately left UNREGISTERED and say so in place: they run one-per-row of a shrink-only ledger, and a floor moving with that list would red every legitimate removal (#13797's ruling, carried forward by PR #15217's check-whole-set-label-write). `LOG_CHANNELS` is not that -- it is the contract's own vocabulary, not a list meant to shrink -- so its loops do register. `--self-test` stdout and stderr byte-identical to the base tree's on all three, exit 0 both sides; normal mode byte-identical where the gate has one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
baozhoutao
pushed a commit
that referenced
this pull request
Sep 4, 2026
…tered battery
The 22 bare `if (...) throw ...` assertions in `selfTest()` are each wrapped
verbatim in the `check(() => { ... })` thunk PR #15198 landed: the condition is
carried in untouched, so no `!` can be dropped while the case still registers
and still passes. Zero named section banners, so one hoisted battery (the
PR #14896 / #15003 / #15217 shape), floored at the measured 22 with the roster's
own size pinned at 1. The floor throws, matching this file's own sink, and is
evaluated before the verdict so the success line can only be printed by a run
that actually ran its cases.
Part of #13799
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
baozhoutao
pushed a commit
that referenced
this pull request
Sep 4, 2026
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 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
Batch 5 of the
scripts/**assertion-floor work: the class-2-ONLY deferrals from PR #15003's table — files that already carry a block-bodied in-body assertion helper and a body-level verdict site, but fewer than the two named section banners the sectioning criterion needs.9 floored, 2 deferred with a measured reason. Every candidate was re-verified at the pin
50d6c924brather than taken from the table; two of the eleven turned out to be class-1 as well, and are deferred rather than forced.The shape
One battery per file, opened at the top of the self-test body — the hoisted shape PRs #14896 and #15003 landed for files that run cases before any banner — named after the file's self-test, with the floor at the measured case count,
SELF_TEST_BATTERIESroster size pinned at 1, and a verdict that refuses below-floor / DID NOT RUN.registerCase()is called from the existing helper's block body; no case is rewritten and no assertion changed.⛔ No comment is promoted to a section head — that is a judgement per comment this transplant does not make (b2's rule). ⛔ Where a file carries exactly one real banner (
check-label-desc-cap), it still gets one battery; a lone banner is not split. Every verdict handshake is kept exactly as landed, in the spelling each file already uses — five return theSELF_TEST_VERDICTsentinel, four set aselfTestReachedVerdictflag because their own exit code stays load-bearing.Floored (9)
scripts/check-dts-emitted.mjseqscripts/check-logger-receiver-detach.mjsexpectscripts/check-objectql-double-limit.mjsexpectscripts/check-spec-parsed-alias.mjscheckscripts/check-stack-collection-maps.mjseqscripts/check-tenant-chokepoint.mjsassertscripts/check-whole-set-label-write.mjsexpectscripts/check-wildcard-fallthrough.mjsassertscripts/pm/check-label-desc-cap.mjst258 cases floored across the nine. Two files needed the floor written in their own idiom rather than the landed one, and say so in place:
check-label-desc-cap's sink is a counter rather than a list, so a breach prints and folds intofailed;check-wildcard-fallthroughrefuses in place instead of collecting, so its floor refuses in place too.⭐ Two floors that are deliberately NOT "every case in the file"
check-whole-set-label-writeregisters fromexpect()only. Its two trailing loops walkWHOLE_SET_ACTIONSandALLOWLISTand push straight tofailures, one iteration per row. They are left unregistered on purpose:ALLOWLISTis an allowlist, so it is meant to SHRINK, and a floor that moved with it would red every legitimate removal and train the next author to edit the floor — the one habit these floors exist to prevent (PR Survey: which scripts/** self-tests cannot prove they ran — and the two that now can #13797's ruling, which 155 of 158 scripts/** self-tests have no assertion floor: a battery that never ran is indistinguishable from one that passed #13799's body carries forward). The floor pins the part that does not move with a list. The comment above the roster states this where the next reader will be standing.check-stack-collection-mapsalready COUNTED its assertions and printed the number — but nothing compared it, so a case block that stopped running shrank the printed count and the gate stayed green. Evidence, not proof. Itsassertedcounter and the new ledger now agree at 18, and only the ledger is enforced.Deferred (2) — measured, and a correction to PR #15003's table
Both were recorded there as class-2 only. Measured at the pin they are class-1 as well: neither has a single block-bodied in-body assertion helper. Registering from a
forloop body has no landed precedent — the two landed multi-site files (scripts/pr-labels.mjs,scripts/docs-audit/check-audit-scope.mjs) register from two block-bodied helpers, not from loops — so forcing them here would be improvising a new shape on a file whose census class would then read ROSTER while most of the hole stayed open.scripts/check-startup-registry-verdict.mjsfor (const c of cases)loop body, which incrementsfailuresonce per table row (base L1366), and theexpectRoothelper (base L1380). Registering fromexpectRootalone would floor only the four dead-root cases and leave the ~20-row analysis table unfloored.scripts/js-comment-mask.mjsfailed++(base L508); the interpolation half uses a concise-arrow sink,const x = (name, ok, detail) =followed by an arrow toextra.push(...)(base L526), which has no block body to holdregisterCase(). Concise-arrow sinks are batch 3 / batch 4 territory (the thunk route PR #15156 measured).⛔
scripts/pm/dispatch-gates.mjs(DEFERRED by the card),scripts/pm/check-half-states.mjs(its own batch) andscripts/partition-test-shards.mjs(batch 4, PR #15198, in flight) are untouched, as are all class-1 and class-3 files.Evidence
Behaviour is unchanged, per file
--self-testrun in a base worktree at50d6c924band in this one, exit codes captured by redirect before any pipe, the two tree roots normalised away, stdout and stderr compared in full rather than sampled:9/9 exit 0 on both sides, with stdout AND stderr byte-identical on every one. The registered-case ledger is a
Mapwrite and nothing prints it, so no verdict line moves.check-dts-emittedis not run by anycheck:script — it is invoked by about eleven packages' own build scripts — so its normal mode was run too, frompackages/clienton both trees: output byte-identical, exit 1 on both sides (that package has nodistin either worktree; container state, present identically on the base, and not a verdict about this diff).Case counts: measured, never transcribed
Each floor was read from the file's own report rather than counted by eye: the roster was pinned to a deliberately unreachable value, the self-test run, and the floor's own breach line (
registered N case(s), below its pinned floor of ...) names N. The pin was then set to N. No temporary statement was injected into any file to obtain a count.Two files carry a hand-written count in their verdict line.
check-spec-parsed-alias(18 assertions passed) andcheck-stack-collection-maps(18 assertions) both agree with the measured count — neither had drifted.check-wildcard-fallthroughprints✓ self-test: 17 caseswhile its body has 18assert(call sites and registers 18. The literal is left untouched so this change stays a pure no-op on output — correcting it would break the byte-identical proof that is this PR's whole evidence — and it is filed as #15231 (unassigned). A comment records the measurement in place. The floor pinned at the measured 18 is what makes the drift harmless: the count can no longer shrink in silence.Ablations — three shapes, eleven legs, each from the committed implementation
Every leg registers its restore before the mutation, on absolute paths. The mutation is proved on disk by an exact-substring count and a
git hash-objectthat moved off the HEAD blob's (an empty hash is read as FAILURE, not as "nothing to compare"); the restore is proved by hash equality against the HEAD blob and an emptygit diff HEAD— never by an exit code, and never by a baregit checkout -- path, which reads the index the mutation also wrote. Anchors must match exactly one occurrence or the leg aborts. None of these nine files resolves through adist, so no rebuild leg applies.check-tenant-chokepoint's only entry. Exit 0 → 1, naming both halves: SELF_TEST_BATTERIES declares 0 batteries, below the pinned 1 — a battery deleted from the roster takes its own floor with it and battery "check-tenant-chokepoint self-test" registered 17 case(s) but is not declared in SELF_TEST_BATTERIES. So the roster-size pin is load-bearing at size 1, not decorative.registerCase()removed from the sink —check-whole-set-label-write. Exit 0 → 1 with every original case still passing: DID NOT RUN — 0 cases registered, 41 pinned. The file's own green verdict is exactly what the floor refuses.The census moves by exactly the worklist
node scripts/measure-self-test-floor.mjs --json, computed as set assertions rather than read by eye:50d6c924b4d7538c4cNONE -toROSTER;ROSTERafter — True;git diff --name-onlyagainst the recorded base equals the worklist exactly (9 files) — True.Battery names are not path populations
The #15003 hazard: a battery name that reads as a declared path population changes what a gate thinks it watches. Every name here is
BASENAME self-test, which contains a space and so cannot passextractWatchHints' admission test at all. Proved rather than argued:extractWatchHintsrun over each of the nine files on both trees, hints sorted and compared — 9/9 identical (0, 8, 3, 1, 8, 0, 13, 0 and 1 hints respectively, unchanged).pnpm check:watch-hint-literalexit 0.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom this worktree after the edits — no paths passed; the script reads the change set from the merge base. 28 commands derived. Added on top, because a derived family is not a complete account of CI: each edited script's own--self-test, plus the always-runs tail (check:self-test-wired,check-self-test-workflow-commands.mjsand its--self-test,check:declared-population-live,check:ratchet-remedy-authority,check:watch-hint-literal,check:nul-bytes). 39 commands run, every exit code captured by redirect before any pipe.check:pm-dispatch-gates— exit 0, dispatch-gates self-test: 1353 cases pass — run in the foreground, pluscheck:declared-population-live,check:ratchet-remedy-authority,check:watch-hint-literalandcheck:nul-bytes, and the nine per-file--self-testruns.pnpm lint(whole repo,eslint . --no-inline-config) — exit 0 on4d7538c4c, 81 s. No narrowing claimed.grep -naPover the C0 range plus DEL) — no hits.All of the above ran on
4d7538c4c, which is this branch's head, withgit status --porcelainempty.ℹ️ The derivation printed a STALE TREE notice:
origin/mainhas advanced 5 commits since the pin, and 11 files the derivation reads from changed across that range. The branch is not merged forward, deliberately — none of those commits touches any of the nine files here (git merge-baseis still the recorded pin, and the diff against it is exactly the nine), so there is nothing to reconcile and a merge would only invalidate every measurement above. Recorded rather than silently absorbed; CI runs the farm against the real merge base regardless.scripts/**publishes nothing ⇒skip-changeset, applied at PR-open time.⛔ Left as a draft, not armed and not flipped ready — the PM does that.
🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code