fix(devx): the durability-log-level self-test handshake asserts "ran to the end", pass or fail - #15504
Conversation
…to the end", pass or fail
`selfTest()` set `selfTestReachedVerdict` on its SUCCESS path only, and the
dispatch read that flag BETWEEN the two batteries. A genuine red therefore
printed its own verdict line and was then reported as
"selfTest() returned without reaching its verdict" — false, since the verdict
had just been printed — and the process exited before `selfTestReadSeams()`
ran at all, which is exactly what the comment above the dispatch forbids
("a red one must not hide the other"). Exit 1 either way, so no false green;
the cost was a misleading diagnostic plus half the self-test coverage lost on
the red path.
Both halves of the repair:
- the flag is now set at BOTH verdict sites of each battery, adjacent to the
line it certifies, so it can only be true if a verdict was really printed;
the returned status keeps carrying pass/fail;
- the dispatch runs BOTH batteries first and reads both handshakes after, then
exits with the combined status.
An early `return` above either verdict still trips that battery's own named
diagnostic — the property the handshake was landed for is unchanged.
`scripts/check-dispatcher-error-vocabulary.mjs` ships the same landed shape and
is deliberately untouched: its failure path calls `process.exit(1)` inside the
self-test, so its flag is never consulted on a red.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
|
ACCEPT — PM seat Reviewed against the three-dot diff Generated by Claude Code |
Fixes #14962
The defect
selfTest()setselfTestReachedVerdicton its SUCCESS path only, and the dispatch read thatflag BETWEEN the two batteries. A genuine red therefore printed its own verdict line and was
then reported as
selfTest() returned without reaching its verdict— false, the verdict hadjust been printed — and the process exited before
selfTestReadSeams()ran at all, which isexactly what the comment one line above forbids ("a red one must not hide the other").
Exit 1 either way, so this was never a false green. The cost was a misleading diagnostic plus
half the self-test's coverage lost on the red path.
The option taken, and why
The card names two legitimate repairs. This PR takes the first: the handshake asserts
"ran to the end", pass or fail, and the returned status keeps carrying the verdict — per the
dispatching PM's ruling on this card.
Concretely:
selfTestReachedVerdictis now set at both ofselfTest()'s verdict sites — the greenN case(s) passedline and the redN failure(s) (cases and floor)line — each assignmentplaced adjacent to the line it certifies rather than once before the branch, so the flag
can only be true if one of the two verdict lines was really printed;
readSeamsReachedVerdictgets the same treatment at its own two verdict sites;with the combined status (
handshakeMissing || logLevelStatus || readSeamStatus).Why this option rather than "each battery gets its own handshake, checked after both have run":
the two are not exclusive, and the second alone does not fix defect #1. Both flags already
existed, one per battery; moving the checks after both calls restores the lost coverage, but a
success-only flag would still print
returned without reaching its verdictunder a red batterythat plainly reached it. Only redefining what the handshake asserts removes the false
diagnostic, and the "check after both" half is folded in with it.
What the handshake was landed for is unchanged: an early
returnabove either verdict stilltrips that battery's own named diagnostic, and exits 1 — ablations (b) and (c) below.
scripts/check-dispatcher-error-vocabulary.mjsships the same landed shape and is deliberatelyuntouched: its failure path calls
process.exit(1)inside the self-test, so its flag isnever consulted on a red. The divergence is now written down beside this file's flag, so the
next author does not "harmonise" it back.
Ablations
All four run against the committed implementation (
dfad2f273), each through one harnessthat mutates, proves the mutation reached disk (a
grep -cof the injected marker, refusingto run at zero), runs, then restores under
trap ... EXIT INT TERMand proves the restore bygit hash-objectequality against the HEAD blob plus an emptygit diff HEAD. Every run'srestore printed:
(a) force battery 1's failure branch (
if (failures > 0)to>= 0atselfTest's verdict,one line, marker
ABLATION-A-FORCED-RED, on-disk count 1):Battery 2 ran and printed its own verdict; exit 1; no false handshake diagnostic. This is the
same probe that, on
origin/main(4f85e4d) before the fix, produced the card's reading:(b) early return from
selfTest()before its verdict (if (true) return 0;injected abovethe floor check, marker
ABLATION-B-EARLY-RETURN, on-disk count 1).return 0deliberately, sothe only thing that can turn the run red is the handshake:
(c) early return from
selfTestReadSeams()before its verdict (same shape, markerABLATION-C-EARLY-RETURN, on-disk count 1):(d) unmutated, both green:
Verification
Every exit code captured by redirecting first (
cmd > file 2>&1; EXIT=$?), never read after apipe. Union run on the final commit
dfad2f273.pnpm check:durability-log-level(branch)✓ durability-degradation log levels: 29 durability-critical catch seam(s), all loud, ...and✓ read-seam invention (#5186 + #6451 + #9165, 3 package roots, ...): 66 read seam(s), none invents an unreported answer ...node scripts/check-durability-degradation-log-level.mjs --self-test(branch)✓ self-test (log-level rule): 63 case(s) passed·✓ self-test (read-seam invention rule): 57 case(s) passed, ...origin/maincontent (4f85e4d, pristine worktree before the edit)cmpexit 0, md5af1a04bcc31133437b711898fc946e69both sidesnode scripts/measure-durability-swallow-family.mjscmpexit 0) — no vocabulary driftnode scripts/measure-durability-swallow-family.mjs --self-test=gated✓ measure-durability-swallow-family self-test, gated families (#13919): 3 negative control(s) yield none, 2 regression control(s) stay clear, 6 resolution control(s) resolve as declared, 3 DETERMINED register row(s) cross-check clean, 56 member site(s) total— byte-identical before/afternode scripts/measure-self-test-floor.mjsmeasure-self-test-floor: 170 file(s) under scripts/ dispatch on --self-test.— output byte-identical before/after, and the roster still namesscripts/check-durability-degradation-log-level.mjspnpm -s check:pm-dispatch-gates✓ dispatch-gates self-test: 1402 cases pass.(no case edited)pnpm check:nul-bytescheck-nul-bytes: OK (scanned 7502 text file(s) ... no raw ASCII control bytes).pnpm lint(repo-wide,eslint . --no-inline-config)os-verify-lock: VERDICT command-exit 0 · held the lock 97s (1m37s) · waited 152s (2m32s)The instrument comparisons above were taken by reverting the file to its HEAD blob, running each
instrument, then reapplying the diff — the reapplied file hashed back to
38738c52d483d9e1f11f1f2afe5b58a1b8f3a3c3, byte-for-byte the committed content.Derived gate family.
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 25 commands from the committed change set (its own stderr: "gate list derived from the tree
of 'objectstack-ai/objectstack' at commit dfad2f2", change set "1 path(s) vs merge base 4f85e4d").
All 25 ran; all exited 0 — the table's rows plus
check-reference-carrier-shape(+ self-test),check-ci-filter-parity,check-closing-keyword-parity(+ self-test),check-comment-mask-corpus,check-self-test-wired(+ self-test:✓ check-self-test-wired: every one of the 169 script(s) CI runs that ship a --self-test has that self-test run by CI.),check-whole-set-label-write(+ self-test),bare-root-worklist --self-test,check:agent-test-spelling,check:bash32-floor,check:cli-command-ids,check:cross-package-test-inputs,check:driver-memory-census,check:entry-guard,check:parse-guard,check:pnpm-filter-targets,check:ratchet-remedy-authority,check:refd-timer-probe,check:watch-hint-literal.Beyond the derived set, the six artifact-roster gates the tool flags as keeping their roster under
scripts/(where this path lives, so their silence is evidence in neither direction) were runtoo:
check-published-list-mirrors(+ self-test),check:console-injection,check:engine-double-contract,check:i18n-stale-fill— all exit 0. The sixth,pnpm check:published-readme-exports, exits 1 in a fresh worktree and is recorded NOT MEASURED,not a red: every one of its findings is
... whose type entry packages/PKG/dist/... does not exist. Build first, i.e. an unbuilt workspace, and its inputs are README files anddist/typeentries — nothing this diff touches.
Scope
scripts/-only; publishes nothing from any released package, soskip-changeset. No self-testcase's expected outcome was edited, no gate's normal-mode reading changed, no dispatch-gates case
touched, and
scripts/measure-durability-swallow-family.mjs(in flight on another branch) was notedited.
🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code