Skip to content

test(scripts): floor partition-test-shards self-test via the thunk route (#13799 batch 4) - #15198

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-batch4-thunk-sink
Sep 4, 2026
Merged

test(scripts): floor partition-test-shards self-test via the thunk route (#13799 batch 4)#15198
baozhoutao merged 1 commit into
mainfrom
claude/issue-13799-batch4-thunk-sink

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Part of #13799

scripts/partition-test-shards.mjs was the file batches 2 and 3 each deferred. It already had seven named banners and a verdict handshake, but every one of its assertions is a bare throw — 36 in the self-test body (45 throw new Error in the whole file), 22 uniform single-line and 14 multi-line, several nested in a try/finally and behind a dataset-presence guard. Routing those through a boolean helper means inverting 36 failure conditions by hand, and a dropped ! yields an assertion that still registers its case and still passes — invisible to the very floor being installed.

The route: a thunk, not a rewrite

const check = (fn) => {
  registerCase();
  fn();
};

Each site's existing if (...) throw ... is carried into the thunk verbatim, modulo indentation. No condition is touched, so the dropped-! hazard cannot arise, and the file keeps failing fast on the first broken assertion exactly as before. The 14 multi-line blocks are reindented by two spaces and nothing else.

The roster

Seven batteries, declared from the seven banners that actually register cases; the counts sum to exactly the 36 sites.

battery floor
coverage + determinism 2
LPT balance bound 1
the two heaviest packages must not share a bin 1
degenerate inputs 2
payload assertions: the cross-writer count/items invariant 9
path resolution: the silent weight-0 cwd defect 5
the balancing pins (#10472) 16

SELF_TEST_BATTERY_FLOOR = 7 pins the roster's own size — deleting an entry silences a floor exactly as effectively as zeroing it.

One floor deserves its note in the body, and has one. 2 of the balancing pins' 16 are the end-to-end inversion pin, which runs only while scripts/test-shard-timings.json still carries both packages of its inversion pair. That guard is silent today: drop either package in a timings refresh and the pin stops testing anything while everything stays green. Flooring at the measured 16 makes that loud, and the remedy is the one the pin itself already names — pick a new inversion pair from the dataset — never lowering the number. The alternative (floor 14, the count that cannot move with the dataset) keeps the silent vacuous pass, which is the defect this card exists to remove.

The floor throws rather than pushing onto a failures array, because that is how every other assertion in this file reports; the existing dispatch turns it into a non-zero exit.

Proof

  • Semantic identity, mechanical. For all 36 wrapped sites, the block inside the thunk with leading whitespace stripped per line diffs empty against the original block with leading whitespace stripped per line. Wrapped-site count == pre-change assertion-site count == 36 (22 single-line + 14 multi-line), the sites located by a statement-boundary parse of the base tree rather than by eye.
  • Case count before == after. The base file prints no count, so the base was instrumented with a counter at each of the 36 sites, run, and restored — restore proven by git hash-object equality against the HEAD blob plus an empty git diff HEAD, never by the restore command's exit code.
  • Verdict output unchanged. --self-test prints a line byte-identical to the base tree's.
  • Ablation. A battery opener renamed so it registers nothing → --self-test exits non-zero naming that battery DID NOT RUN; restored → green. Mutation proven on disk by marker count, restore by hash equality.
  • The test(scripts): give 13 more self-tests a battery roster and floor #15003 hazard. extractWatchHints over this file on both trees is byte-identical — the seven new battery-name string literals do not read as path populations.
  • The card's own instrument. node scripts/measure-self-test-floor.mjs before/after: the unfloored count drops by exactly 1 and the new roster entry is this file.

Full numbers, commands and captured exit codes are in the os-dev-report comment on #13799.

Scope

One file plus this PR's label. scripts/pm/dispatch-gates.mjs stays DEFERRED, scripts/pm/check-half-states.mjs is its own batch, class-2/3 files untouched. The card stays open — 49 deferrals remain after this one, so this is Part of, not a closing keyword.

skip-changeset: scripts/** publishes from no package, the same call batch 3 made.


🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

…oute (#13799 batch 4)

Its 36 assertions are bare `throw`s, which is why batches 2 and 3 deferred
this file twice: routing them through a boolean helper means inverting 36
failure conditions by hand, and a dropped `!` yields an assertion that still
registers its case and still passes -- invisible to the very floor being
installed.

The thunk route touches no condition. `check(() => { ... })` counts a case and
then runs the existing `if (...) throw ...` verbatim, carried in modulo
indentation only; 22 sites were single-line and 14 multi-line, several nested
in a `try`/`finally` and behind a dataset-presence guard. Seven batteries are
declared from the seven banners that register cases (2/1/1/2/9/5/16 = 36), the
roster's own size is pinned, and the floor is evaluated before the verdict so
the success line cannot be printed by a run whose batteries went quiet.

The self-test's printed verdict is byte-identical to the base tree's.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026
@github-actions github-actions Bot added the size/m label Sep 4, 2026
@baozhoutao
baozhoutao marked this pull request as ready for review September 4, 2026 06:09
@baozhoutao
baozhoutao enabled auto-merge September 4, 2026 06:09
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 82a9ebf Sep 4, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch4-thunk-sink branch September 4, 2026 06:49
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
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants