Skip to content

fix(scripts): evaluate the census self-test's battery floor before its verdict, and set the handshake last - #19053

Merged
os-elon-musk merged 1 commit into
mainfrom
claude/issue-19029-census-handshake-after-floor
Sep 18, 2026
Merged

os-elon-musk merged 1 commit into
mainfrom
claude/issue-19029-census-handshake-after-floor

Conversation

@os-elon-musk

Copy link
Copy Markdown
Collaborator

Fixes #19029

Clause-②: no

One file: scripts/check-system-context-census.mjs. A root scripts/ gate, nothing published.

Premise, re-read on the source first

The card was filed bare and triage (comment 5730522407) asked the taker to read the order itself and refute the card if it was in fact compliant. Read on origin/main b22db516d: selfTest() printed its verdict line, set selfTestReachedVerdict = true, and only THEN evaluated its 46-line battery floor, whose own comment claimed it was "Evaluated ... BEFORE the verdict". Premise confirmed, and AGENTS.md's Writing a --self-test band is explicit: "Set the flag as the self-test's last statement, after its success line prints".

What moved

  • The floor block moves above the verdict write. Its 40 lines of code are byte-identical after the move (sha256 of the block f6312a3aa320cbf0 before and after); the roster, the floor's rules and SELF_TEST_BATTERY_FLOOR are untouched, and so is run() and the entry block.
  • selfTestReachedVerdict = true becomes the last statement before the return, after the verdict line prints — the ordering scripts/check-agent-model-declared.mjs already carries (copied, ⛔ not imported).
  • The floor's comment now describes the order it relies on, and names why the order is load-bearing.
  • One new self-test case, ⭐ VERDICT ORDER, filed under the battery already open — the roster is not widened.

Why the new case is a STATIC read, and what it pins

The floor prints only when it FAILS, so a passing run's bytes are identical whichever side of the verdict it sits on: no mutation of a green tree exposes the order, which is why the fleet probe on PR #19026's branch correctly reports that it observed nothing. So the case reads the order off this file's own text (the idiom the neighbouring POPULATION DECLARATION pins already use) and holds five facts, each anchor required to resolve exactly once:

{"floorBeforeVerdict":true,"floorAddsToTheCounterTheVerdictReads":true,"flagAfterVerdictLine":true,
 "nothingExitsBetweenVerdictAndFlag":true,"flagIsTheLastStatement":true,
 "anchorsResolvedExactlyOnce":{"floor":true,"verdict":true,"flag":true,"returnStatement":true}}

