Skip to content

test(scripts): batch 6b — assertion floors for nine scripts/** self-tests (sink repair + hoisted battery) - #15248

Merged
baozhoutao merged 3 commits into
mainfrom
claude/issue-13799-batch6b-sink-plus-battery
Sep 4, 2026
Merged

test(scripts): batch 6b — assertion floors for nine scripts/** self-tests (sink repair + hoisted battery)#15248
baozhoutao merged 3 commits into
mainfrom
claude/issue-13799-batch6b-sink-plus-battery

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Part of #13799 (batch 6b — the class-1 + class-2 deferrals from PR #15003's table: sink repair plus a single hoisted battery).

Dispatched by PM claim 5536969005; dev claim 5536991755. Branched at origin/main = 1bc3c092a, the dispatch pin, re-read and still matching at the branch point. origin/main was merged in at 332ada04c (a real merge commit — no rebase, no force-push) after PR #15217 and three siblings landed; the merge touches neither of the two files this PR edits.

2 of the 9 dispatched files are floored here. 7 are deferred with a measured reason rather than improvised, per the dispatch's own instruction to defer table-driven / bare-throw files to the loop-body decision. The deferral is the finding of this batch, and the evidence is below.

Floored (2)

file sink kind on the pin helper shape battery cases
scripts/check-pnpm-acquisition.mjs concise arrow const t = (name, ok, detail) => cases.push({...}), called at 12 per-case sites the arrow gains a block body: registerCase() then the identical cases.push({ name, ok: Boolean(ok), detail }) check-pnpm-acquisition self-test 12
scripts/check-skill-frame-freshness.mjs cases.push({...}) written inline at 12 per-case sites, no helper ONE block-bodied in-body helper addCase(c): registerCase() then cases.push(c); the 12 sites call it check-skill-frame-freshness self-test 12

Both declare SELF_TEST_BATTERY_FLOOR = 1 (the roster's own size, so deleting the entry cannot silence the floor), UNATTRIBUTED_BATTERY, and a floor evaluated before the verdict that refuses a below-floor or DID-NOT-RUN battery and an undeclared one. Neither file carries two named section banners, so each declares ONE battery opened at the top of the self-test body — the PR #14896 / #15003 / #15217 hoisted shape. No comment is promoted to a section head. No assertion condition is inverted, rewritten, reordered or re-judged; the case objects are passed through untouched and the loop that runs them is not touched at all. A floor breach is filed into each file's own existing failure sink (cases with ok: false; the failed counter), so the existing verdict reds on it with no verdict line rewritten, and the #13798 handshake is byte-unchanged.

Case count before == after, measured on runs

file pin 1bc3c092a this branch
check-pnpm-acquisition 12 cases pass 12 cases pass
check-skill-frame-freshness 12 cases pass 12 cases pass

Line-level identity of the sink rewrite

Removed lines that do not reappear in the added lines after normalising indentation:

  • check-pnpm-acquisition1 residue, const t = (name, ok, detail) => cases.push({ name, ok: Boolean(ok), detail });. Fully explained: the concise arrow was split into head + registerCase(); + body, and its expression body cases.push({ name, ok: Boolean(ok), detail }); reappears verbatim inside the block body.
  • check-skill-frame-freshness12 residues, all of them the opener line cases.push({ rewritten to addCase({. The case object literals that follow never enter the diff at all, which is the point: nothing about any case changed.

Ablation (each leg proves its mutation landed on disk; each restore is proven by HEAD-blob hash equality, not by an exit code)

Both files are plain node scripts/NAME.mjs entrypoints — executed from source, never resolved through a package exports into a dist/, so no rebuild leg applies and no stale-artefact false green is available here. Both ablations ran against a committed implementation, so the restore leg had a real reference point. The harness carries trap ... EXIT INT TERM with absolute paths.

leg mutation confirmed on disk result restore
check-pnpm-acquisition, battery opener renamed anchor count 1 to 0, injected 1 exit 1battery "check-pnpm-acquisition self-test" DID NOT RUN — 0 cases registered, 12 pinned, plus the undeclared-battery refusal; 3 of 15 case(s) failed, so all 12 original cases still pass blob 2f60872 == HEAD blob, git diff HEAD empty
check-pnpm-acquisition, registerCase() removed from the helper anchor count 1 to 0 exit 1 — same DID NOT RUN line; 2 of 14 case(s) failed, so all 12 original cases still pass blob 2f60872 == HEAD blob, git diff HEAD empty
check-skill-frame-freshness, battery opener renamed anchor count 1 to 0, injected 1 exit 1 — undeclared battery registered 12 cases and the declared one DID NOT RUN; the 12 original cases tick green above the refusal blob b9ff265 == HEAD blob, git diff HEAD empty
check-skill-frame-freshness, registerCase() removed from addCase anchor count 1 to 0 exit 1 — DID NOT RUN, 0 registered of 12 pinned; the 12 original cases tick green above the refusal blob b9ff265 == HEAD blob, git diff HEAD empty

One ablation leg was rejected by its own landing check before it could produce a reading: the first registerCase()-removal attempt passed an anchor with a trailing newline, so grep -c read it as two patterns (the empty one matching every line) and reported 685 -> 684. The run stopped, the trap restored the tree, and the leg was re-run with a corrected anchor. Recorded because the first attempt produced no measurement, not a passing one.

extractWatchHints on both trees, per file

Run through the real extractWatchHints exported by scripts/pm/dispatch-gates.mjs (untouched by this PR), on the pin's content and this branch's content:

file pin 1bc3c092a this branch
check-pnpm-acquisition.mjs [".github/workflows"] [".github/workflows"] IDENTICAL
check-skill-frame-freshness.mjs [] [] IDENTICAL

check:watch-hint-literal green: 49 declarations across 4 rostered names.

The card's instrument, with the concurrent batch accounted for rather than asserted

node scripts/measure-self-test-floor.mjs --json, at the pin and on this branch:

reading pin 1bc3c092a this branch delta
NONE 54 43 −11
ROSTER 113 124 +11

11 files moved NONE to ROSTER across that range. 9 are PR #15217 (batch 5), which merged in between and is in this branch through the merge commit; 2 are this PR's. Unexplained movement: none. Symmetric difference of (moved, minus batch 5's nine) against this batch's floored worklist: empty. So the NONE drop attributable to this PR is exactly 2, the number floored.

All 7 deferred files read exactly as they did at the pin — six NONE, one COUNT — i.e. untouched.

Deferred (7), each with the measurement that decided it

⛔ Not improvised. The dispatch reserves table-driven and bare-throw files for the loop-body decision, and all seven measure as the same shape: a literal const cases = [ ... ] table, zero cases.push sites, exactly one loop over the table, and sink writes that are failure-only.

file PR #15003's reason measured at 1bc3c092a why deferred
check-refd-timer-probe.mjs failed sink at 5 inline sites; 0 banners literal table, 0 pushes, 1 loop, 5 failure-only writes, 2 continue table-driven; loop body carries continue
check-sdui-manifest.mjs failures sink at 1 inline site; 0 banners literal table, 0 pushes, 1 loop, 1 failure-only write table-driven
check-skill-compatibility-version.mjs failed sink at 7 inline sites; 1 banner literal table, 0 pushes, 1 loop, 6 failure-only writes, 3 continue table-driven; loop body carries continue
check-skill-frame-sync.mjs failed sink at 5 inline sites; 1 banner literal table, 0 pushes, 1 loop, 4 failure-only writes, 4 continue table-driven; loop body carries continue
check-skills-token-ratchet.mjs failed sink at 1 inline site; 0 banners literal table, 0 pushes, 1 loop, 1 failure-only write table-driven
check-widget-option-census.mjs failed sink at 5 inline sites; 1 banner literal table, 0 pushes, 1 loop, 5 failure-only writes, 4 continue table-driven; second literal table checks driven by a second loop
pm/check-skill-id-lint.mjs failed sink at 1 inline site; 0 banners literal table, 0 pushes, 1 loop, 1 failure-only write table-driven

Why the recipe cannot be applied to these without the reserved decision. PR #15003's table counts the failed += 1 / failures++ sites as "inline sites", but every one of them is lexically inside a failure branch or a catch — verified on all seven, guard by guard. So routing them through a block-bodied helper that calls registerCase() would register a case only when a case fails: a fully green run would register zero cases and the battery would read DID NOT RUN. That is the floor inverted, not installed — the one outcome this card exists to prevent. There is no per-case sink to repair, and the only site that executes once per case regardless of outcome is the loop body itself, which is exactly the loop-body decision the dispatch reserved. Batch 4's thunk is not an escape either: in 4 of the 7 the loop body carries continue, which cannot cross a function boundary, so check(() => { ... }) cannot wrap those bodies verbatim.

This matches the card's own Tier C wording — "table-driven self-tests where the natural roster is the table's own named rows rather than sections" — so the natural remedy for these seven is a roster of the table's named rows, which is a shape no batch has landed yet.

One re-verification correction to carry forward: check-refd-timer-probe.mjs reads COUNT, not NONE, on the instrument — it is one of the two files on the tree that derive and print a case count nothing compares (the other is pm/check-half-states.mjs, excluded by the dispatch). The card body names a different pair, which the two intervening batches have since moved.

Verification

Exit codes captured by redirect before any pipe; every result below is the gate's own printed verdict line, never a bare status variable. All runs in the foreground, on final commit 332ada04c (git rev-parse --short HEAD from the same tree the runs used).

Derived familynode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, which derives its own change set from the merge base (no hand-passed path list). The first derivation refused to be trusted, printing STALE TREE and naming check-ratchet-remedy-authority.mjs and dispatch-gates.mjs as changed under it; origin/main was fetched and merged and the family re-derived clean. 23 commands, all exit 0.

Always-runs tail: check:pm-dispatch-gates (1353 cases pass) · check:self-test-wired (168 scripts, every one CI runs) · check-self-test-workflow-commands and its --self-test · check:declared-population-live (201 of 252 families reach this tree's 8281 files) · check:ratchet-remedy-authority (202 scripts swept) · check:watch-hint-literal · check:nul-bytes (8274 files scanned, no raw control bytes). All exit 0.

Each edited script's own suite, normal mode against the tree and --self-test, all exit 0 — both are lint.yml gates and both stay green on the tree:

  • check-pnpm-acquisition normal + --self-test (12 cases pass)
  • check-skill-frame-freshness normal + --self-test (12 cases pass); normal mode reports the decision frame current with origin/main, 2 copies across 2 files

Neither script is named by any test file in the tree (git grep over test globs: no hits; referenced only from .github/workflows/lint.yml and package.json), so no separate suite is owed.

Control-byte scan of both edited files and of every body posted to GitHub: clean.

skip-changeset: this PR publishes nothing from any package — it edits two scripts/** gate self-tests. Label applied through the additive endpoint and read back.


Generated by Claude Code

…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
@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
…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
baozhoutao marked this pull request as ready for review September 4, 2026 07:33
@baozhoutao
baozhoutao enabled auto-merge September 4, 2026 07:34
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit cc2e39e Sep 4, 2026
35 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-13799-batch6b-sink-plus-battery branch September 4, 2026 08:14
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