Skip to content

test(scripts): floor only the unconditional cases of run-with-stall-guard and release-rehearsal-clone (#15317 ruling B) - #15399

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-15317-conditional-floors
Sep 4, 2026
Merged

test(scripts): floor only the unconditional cases of run-with-stall-guard and release-rehearsal-clone (#15317 ruling B)#15399
baozhoutao merged 2 commits into
mainfrom
claude/issue-15317-conditional-floors

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #15317

Ruling B on the two b5 hoisted single batteries PR #15308 landed for batch 8a of #13799.
Both floors counted cases that only run when the ENVIRONMENT provides something. Off Linux,
or in a checkout missing a wiring file, those floors red for the host rather than for a case
that stopped running — and the remedy an author reaches for is editing the floor down, the one
habit these floors exist to prevent. The conditional cases keep asserting exactly as they did;
what changes is that they no longer register against the floor, and the guard now says why.

What moved

scripts/run-with-stall-guard.mjs — 21 of the 41 cases sit behind
const linux = existsSync('/proc'): process classification, the SIGTERM-trapping descendant,
the source-side liveness probe and its cap. They now report through checkConditional, a sink
that pushes into the same failures/results arrays with the same label and detail, and calls
registerCase() never. Floor 41 -> 20. The block already named itself on skip
((process-classification cases skipped: /proc not available)); that line is untouched.

scripts/pm/release-rehearsal-clone.mjs — C10's two wiring cases sit behind existsSync of
docs/releases-maintenance.md and of .github/workflows/lint.yml. They now report through
tConditional, same failures tally, no registration. Floor 32 -> 30. C10 gains the equivalent
(C10 wiring cases skipped: ... not present) line, so a guard that skipped can never read as one
that ran and held.

The guards themselves are untouched, no condition is inverted, and no assertion condition, message
or argument changed. The only deletions are inside the two sinks: each original body was split into
a non-registering reporter (record / report) plus a thin registering wrapper that keeps the old
name (check / t), so every existing call site is unchanged.

The floors are MEASURED off a run, never derived by subtraction

Pin the floor to 9999, run, read the breach line the self-test prints:

✗ self-test battery "run-with-stall-guard self-test" registered 20 case(s), below its pinned floor of 9999 — cases that used to run no longer do.
✗ self-test battery "release-rehearsal-clone self-test" registered 30 case(s), below its pinned floor of 9999 — cases that used to run no longer do.

20 and 30 are those readings, not 41 minus 21 and 32 minus 2 done by hand.

Green lines are byte-identical to the installed base

Both self-tests, stdout+stderr, this branch vs a worktree at the merge base:

  • run-with-stall-guard --self-test: whole output cmp-identical, 42 green lines
    (41 cases + ✓ 41 case(s) passed).
  • release-rehearsal-clone --self-test: 33 green lines, identical except one case that prints a
    wall-clock figure (C2 a healthy tree is not slowed (102 ms < 10000)). That figure moves between
    two runs of the BASE at the same commit (102 ms then 95 ms), so it is nondeterminism the base
    already had, not a change this diff made. With that one number normalised the green lines are
    cmp-identical.

Both suites still run every case here: 41 and 32 assertions execute, exactly as before. Only the
registration changed.

Ablations

Each mutation was proven on disk by blob hash plus grep counts before its reading was taken, and
each restore proven by hash equality against the HEAD blob plus an empty git diff HEAD, under a
trap ... EXIT INT TERM.

(a) The environment simulated absent — least-invasive path-literal mutation
(existsSync('/proc') and the two join(REPO_ROOT, ...) wiring paths pointed at names that do not
exist). Both self-tests go GREEN, both print their cases skipped line naming what was missing, and
both floors hold: ✓ 20 case(s) passed and ✓ self-test passed.

The same mutation against the installed base is the counter-control, and it is the defect this card
exists to remove — the base REDS on the floor, for the environment:

✗ self-test battery "release-rehearsal-clone self-test" registered 30 case(s), below its pinned floor of 32 — cases that used to run no longer do.

(b) registerCase() removed from the unconditional sink — the floor calls it, and says so:

✗ self-test battery "run-with-stall-guard self-test" DID NOT RUN — 0 cases registered, 20 pinned. The verdict below would have claimed those cases hold.
✗ self-test battery "release-rehearsal-clone self-test" DID NOT RUN — 0 cases registered, 30 pinned. The verdict below would have claimed those cases hold.

All 41 and all 32 case lines stayed green under that mutation and were cmp-identical to the
unmutated run — which is exactly the point: nothing but the floor can see this.

(c) A conditional case forced to fail with the environment present — the run reds on it, so the
cases are still real assertions rather than decoration:

✗ idle hang is classified idle, not on-CPU
✗ 1 failure(s) (cases and floor) — the stall guard does not do what its callers assume.
✗ C10 the rehearsal doc names this script
✗ self-test: 1 failure(s) (cases and floor)

The instrument does not move

node scripts/measure-self-test-floor.mjs --json, at the merge base vs this branch (170 files both
sides): both target files stay ROSTER, the tally is identical (163 ROSTER / 6 NONE / 1 COUNT), and
nothing entered NONE. Zero floor-class changes attributable to this diff.

Gates

Run at cf532f2b3, exit codes captured before any pipe. The derived family from
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack — all 25 commands,
green. The always-runs tail — check:pm-dispatch-gates, check-self-test-workflow-commands.mjs
both modes, check:declared-population-live, check-self-test-wired.mjs both modes,
check:ratchet-remedy-authority, check:nul-bytes, check:watch-hint-literal — green. Whole-repo
pnpm lint — green. Both files' own self-test suites are their test suites; no vitest file in the
repo names either script.

The first derivation ran on a tree 13 commits behind and the tool said so, naming
scripts/pm/dispatch-gates.mjs itself among the files that had changed. Re-deriving after merging
origin/main added pnpm check:driver-memory-census to the family — so the staleness was real, and
the number above is the fresh one.

skip-changeset: this PR publishes nothing from any package — it edits two files under scripts/.

🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

`run-with-stall-guard.mjs` (floor 41) and `pm/release-rehearsal-clone.mjs`
(floor 32) each pinned an assertion floor over a battery whose case count
depends on the HOST, not on whether the cases ran: 21 of the stall guard's
cases sit behind `existsSync('/proc')`, and 2 of the rehearsal clone's behind
`existsSync` of the rehearsal doc and of `lint.yml`. Off Linux, or in a
checkout missing either file, those floors red for the ENVIRONMENT — and the
remedy an author reaches for is editing the floor down, the one habit these
floors exist to prevent.

The environment-conditional cases now go through a sink variant that reports
into the same `failures`/`results` sinks and registers nothing
(`checkConditional`, `tConditional`). Their conditions, messages and arguments
are unchanged; the guards are untouched and no condition is inverted. Why they
are outside the roster is stated at the guard and in the roster comment.

Floors re-measured off a run at pin 9999, never derived by subtraction:
41 -> 20 and 32 -> 30, read from the breach line each self-test printed.

The skipped block still names itself: the stall guard keeps its existing
`(process-classification cases skipped: /proc not available)` line, and C10
gains the equivalent `(C10 wiring cases skipped: ... not present)` line so a
guard that skips can never read as one that ran and held.

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 14:28
@baozhoutao
baozhoutao enabled auto-merge September 4, 2026 14:28
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 52d5a52 Sep 4, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-15317-conditional-floors branch September 4, 2026 15:13
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

2 participants