test(scripts): batch 8b — assertion floors for two b4-thunk and two recipe-A self-tests - #15307
Merged
Merged
Conversation
…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
…a registered battery
The 13 `if (...) problems.push(...)` assertion sites in `selfTest()` are each
wrapped verbatim in the `check(() => { ... })` thunk PR #15198 landed. The sink
here is FAILURE-ONLY, so routing `problems.push` itself through `registerCase()`
would have inverted the floor rather than installing it: a green run would
register nothing and the battery would read DID NOT RUN. Zero named banners, so
one hoisted battery, floored at the 24 registrations measured on a run (four of
the thirteen sites sit inside loops: 9 + 4 + 4 + 2 + 5).
The floor lives inside the `!quiet` branch. `main()` gates the PRODUCTION census
on `selfTest({ quiet: true })`, which prints no verdict and so makes no claim for
a floor to guard; evaluating it there would let a roster edit change what a
census run outputs. Both production modes are byte-identical to the base tree.
One site stays outside the roster and says so in place: the `catch` arm of the
AUDIT_CONTROLS loop ends in `continue`, illegal inside the thunk's arrow
function, and rewriting that control flow is exactly what the verbatim rule
forbids. Its sibling in the same loop body is floored, so a loop that stops
running still reds.
Part of #13799
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…ble rows Recipe A as the pilot PR #15271 settled it: each of the 17 row labels of the literal `cases` table is a declared battery with a floor of 1, `registerCase(name)` is the first statement of the driving loop body, and the roster is a LITERAL the table is cross-checked against so a deleted or renamed row names ITSELF rather than deleting its own floor. Roster size pinned at 17; duplicate labels are refused from both sides. The three `// --- ... ---` comments inside the array are grouping rules, not section heads. The boolean `passed` becomes a `failures` counter so the red line can carry the recipe's wording, `N failure(s) (cases and floor)`; no assertion condition is touched and the green line is byte-identical to the base tree's. Part of #13799 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…table rows Recipe A per the pilot PR #15271: every row label is a declared battery with a floor of 1, `registerCase(name)` is the first statement of the driving loop, the roster is a LITERAL cross-checked against the table, size pinned at 155. The only deleted line is the red-run verdict, reworded to the recipe's `N failure(s) (cases and floor)`; the green line stays byte-identical. The batch-8 census flagged this table's four `...(() => { ... })()` spreads as an IIFE-produced block whose rows could not take a literal roster key. Measured, that premise does not hold here: each IIFE is a SCOPING device that declares local fixture consts and then returns an array of LITERAL [label, actual, expected] rows. No label is a template string or computed, and no row comes from a map/push/loop. Three independent readings agree on 155 -- labels extracted from source, literal row starts, and the `cases.length` the green line prints on a run -- so ALL 155 rows are floored with no residue, rather than the partition the row anticipated. Part of #13799 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
baozhoutao
marked this pull request as ready for review
September 4, 2026 10:31
baozhoutao
enabled auto-merge
September 4, 2026 10:31
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 8b of the self-test assertion-floor card: two b4-thunk files and two recipe-A files, from the batch 8 census table (
5538556734) as dispatched by its ACCEPT (5538595066) and the PM claim5538595337. Base pinorigin/main=5b09356b7; every reading below was taken at head9965c88d3. Exactly four files,skip-changeset, no deferrals.Per file
scripts/measure-test-shard-timings.mjsregistered 22 case(s), below its pinned floor of 23scripts/measure-position-name-fold-census.mjsregistered 24 case(s), below its pinned floor of 999scripts/check-override-consistency.mjsdeclares 17 batteries, below the pinned 999scripts/pm/check-skill-line-ratchet.mjsdeclares 155 batteries, below the pinned 999A measured correction to census row 19
The row warned that the
casesarray "also spreads an IIFE-produced block — generated rows cannot take a literal roster key", and dispatched the file as "recipe A on the literal rows only, generated rows outside the roster".Measured, that premise does not hold for this file. Each of the four
...(() => { ... })()spreads is a SCOPING device: it declares local fixture consts and thenreturn [...]s an array of LITERAL[label, actual, expected]rows. No row label is a template string, none is computed, and no row is produced by amap/push/ loop. Three independent readings agree on 155:155 cases pass.printed by the green line on a run of the unmodified base tree.So all 155 rows are floored, with no residue — nothing here is the
extra-call class of PR #15286, and partitioning the table would have been the lossy reading (the 7a Q1 precedent). The reasoning is recorded in place above the roster.Where the floor lives in
measure-position-name-fold-censusmain()gates the PRODUCTION census onselfTest({ quiet: true }), so this file has two callers of one body. The floor is evaluated inside the!quietbranch: the quiet call prints no verdict and therefore makes no claim for a floor to guard, and evaluating it there would let a roster edit change what a census run outputs. Proven, not argued — leg D4 below.One site stays outside the roster and says so in place: the
catcharm of theAUDIT_CONTROLSloop ends incontinue, which is illegal inside the thunk's arrow function, and rewriting that control flow is exactly what the verbatim rule forbids. Its sibling in the same loop body,if (!ac.expect(result)), is floored, so a loop that stops running still reds.Line-level identity (thunk files)
Every removed line, stripped of leading whitespace, reappears among the added lines. No condition was inverted; the dropped-
!hazard cannot arise.measure-test-shard-timings.mjsmeasure-position-name-fold-census.mjsWrapped-site count == assertion-site count in both: 22
check(() => {wrappers over 22if (...) throw ...sites; 13 wrappers over the 13if (...) problems.push(...)statement-sites carrying 14 of the 15 push sites (oneif/else ifcarries two), the 15th being the declaredcatch-arm exclusion.The two recipe-A files delete only sink lines:
check-skill-line-ratchetdeletes exactly one, its red-run verdict, reworded to the recipe'sN failure(s) (cases and floor);check-override-consistencydeletes four, converting its booleanpassedinto afailurescounter so the same red line can carry a count. No assertion condition is touched in either, and both green lines are byte-identical to the base tree's.Roster ⇄ table cross-check (recipe A)
Both lists printed and compared; symmetric difference empty in both directions, order identical, zero duplicate labels.
check-override-consistency: 17 roster keys vs 17 table labels.check-skill-line-ratchet: 155 roster keys vs 155 table labels.Ablation ledger — 15 legs
Every leg was run from the committed implementation. Each proves its mutation landed on disk (a grep count of the removed anchor AND of the injected text; a no-op mutation aborts the leg and discards the reading), and each restore is proven by HEAD-blob hash equality plus an empty
git diff HEAD— an empty hash is read as failure, never as "nothing to compare". The mutators carry atrap ... EXIT INT TERMrestore against an absoluteREPO_ROOT."over the ceiling -> red" DID NOT RUN, exit 1, 0 failing casesregisterCase()removeddeclares 155 batteries, below the pinned 999registerCase()removeddeclares 17 batteries, below the pinned 999registerCase()removed from the thunkDID NOT RUN — 0 cases registered, 22 pinned, cases greendeclares 1 batteries, below the pinned 9registerCase()removed from the thunkDID NOT RUN — 0 cases registered, 24 pinned, cases greendeclares 1 batteries, below the pinned 9--self-testreds (exit 1) while the census run stays exit 0 and byte-identical to the base tree — the floor cannot reach productionThese scripts are executed directly by path, not resolved through a package
exports, so nodist/rebuild leg applies; there is nothing between the edited source and the run.Both modes vs an installed base worktree at the pin
A detached worktree at
5b09356b7,pnpm installexit 0. Every stream compared withcmp.--json--self-test--self-test--self-testskills/**,.claude/**)--self-test18/18 streams identical.
skills/**was never edited; the ratchet's normal mode is green on both trees.The card's instrument
node scripts/measure-self-test-floor.mjs --jsonon both trees, 169 rows each:extractWatchHints(fromscripts/pm/dispatch-gates.mjs) over all four files, base vs branch: byte-identical ×4 — the 172 new roster labels contribute zero hints, andcheck-skill-line-ratchet's own 28 hints are unmoved.check:watch-hint-literalgreen.Gates (foreground; exit codes captured by redirect BEFORE any pipe)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(change set: exactly the 4 files vs merge base5b09356b7).check:pm-dispatch-gatesunder the shared verify lock, VERDICTcommand-exit 0 · held the lock 374s,1381 cases pass.check-self-test-workflow-commands.mjsand its--self-test,check:declared-population-live,check:ratchet-remedy-authority,check:watch-hint-literal,check:nul-bytes,check-self-test-wired.mjsand its--self-test— all exit 0. NOT MEASURED:pnpm check:self-test-wiredexits 254 because no suchpackage.jsonscript exists (0 occurrences); the wired spelling is the directnodeinvocation, which is green.--self-test; the only non-zero ismeasure-test-shard-timings.mjsnormal mode, exit 1 = its usage line, identical to the base tree's.packages/plugins/plugin-security/src/position-name-fold-warning.test.ts— 28/28 pass, after building the dependency closure under the verify lock.pnpm lintexit 0, not narrowed.grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]') clean on all four files and on every body posted.Derivation carried a STALE TREE warning:
origin/mainhas moved toed217e697(2 commits) since the dispatch pin, and 9 files changed across that range — all of them 7a/7b's landed files, disjoint from these four. The branch is deliberately left on its pin rather than rebased.🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code