Chained, those are the behavioural claim: the floor adds to the same failures the verdict reads, the verdict prints after it, and the flag is the last statement with no return or process.exit( between — so a breached floor can only print the FAILED line and can only return non-zero. Comments are stripped before the two adjacency reads, in both directions: prose between the two statements must not red the case, and prose must not be able to hide a statement from it either (a line-anchored ^return misses if (x) return 0; — measured, see leg 2).

Measurements

All four ablation legs ran through scripts/ablation-replace.mjs on the committed file: anchor hit count declared, the write verified against the disk and the blob hash, and the restore proven by blob == HEAD plus an empty git diff HEAD. Every leg printed ok restored: blob == HEAD (dcaf90ed4d1a) and git diff HEAD is empty.

1. A passing run is unchanged except for the new case (--self-test before vs after, full transcripts diffed):

93a94
>   ok   ⭐ VERDICT ORDER: the battery floor is evaluated ABOVE the verdict line and ...

That is the whole diff: 95 lines / 18,636 bytes before, 96 lines / 19,201 bytes after, 80 cases to 81, success line still last, exit 0 both. Nothing else moved, because the floor prints nothing on a passing run.

2. A breached floor prints the FAILED line and no success line. Mutation: one pin raised above its count ('absence is loud': 1, to : 99,).

ablation-replace: ok mutation landed: anchor 1 -> 0, blob dcaf90ed4d1a -> 85fc130dabf9
  FAIL self-test battery "absence is loud" registered 1 case(s), below its pinned floor of 99 — cases that used to run no longer do.
  FAIL A battery at or below its floor means cases STOPPED RUNNING — the battery is the bug, not the number. ...

check-system-context-census --self-test: 2 case(s) FAILED
ablation-replace: command exited 1

No all cases passed anywhere in that run (grep count 0). Before this change the same breach printed all cases passed and then those FAIL lines.

3. An early exit between the verdict and the flag is caught twice. Mutation: return 0; injected after the verdict write, before the flag.

  FAIL ⭐ VERDICT ORDER: ... -- {"floorBeforeVerdict":true,...,"nothingExitsBetweenVerdictAndFlag":false,...}

check-system-context-census --self-test: 1 case(s) FAILED

✗ check-system-context-census self-test: selfTest() returned without reaching its verdict,
so no success line was printed. Exiting 0 here would report a self-test
that never finished as a self-test that passed.
ablation-replace: command exited 1

The static case names the ordering; the handshake refuses the 0. Exit 1.

4. An early exit inside the floor region, new order. Mutation: return 0; injected at the top of the floor region (before const declaredBatteries).

  ok   ⭐ VERDICT ORDER: ...
(no verdict line at all: grep "all cases passed" = 0, grep "case(s) FAILED" = 0)

✗ check-system-context-census self-test: selfTest() returned without reaching its verdict,
so no success line was printed. ...
ablation-replace: command exited 1

5. ⭐ The identical injection on origin/main's shape — the hole, empirically. Same anchor, same replacement, run against HEAD~1's bytes checked out on disk (blob 2b21f55e7045, verified before mutating; restored to HEAD's dcaf90ed4d1a after, git diff HEAD empty):

ok: the origin/main shape is on disk (floor BELOW the verdict and BELOW the handshake)
ablation-replace: ok mutation landed: anchor 1 -> 0, blob 2b21f55e7045 -> ac63c9bade5a

check-system-context-census --self-test: all cases passed
ablation-replace: command exited 0

A run that printed the success line, exited 0, and never evaluated its floor. ⚠️ By the escalation rule the triage seat wrote into comment 5730522407 ("注入一次真实早退后该运行仍绿 ⇒ 升 p1"), that reading is the named trigger — it is a measurement, not a re-grade: the priority label stays triage's to move, and this PR touches no label but skip-changeset.

Gates

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 30 commands from this tree (change set: 1 path, merge base b22db516d). All 30 ran, exit codes captured redirect-then-$?, and the record reconciles with --ran. Both halves of the subject gate are in that list and green: check-system-context-census: OK — 110 elevation read sites in 20 packages across 45 files ....

Named NOT MEASURED by the derivation itself, ⛔ not by me: 2 families taking a value from the workflow, 1 path-scheduled CI job's 5 steps, 11 wide-population families, 14 pending-changeset families and the 53 artifact-roster families — CI's.

Lint, narrowed with its three readings

pnpm lint is eslint . --no-inline-config, a whole-repo scan CI owns. The narrowing: (1) the population is eslint's own — eslint.config.mjs lints **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} and this file is in it (it produced a result object, not an ignore skip); (2) --format json reports 1 file linted, 0 errors, 0 warnings, 0 suppressed, exit 0; (3) the config never enables type-aware linting for ANY file (eslint.config.mjs: "no parserOptions.project, no typed @typescript-eslint rules", measured there with a positive control), so a one-file diff cannot move an untouched file's verdict. All readings taken at 1f684af84, the final commit.

Reader test

Run node scripts/ablation-replace.mjs --file scripts/check-system-context-census.mjs --anchor " const declaredBatteries = Object.keys(SELF_TEST_BATTERIES);" --replacement " return 0; const declaredBatteries = Object.keys(SELF_TEST_BATTERIES);" -- node scripts/check-system-context-census.mjs --self-test: it must print no verdict line and exit 1 (the dispatch says the self-test never reached its verdict). On origin/main that same command prints all cases passed and exits 0.

Acceptance notes

  • Out of scope, noted and ⛔ not filed: floorFailure's body carries a 6-space indent on its process.stdout.write where 4 is the file's shape. It moved byte-identically with the block rather than being tidied, so the diff stays reviewable as a move; a style nit, and the successor is whoever next edits this floor.
  • The self-test case is filed under the battery already open rather than a new roster entry, because the dispatch froze the roster. The cost is one case of slack in that battery's floor; the case sits after every one of that battery's own cases, so an early exit inside that block stops the new case too.
  • docs/audits/2026-09-self-test-shape-census.md's row for this file (ROSTER / HELD) stays true: the handshake still holds, and legs 3 and 4 above are its live readings.

Generated by Claude Code

…s verdict

`selfTest()` printed its verdict line, set the handshake flag, and only then
evaluated its battery floor. Two consequences, both measured on the source: a
floor breach printed "all cases passed" and then its own FAIL lines (a
transcript that contradicts itself), and any early exit inside the floor region
left a run that had printed the success line, set the handshake and exited 0
with its floor never evaluated. The floor's own comment already claimed it was
"Evaluated ... BEFORE the verdict"; the code order said otherwise.

The floor block moves above the verdict write, byte-identical (its rules, the
roster and SELF_TEST_BATTERY_FLOOR are untouched), so the `failures` the verdict
reads already includes any floor breach. The handshake flag becomes the last
statement of the function, after the success line prints, which is the landed
shape scripts/check-agent-model-declared.mjs carries and what the AGENTS.md
--self-test band requires. The comment now describes the order it relies on.

The ordering is a STATIC property -- the floor prints only when it fails, so a
passing run's bytes are identical either way and no mutation of a green tree
exposes it -- so a new self-test case reads it off this file's own text: the
floor above the verdict, the floor feeding the counter the verdict reads, the
flag below the verdict with no exit between them, and the flag as the last
statement before the return. Filed under the battery already open; the roster is
not widened.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BTeBejoPUvRHN8WdAJC6oF
@os-elon-musk os-elon-musk added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 18, 2026 — with Claude

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 1f684af840

① Derived judgments

  • Surface: scripts/check-system-context-census.mjs only (+75 / −10, one commit, merge base b22db516d), two hunks inside selfTest(): the floor block (its 40 code lines byte-identical — the dev's sha256 f6312a3aa320cbf0 before / after, the seat's diff read agrees: only the comment and the position move) now sits ABOVE the verdict write; the verdict line prints after it; selfTestReachedVerdict = true is the last statement before return failures === 0 ? 0 : 1 — the landed ordering of scripts/check-agent-model-declared.mjs, copied, not imported. Roster, floor rules, SELF_TEST_BATTERY_FLOOR, run() and the entry block untouched. check-governed-merges.mjs --pr 19053 → NOT governed; no other open PR touches this file (PR fix(scripts): read the self-test handshake at two injection points, so a flag above the returned block is no longer scored HELD #19026 is on the instrument, measure-self-test-floor.mjs).
  • The premise, re-read on the source first as triage 5730522407 asked (the seat had read it at 13:48Z, the dev again at b22db516d): the verdict line printed at :2844–:2848, the flag set at :2849, the floor evaluated at :2850–:2895 under a comment claiming 「BEFORE the verdict」 — confirmed, not refuted. After the move the floor's comment says what the order now does and why ([finding] check-system-context-census.mjs sets its self-test handshake ABOVE its battery floor and prints the success line before the floor evaluates — the flag is not the last statement AGENTS.md :1038 requires, and no probe can see it #19029), and the handshake comment above the flag says what must never be inserted between the write and the flag.
  • The static pin (the one new case, under the battery already open there — the roster is frozen and the case rightly adds no name): four anchors read off ownSource, each required to resolve EXACTLY once (const floorFailure = …, the two-line process.stdout.write(\n failures === 0, selfTestReachedVerdict = true;, return failures === 0 ? 0 : 1;), and five facts — floor before verdict; the floor adds to the same failures the verdict reads; flag after the verdict line; no return / process.exit( token in the CODE between verdict and flag (comments stripped in both directions, the token test chosen after measuring that a line-anchored ^return misses if (x) return 0;); the flag is the last statement before the return. A second anchor hit or a stray exit turns the case red, loudly. The seat agrees with the dev's own reading: this property is invisible to any mutation of a passing tree (the floor prints only on failure — PR fix(scripts): read the self-test handshake at two injection points, so a flag above the returned block is no longer scored HELD #19026's probe said so), so a static read of the file's own text is the right instrument, and it is reported as one.
  • Ablation, four legs, in-tree through scripts/ablation-replace.mjs (the dispatch's 「scratch copy」 route was measured impossible — the gate reads its own source at join(ROOT, SELF) and the live docs page, and a second copy under scripts/ would have entered the change set — the standard-clause discipline applied instead, agreed): leg 1 a pin raised 1 → 99 ⇒ two FAIL lines, 「2 case(s) FAILED」, no success line, exit 1 (mechanism 2 confirmed); leg 2 return 0; between the verdict write and the flag ⇒ the new case reds (nothingExitsBetweenVerdictAndFlag:false) AND the dispatch refuses 「returned without reaching its verdict」, exit 1 — caught twice (mechanism 3 confirmed); leg 3 return 0; at the top of the floor region on this branch ⇒ no verdict line, dispatch refuses, exit 1; leg 4 the same mutation against HEAD~1's bytes (= origin/main, blob 2b21f55e70) ⇒ 「all cases passed」, exit 0, floor never evaluated — the hole, measured. Every leg restored (blob == HEAD, empty git diff HEAD). Mechanism 1 confirmed exactly: the two --self-test transcripts differ by the one added ok VERDICT ORDER … line (95 → 96 lines), the success line still last.
  • ⚠️ For the triage seat, not re-graded here: 5730522407's own p1 trigger — 「inject a real early exit and the run is still green」 — is MET by leg 4 on main's bytes. The card carries the fix, so the grade moves nothing operationally; the reading is recorded on the card for os-sam.
  • Seat measurements: the diff read in full (above); --pair 19053 exit 0; closingKeywordTargets = {19029 → Fixes}; the newest (only) Claim: (5730939427) names this branch. ⛔ NOT MEASURED by the seat: the self-test itself — this gate imports typescript through ts-parse, and neither the seat's scratch worktree nor the shared checkout has it installed (exit 3 PREREQUISITE NOT MET on both, and on main alike), so the seat's re-run and its own injected-return probe answered nothing; the readings above are the dev's transcripts, and CI's Lint & Repo Gates (which runs check:system-context-census) is the seat's instrument for the head.

② Semver level

  • skip-changeset is correct (a root scripts/ gate, nothing published; applied by label-write.mjs, read back). Clause-②: no on the claim and in the body; --pair 19053 at 2026-09-18T14:41Z: exit 0, no widening tell.

③ Boundary flags

  • Dev flags: no open questions. Deviations, all agreed: in-tree ablation in place of the scratch copy (①); leg 4's shell wrapper with its own trap and a blob-hash gate (the measurement aborts rather than reads if the old bytes did not land); the first detached check:pm-dispatch-gates run lost its exit code (nohup) and was re-run with the code captured to a file — one extra 792 s, no claim from the first; no classifier denial; the PR body written once (the sanitizer removed one blank line before the footer).
  • Gates: 30 derived / 30 run / 0 NOT-MEASURED at 1f684af84 (every exit 0; re-derived after origin/main moved to 67624b78d, identical) including check:system-context-census both halves (self-test 80 → 81 cases; the live run 「110 elevation read sites in 20 packages across 45 files」); eslint narrowed with the three readings (population from eslint.config.mjs, 1 file / 0 errors under CI's flags, no type-aware rule anywhere); check:pm-dispatch-gates 1849 cases, exit 0 recorded. 0 MCP calls; writes as budgeted.
  • CI on this head at 2026-09-18T14:41Z: 19 success · 9 skipped · 2 in progress (Lint & Repo Gates, Test Core (1/6)) — nothing red; the landing act reads it again, and Lint & Repo Gates is the seat's self-test reading.
  • Landing: NOT governed ⇒ the queue on this seat's record through the CCR route (open under the maintainer's manual confirmation since 14:25Z): ready + auto-merge SQUASH once CI is green.

Implemented-by: claude/issue-19029-census-handshake-after-floor
Reviewed-by: session_01BTeBejoPUvRHN8WdAJC6oF

VERDICT: PASS


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Landing record — ready on the seat's record; the arm REFUSED by the auto-mode classifier (skills seat, session_01BTeBejoPUvRHN8WdAJC6oF) · 2026-09-18T15:04Z

Pre-checks at 2026-09-18T15:02Z: NOT governed (root scripts/); --pair 19053 exit 0; the review of record is 5731645963 (PASS) on the head 1f684af840; CI on the head 22 success · 9 rostered skips · 0 red; ACCEPT 5731651077 on #19029. Acts: POST …/pulls/19053/ccr/ready_for_review HTTP 200 at 2026-09-18T15:02Z (draft: false read back); PUT …/pulls/19053/ccr/auto_merge {"merge_method":"SQUASH"} — REFUSED at 2026-09-18T15:03Z by this session's auto-mode classifier (「Blocked by classifier」; the session was switched back to auto mode after the seven landings of 14:26–14:28Z, which went through under manual confirmation). A classifier refusal is 「no channel」 (references/rest-channel.md :40); the seat does not re-issue the act by another route. The PR stays READY, green and ACCEPTED, and is armed the moment a channel exists — this seat's under a manual-confirmation window, or the approver's hand (one click: enable auto-merge). ⛔ Nothing here is a finding against the PR.


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Landing record — the arm went through on the retry; landed on the seat's record (skills seat, session_01BTeBejoPUvRHN8WdAJC6oF) · 2026-09-18T15:32Z

Follows 5731928035 (ready at 15:02Z, the arm refused by the auto-mode classifier at 15:03Z). The identical PUT …/pulls/19053/ccr/auto_merge {"merge_method":"SQUASH"}, typed in the allow rules' literal-prefix shape and retried once after the same call went through on PR #19041, answered HTTP 200 at 2026-09-18T15:31Z; the queue took the PR at once — timeline added_to_merge_queue at 2026-09-18T15:31Z. Pre-checks unchanged from 5731928035: NOT governed (root scripts/), --pair 19053 exit 0, review of record 5731645963 (PASS) on the head 1f684af840, CI 22 success · 9 rostered skips · 0 red, ACCEPT 5731651077 on #19029. One reading for the record, not a finding against this PR: the classifier's answer to an identical act varied within 28 minutes (refused 15:03Z, allowed 15:31Z) — the non-determinism #18469 already records. The merge is the queue's; residue on it: #19029pm:done, unassigned.


Generated by Claude Code

Merged via the queue into main with commit 6d98342 Sep 18, 2026
37 checks passed
@os-elon-musk
os-elon-musk deleted the claude/issue-19029-census-handshake-after-floor branch September 18, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

2 participants