fix(harness): control rows anchor on a machine token, not on audit.mjs's prose #64

Merged
bosun merged 2 commits from i/61-token-anchors into main 2026-07-14 13:09:57 +02:00
Owner

Closes #61.

audit.mjs emits a stable machine contract. Every control row anchors on that, not on a sentence. The auditor's prose is now free to improve — which is the entire point, because it kept improving and kept breaking its own controls.

The AC, and it is the whole PR

@herald's acceptance criterion: reword every human-facing sentence in audit.mjs; the suite must stay green. Watched to fail first, then watched to pass. One reword (31 sentences, 17 hunks, byte-identical across both arms, provably touching zero tokens), two control files, three runs:

arm controls auditor exit result
A prose-anchored (main) reworded 1 🔴 RED — 10 rows
B token-anchored (this PR) the same reword 0 GREEN — 0 red
C token-anchored untouched 0 GREEN — 36 green, 0 red

Arm A is the demonstration that the defect was ever real, and it is worth reading the failures:

🔴 FAIL — does not REFUSE without a target      ; missing: 'ctl-notagate.mjs: does not REFUSE without a target (exit 0, want 2)'
🔴 FAIL — and it names UNREACHABLE, the right branch ; missing: 'UNREACHABLE — refused in ALL THREE columns'
🔴   and it prints the invocation contract       ; missing: 'ONE argument, and only one'
🔴 FAIL — page built behind the primitive        ; missing: 'construct a page behind the primitive's back'
🔴 COULD NOT GRADE (exit 2), and it NAMES the file ; missing: 'ctl-mystery.ts  — not .mjs/.cjs, and not a NAMED exemption'
🔴 PASS — every harness refuses, gates, passes   ; missing: 'refuse, gate, and pass'
🔴 FAIL — the auditor calls it UNREACHABLE       ; missing: 'ctl-unreachable.cjs: ⛔ UNREACHABLE'
🔴 FAIL — a dead server called a FAILED BUILD    ; missing: 'ctl-deadserver.mjs: calls a DEAD SERVER a FAILED BUILD (exit 1, want 2)'
...10 rows

Not one of those is a behavioural failure. Every single red reads missing: '<a sentence>'. The auditor was correct in all three arms and did not regress once. Arm A is a correct auditor being convicted by its own controls for the crime of wording itself differently — which is the defect, reproduced on demand, instead of asserted.

The contract

AUDIT/1 ROW file=ctl-deadserver.mjs refuses=2 gates=1 passes=0 unreach=1 ok=0
AUDIT/1 UNREACHABLE file=ctl-unreachable.cjs
AUDIT/1 ESCAPE file=ctl-escape.mjs
AUDIT/1 UNGRADABLE file=ctl-mystery.ts
AUDIT/1 CONVICTED file=ctl-notagate.mjs
AUDIT/1 HINT id=invocation-contract
AUDIT/1 VERDICT result=PASS reason=all-gate harnesses=13 ok=13 convicted=0

CONVICTED is derived from the same array the FAIL prose iterates, so the token and the sentences cannot name different guilty sets — there is only one set.

It is an exit HOOK, and that is load-bearing

Not a call at each process.exit. audit.mjs has an exit path it does not own: loadChromium() in target.mjs calls process.exit(2) itself when playwright is missing. A hand-placed emit would be simply absent on the auditor's single most important refusal — and an absent token is indistinguishable from a token that matched nothing. So the hook emits on every path, and the default is COULD-NOT-GRADE reason=died-before-verdict: if it dies before reaching a verdict, it says so, instead of saying nothing and letting a grep read the silence as innocence.

That also settles a question the old control 1 was quietly wrong about: its needle (cannot resolve \playwright`) **is printed by target.mjs, not by audit.mjs` at all.** The universe of an anchor is not one file — it is the transitive closure of everything that writes to the log. Which is exactly why @surveyor's static must-NOT check was withdrawn in #53 after it flagged a healthy row.

§11 — the anchors themselves

A must-CONTAIN needle guards itself: typo it and the row goes red, and somebody looks. A must-NOT needle has no such guard. Typo it, or leave it pinned to a sentence that no longer exists, and it simply never matches. The row goes green.

AN UNFALSIFIABLE MUST-NOT PASSES BY BEING IMPOSSIBLE. It does not assert that the wrong branch stayed silent. It asserts that a string nobody can produce was not produced.

So §11 proves every must-NOT needle is a string this run's own logs show is producible — each one is the affirmative token of some other row's expected output. Rename a token and every row forbidding it now reddens by name, instead of going quietly green. It has its own control row (§0's discipline): it is fed an impossible needle and must catch it.

It forced a real correction. Control 9's must-NOT was newgate.mjs — which, when the gate works, appears in no log of the run at all. It was unfalsifiable. The machine form is both witnessed and strictly stronger: assert the audit emitted no AUDIT/1 ROW at all, i.e. it never graded anything.

I made the exact mistake this file exists to punish

I justified writeSync over console.log by writing that process.stdout is async when piped, so a console.log in an exit handler would be dropped down a pipe. Then I ran it.

lines emitted in an exit handler, DOWN A PIPE (want == N):
  N=1      console.log -> 1       writeSync -> 1
  N=5000   console.log -> 5000    writeSync -> 5000

It is not dropped. Not at one line, not at five thousand. I asserted a property of my own artifact nine lines below the paragraph in that same file which says, about this same mistake: "there is no claim here about what a grep returns. Run the thing."

writeSync stays — but the comment now says the honest reason. It is synchronous by contract, where console.log is synchronous by current measured behaviour on this Node and this platform. For the one line the entire gate reads, I would rather depend on the guarantee than on the measurement. There is no bug being fixed, and the comment says so.

Scope swept beyond the issue

#61 named audit.mjs's prose. The defect is the class — a row anchored on a sentence — and control 9 was anchored on a sentence audit-controls.sh prints about itself. Same bug, one writer over. It gets a CONTROLS/1 GATE id=dirty-source token rather than an exception. Disclosing the extension rather than quietly shipping it: I changed 1 site more than the issue asked for.

What this PR does NOT do

  • It does not make the prose emit-once. Both prose and tokens are printed. The tokens are additive; nothing was removed from the human-facing output, because the reader is still a person.
  • It does not wire CI. #63.
  • It does not version-negotiate. AUDIT/1 is a version marker, not a compatibility mechanism. If the contract ever needs to change incompatibly, bump it and move the anchors in the same commit — the marker exists so that a future reader knows there is a contract at all.
  • The reword instrument is not in the repo. A .py under harness/ would be graded by audit.mjs as UNGRADABLE and exit 2 — the auditor's own denylist discipline, biting correctly. It lives at /srv/claude/engineer/61-ac-instruments/reword.py alongside the three arm logs, so the arms can be re-run rather than re-argued.
Closes #61. `audit.mjs` emits a stable machine contract. Every control row anchors on **that**, not on a sentence. The auditor's prose is now free to improve — which is the entire point, because it kept improving and kept breaking its own controls. ## The AC, and it is the whole PR @herald's acceptance criterion: **reword every human-facing sentence in `audit.mjs`; the suite must stay green.** Watched to fail first, then watched to pass. One reword (31 sentences, 17 hunks, **byte-identical across both arms**, provably touching zero tokens), two control files, three runs: | arm | controls | auditor | exit | result | |---|---|---|---|---| | **A** | prose-anchored (`main`) | reworded | **1** | 🔴 **RED — 10 rows** | | **B** | token-anchored (this PR) | *the same reword* | **0** | ✅ GREEN — 0 red | | **C** | token-anchored | **untouched** | **0** | ✅ GREEN — 36 green, 0 red | Arm A is the demonstration that the defect was ever real, and it is worth reading the failures: ``` 🔴 FAIL — does not REFUSE without a target ; missing: 'ctl-notagate.mjs: does not REFUSE without a target (exit 0, want 2)' 🔴 FAIL — and it names UNREACHABLE, the right branch ; missing: 'UNREACHABLE — refused in ALL THREE columns' 🔴 and it prints the invocation contract ; missing: 'ONE argument, and only one' 🔴 FAIL — page built behind the primitive ; missing: 'construct a page behind the primitive's back' 🔴 COULD NOT GRADE (exit 2), and it NAMES the file ; missing: 'ctl-mystery.ts — not .mjs/.cjs, and not a NAMED exemption' 🔴 PASS — every harness refuses, gates, passes ; missing: 'refuse, gate, and pass' 🔴 FAIL — the auditor calls it UNREACHABLE ; missing: 'ctl-unreachable.cjs: ⛔ UNREACHABLE' 🔴 FAIL — a dead server called a FAILED BUILD ; missing: 'ctl-deadserver.mjs: calls a DEAD SERVER a FAILED BUILD (exit 1, want 2)' ...10 rows ``` **Not one of those is a behavioural failure.** Every single red reads `missing: '<a sentence>'`. The auditor was correct in all three arms and did not regress once. Arm A is a *correct auditor* being convicted by its own controls for the crime of wording itself differently — which is the defect, reproduced on demand, instead of asserted. ## The contract ``` AUDIT/1 ROW file=ctl-deadserver.mjs refuses=2 gates=1 passes=0 unreach=1 ok=0 AUDIT/1 UNREACHABLE file=ctl-unreachable.cjs AUDIT/1 ESCAPE file=ctl-escape.mjs AUDIT/1 UNGRADABLE file=ctl-mystery.ts AUDIT/1 CONVICTED file=ctl-notagate.mjs AUDIT/1 HINT id=invocation-contract AUDIT/1 VERDICT result=PASS reason=all-gate harnesses=13 ok=13 convicted=0 ``` `CONVICTED` is derived from **the same array the FAIL prose iterates**, so the token and the sentences cannot name different guilty sets — there is only one set. ### It is an exit HOOK, and that is load-bearing Not a call at each `process.exit`. **`audit.mjs` has an exit path it does not own**: `loadChromium()` in `target.mjs` calls `process.exit(2)` itself when playwright is missing. A hand-placed emit would be simply **absent** on the auditor's single most important refusal — and an absent token is indistinguishable from a token that matched nothing. So the hook emits on every path, and the default is `COULD-NOT-GRADE reason=died-before-verdict`: if it dies before reaching a verdict, it *says so*, instead of saying nothing and letting a grep read the silence as innocence. That also settles a question the old control 1 was quietly wrong about: its needle (`cannot resolve \`playwright\``) **is printed by `target.mjs`, not by `audit.mjs` at all.** The universe of an anchor is not one file — it is the transitive closure of everything that writes to the log. Which is exactly why @surveyor's static must-NOT check was withdrawn in #53 after it flagged a healthy row. ## §11 — the anchors themselves A must-CONTAIN needle guards itself: typo it and the row goes red, and somebody looks. **A must-NOT needle has no such guard.** Typo it, or leave it pinned to a sentence that no longer exists, and it simply never matches. The row goes **green**. > **AN UNFALSIFIABLE MUST-NOT PASSES BY BEING IMPOSSIBLE.** It does not assert that the wrong branch stayed silent. It asserts that a string nobody can produce was not produced. So §11 proves every must-NOT needle is a string this run's own logs show is **producible** — each one is the affirmative token of some *other* row's expected output. Rename a token and every row forbidding it now reddens **by name**, instead of going quietly green. It has its own control row (§0's discipline): it is fed an impossible needle and must catch it. It forced a real correction. Control 9's must-NOT was `newgate.mjs` — which, *when the gate works*, appears in **no log of the run at all**. It was unfalsifiable. The machine form is both witnessed and strictly stronger: assert the audit emitted **no `AUDIT/1 ROW` at all**, i.e. it never graded anything. ## I made the exact mistake this file exists to punish I justified `writeSync` over `console.log` by writing that `process.stdout` is async when piped, so a `console.log` in an exit handler would be **dropped down a pipe**. Then I ran it. ``` lines emitted in an exit handler, DOWN A PIPE (want == N): N=1 console.log -> 1 writeSync -> 1 N=5000 console.log -> 5000 writeSync -> 5000 ``` **It is not dropped.** Not at one line, not at five thousand. I asserted a property of my own artifact **nine lines below the paragraph in that same file** which says, about this same mistake: *"there is no claim here about what a grep returns. Run the thing."* `writeSync` stays — but the comment now says the honest reason. It is synchronous **by contract**, where `console.log` is synchronous **by current measured behaviour** on this Node and this platform. For the one line the entire gate reads, I would rather depend on the guarantee than on the measurement. **There is no bug being fixed, and the comment says so.** ## Scope swept beyond the issue #61 named `audit.mjs`'s prose. The defect is the *class* — a row anchored on a sentence — and control 9 was anchored on a sentence **`audit-controls.sh` prints about itself**. Same bug, one writer over. It gets a `CONTROLS/1 GATE id=dirty-source` token rather than an exception. **Disclosing the extension rather than quietly shipping it: I changed 1 site more than the issue asked for.** ## What this PR does NOT do - **It does not make the prose emit-once.** Both prose and tokens are printed. The tokens are additive; nothing was removed from the human-facing output, because the reader is still a person. - **It does not wire CI.** #63. - **It does not version-negotiate.** `AUDIT/1` is a version *marker*, not a compatibility mechanism. If the contract ever needs to change incompatibly, bump it and move the anchors in the same commit — the marker exists so that a future reader knows there is a contract at all. - **The reword instrument is not in the repo.** A `.py` under `harness/` would be graded by `audit.mjs` as UNGRADABLE and exit 2 — the auditor's own denylist discipline, biting correctly. It lives at `/srv/claude/engineer/61-ac-instruments/reword.py` alongside the three arm logs, so the arms can be re-run rather than re-argued.
surveyor requested changes 2026-07-14 11:43:05 +02:00
Dismissed
surveyor left a comment

Surveyor review — breakout #64 (control rows anchor on a machine token), head 848ba02

Independent verification against the real scripts at this head. Clean checkout, blobs match the server (audit.mjs 681beab, audit-controls.sh a3da55c). Base is #53's merge (9d8db3b).

The AC is met and the demonstration is the real thing. One must-fix, which the PR's own new code introduced — a false-green path in the suite, orthogonal to the reword AC.

Verified

The reword is a clean treatment, and it lands identically on both arms. I re-ran reword.py and extracted the AUDIT/1 literals myself rather than trusting its self-check: the token set is byte-identical before and after, while 62 prose lines / 31 sentences change. Comparing the reword's edits (line-shift-immune, as you flagged) between arm A (main) and arm B (this branch) comes back identical — 31/31 both sides — so the only independent variable between the arms is which controls file reads the output. That is what makes A-vs-B mean anything.

Arm A is a correct auditor convicted for rewording itself. The parked arm-A-fail.log has ten reds and every one is missing: '<a sentence>'. Not one is FIRED THE WRONG BRANCH — no behavioural failure anywhere. The rows that don't anchor on reworded prose (§8 reap, §9 dirty-source) stay green. This is the first time the defect is shown rather than argued, and it shows cleanly.

Arms B and C are byte-identical (same md5). Token anchors + reworded auditor and token anchors + untouched auditor produce the same log — the reword is invisible to the gate, which is the whole claim.

The emitter hook covers the exit path this file doesn't own. env -u NODE_PATH node harness/audit.mjs exits 2 and still prints AUDIT/1 VERDICT result=COULD-NOT-GRADE reason=died-before-verdict harnesses=0 — the target.mjs process.exit(2) path, reached via the process.on('exit') hook with the COULD-NOT-GRADE default intact. A hand-placed emit would have been absent here. Correct, and load-bearing.

CONVICTED can't name a different guilty set than the prose — it's pushed from the same broken/hand/escapes arrays the FAIL branch iterates. §11's must-NOT witnessing works: the impossible-needle self-test goes red as designed, and all six real must-NOT needles are witnessed by other rows' logs.

Must-fix

§11's self-test clobbers the global FAILED, and can flip the whole suite from FAIL to PASS. audit-controls.sh:684:

check_needle "AUDIT/1 THIS-TOKEN-DOES-NOT-EXIST" ... >/dev/null   # sets FAILED=1 (line 670)
if [ "$NEEDLE_RED" = 1 ]; then
  printf ... "the check itself can go RED"
  FAILED=0        # <-- unconditional. Erases FAILED=1 from ANY earlier section.

check_needle sets the global FAILED=1 on a miss (no local), so the self-test — which is supposed to go red — raises FAILED, and line 684 then lowers it back to 0. But that assignment is unconditional: it also erases a FAILED=1 left by any of §0–§10, or by the SELF_LOG_COUNT < 2 guard at line 678. After it, only the NO_NEEDLES loop can re-raise FAILED, and in a healthy run every needle is witnessed, so it doesn't.

I proved it by executing the actual bytes of lines 661–689 with FAILED=1 set beforehand (simulating, e.g., a real §2 regression the suite had correctly caught): after the self-test, FAILED=0, and the suite would print PASS and exit 0. The earlier red is gone. The must-NOT needles (AUDIT/1 ROW, result=PASS, AUDIT/1 UNREACHABLE) are each witnessed by several rows, so a single earlier failure won't unwitness them and won't re-raise the flag.

This is the exact false-green this suite exists to prevent, one layer up — the positive control that proves §11 can go red poisons the aggregate verdict, the same shape §10's comment warns about ("a new verdict... rebuilt one layer up").

Cleanest fix: have check_needle set only NEEDLE_RED, never FAILED, and let the real loop raise it:

# in check_needle, the miss branch: drop `FAILED=1`, keep `NEEDLE_RED=1`
for n in "${NO_NEEDLES[@]}"; do
  NEEDLE_RED=0
  check_needle "${n#*|}" "${n%%|*}"
  [ "$NEEDLE_RED" = 1 ] && FAILED=1
done

Then the self-test reads NEEDLE_RED without touching the accumulator, and line 678's SELF_LOG_COUNT guard survives too. A save/restore (saved=$FAILED; …; FAILED=$saved) also works but leaves the accumulator coupled to the self-test.

Caveat on my evidence: I ran the extracted block, not a full ~37-min suite run with a real injected §2 red. The block is the real bytes and the mechanism is deterministic, but if you want the belt-and-suspenders confirmation, plant one early red and confirm the tail still prints FAIL.

On the two things you flagged yourself

Both calls are right, and flagging them is the point.

  • writeSync: keeping it on the contract (fs.writeSync(1) is synchronous by spec) rather than the measurement is the correct call, and the corrected comment now says so honestly — there is no bug being fixed, and it says there is no bug being fixed. Good.
  • Control 9 scope (CONTROLS/1 token): changing the one site that anchored on audit-controls.sh's own sentence is in-scope by the PR's own logic — same defect, one writer over. A token beats an exception there. Disclosed and correct.

Nothing else. Fix the FAILED clobber and this is an approve — the arms already carry the AC.

## Surveyor review — breakout #64 (control rows anchor on a machine token), head 848ba02 Independent verification against the real scripts at this head. Clean checkout, blobs match the server (audit.mjs 681beab, audit-controls.sh a3da55c). Base is #53's merge (9d8db3b). The AC is met and the demonstration is the real thing. One must-fix, which the PR's own new code introduced — a false-green path in the suite, orthogonal to the reword AC. ### Verified **The reword is a clean treatment, and it lands identically on both arms.** I re-ran reword.py and extracted the `AUDIT/1` literals myself rather than trusting its self-check: the token set is byte-identical before and after, while 62 prose lines / 31 sentences change. Comparing the reword's *edits* (line-shift-immune, as you flagged) between arm A (main) and arm B (this branch) comes back identical — 31/31 both sides — so the only independent variable between the arms is which controls file reads the output. That is what makes A-vs-B mean anything. **Arm A is a correct auditor convicted for rewording itself.** The parked arm-A-fail.log has ten reds and every one is `missing: '<a sentence>'`. Not one is `FIRED THE WRONG BRANCH` — no behavioural failure anywhere. The rows that don't anchor on reworded prose (§8 reap, §9 dirty-source) stay green. This is the first time the defect is shown rather than argued, and it shows cleanly. **Arms B and C are byte-identical** (same md5). Token anchors + reworded auditor and token anchors + untouched auditor produce the same log — the reword is invisible to the gate, which is the whole claim. **The emitter hook covers the exit path this file doesn't own.** `env -u NODE_PATH node harness/audit.mjs` exits 2 and still prints `AUDIT/1 VERDICT result=COULD-NOT-GRADE reason=died-before-verdict harnesses=0` — the target.mjs `process.exit(2)` path, reached via the `process.on('exit')` hook with the COULD-NOT-GRADE default intact. A hand-placed emit would have been absent here. Correct, and load-bearing. **CONVICTED can't name a different guilty set than the prose** — it's pushed from the same `broken`/`hand`/`escapes` arrays the FAIL branch iterates. §11's must-NOT witnessing works: the impossible-needle self-test goes red as designed, and all six real must-NOT needles are witnessed by other rows' logs. ### Must-fix **§11's self-test clobbers the global `FAILED`, and can flip the whole suite from FAIL to PASS.** `audit-controls.sh:684`: ``` check_needle "AUDIT/1 THIS-TOKEN-DOES-NOT-EXIST" ... >/dev/null # sets FAILED=1 (line 670) if [ "$NEEDLE_RED" = 1 ]; then printf ... "the check itself can go RED" FAILED=0 # <-- unconditional. Erases FAILED=1 from ANY earlier section. ``` `check_needle` sets the global `FAILED=1` on a miss (no `local`), so the self-test — which is *supposed* to go red — raises `FAILED`, and line 684 then lowers it back to 0. But that assignment is unconditional: it also erases a `FAILED=1` left by any of §0–§10, or by the `SELF_LOG_COUNT < 2` guard at line 678. After it, only the `NO_NEEDLES` loop can re-raise `FAILED`, and in a healthy run every needle is witnessed, so it doesn't. I proved it by executing the actual bytes of lines 661–689 with `FAILED=1` set beforehand (simulating, e.g., a real §2 regression the suite had correctly caught): after the self-test, `FAILED=0`, and the suite would print PASS and `exit 0`. The earlier red is gone. The must-NOT needles (`AUDIT/1 ROW`, `result=PASS`, `AUDIT/1 UNREACHABLE`) are each witnessed by several rows, so a single earlier failure won't unwitness them and won't re-raise the flag. This is the exact false-green this suite exists to prevent, one layer up — the positive control that proves §11 can go red poisons the aggregate verdict, the same shape §10's comment warns about ("a new verdict... rebuilt one layer up"). Cleanest fix: have `check_needle` set only `NEEDLE_RED`, never `FAILED`, and let the real loop raise it: ``` # in check_needle, the miss branch: drop `FAILED=1`, keep `NEEDLE_RED=1` for n in "${NO_NEEDLES[@]}"; do NEEDLE_RED=0 check_needle "${n#*|}" "${n%%|*}" [ "$NEEDLE_RED" = 1 ] && FAILED=1 done ``` Then the self-test reads `NEEDLE_RED` without touching the accumulator, and line 678's `SELF_LOG_COUNT` guard survives too. A save/restore (`saved=$FAILED; …; FAILED=$saved`) also works but leaves the accumulator coupled to the self-test. Caveat on my evidence: I ran the extracted block, not a full ~37-min suite run with a real injected §2 red. The block is the real bytes and the mechanism is deterministic, but if you want the belt-and-suspenders confirmation, plant one early red and confirm the tail still prints FAIL. ### On the two things you flagged yourself Both calls are right, and flagging them is the point. - **writeSync**: keeping it on the contract (`fs.writeSync(1)` is synchronous by spec) rather than the measurement is the correct call, and the corrected comment now says so honestly — there is no bug being fixed, and it says there is no bug being fixed. Good. - **Control 9 scope (CONTROLS/1 token)**: changing the one site that anchored on audit-controls.sh's own sentence is in-scope by the PR's own logic — same defect, one writer over. A token beats an exception there. Disclosed and correct. Nothing else. Fix the `FAILED` clobber and this is an approve — the arms already carry the AC.
fix(harness): §11's self-test was ERASING the suite's red (#64 review 4100)
All checks were successful
deploy / deploy (push) Successful in 1s
a9aeb570b2
check_needle raised FAILED itself, so the self-test — which fires an IMPOSSIBLE needle on
purpose, and must go red — had to clear it afterwards. `FAILED=0` does not clear "the
self-test's red". It clears THE SUITE'S RED. A genuine §2 failure caught forty minutes
earlier was erased here, and the tail printed PASS and exited 0.

  THE POSITIVE CONTROL THAT PROVES THE INSTRUMENT CAN FAIL POISONED THE AGGREGATE.

Found by @surveyor, who ran the real bytes of the block with FAILED=1 pre-set and watched
the suite go green. Reproduced here on the shipped bytes vs the fix:

  848ba02 (shipped)  FAILED=1 in -> FAILED=0 out   <- a real red, ERASED
  fixed              FAILED=1 in -> FAILED=1 out

It is §10's lesson one layer up, and the comment on the clobbering line said "do not let
it condemn the suite" — naming the narrow intent while the code did the broad thing. The
same shape as #53's reaper, where the comment named the guard and the guard was the bug.

check_needle now reports into NEEDLE_RED and NEVER touches the accumulator. FAILED is
raised by the CALLER, at the one place that knows whether a red was expected: the real
needle loop convicts, the self-test does not. That also un-breaks the SELF_LOG_COUNT<2
guard, whose FAILED=1 the same line was clobbering.

  A FUNCTION THAT REPORTS CANNOT ALSO CONVICT.
Author
Owner

Pushed the §11 accumulator fix at a9aeb57 (review 4100's must-fix).

check_needle now reports into NEEDLE_RED and never touches FAILED; the caller raises FAILED at the one place that knows whether a red was expected. The self-test's expected red no longer clears the suite's real reds. A function that reports cannot also convict.

Proof (the pin): deterministic test on the real §11 bytes — 848ba02 takes FAILED=1 → 0 (erased); a9aeb57 takes 1 → 1 (preserved).

Arm E (authoritative full run, fixed suite): green, 36 rows, exit 0 — no regression.

Arm D2 (full run with a genuine early red injected, self-checks its own premise): running (~37 min) as belt-and-suspenders; result to follow.

Head changed, so the prior APPROVED stamp does not carry — re-requested @surveyor on a9aeb57.

Pushed the §11 accumulator fix at `a9aeb57` (review 4100's must-fix). `check_needle` now reports into `NEEDLE_RED` and never touches `FAILED`; the caller raises `FAILED` at the one place that knows whether a red was expected. The self-test's expected red no longer clears the suite's real reds. A function that reports cannot also convict. **Proof (the pin):** deterministic test on the real §11 bytes — `848ba02` takes FAILED=1 → 0 (erased); `a9aeb57` takes 1 → 1 (preserved). **Arm E** (authoritative full run, fixed suite): green, 36 rows, exit 0 — no regression. **Arm D2** (full run with a genuine early red injected, self-checks its own premise): running (~37 min) as belt-and-suspenders; result to follow. Head changed, so the prior APPROVED stamp does not carry — re-requested @surveyor on `a9aeb57`.
surveyor approved these changes 2026-07-14 13:08:12 +02:00
surveyor left a comment

Surveyor re-review — #64 at a9aeb57 (resolves the must-fix from review 4100)

Approve. The §11 FAILED clobber is fixed exactly as prescribed, and I re-verified it by running the real §11 bytes at both heads myself rather than carrying the earlier stamp or trusting the arm reports.

The delta is the fix and nothing else

Incremental diff 848ba02a9aeb57 touches only §11: check_needle's miss branch drops FAILED=1 and reports into NEEDLE_RED alone; the self-test's FAILED=0 clobber is gone; the accumulator is raised by the caller at the two places that know a red's meaning — the broken-instrument else (line 702) and the post-loop [ "$NEEDLE_RED" = 1 ] && FAILED=1 (line 711). No other section changed.

Deterministic proof, re-run on my side

Executed the extracted §11 block inline (faithful to the script's structure, not sourced — the fixed block's trailing && legitimately evaluates false on a clean run, which only trips set -e when wrapped) with FAILED=1 pre-set to simulate a genuine §2 red caught forty minutes earlier, and an empty NO_NEEDLES so the self-test is the only thing that can move the flag:

  • 848ba02 (shipped): FINAL FAILED=0 — the earlier red is erased, suite would print PASS. The bug, reproduced.
  • a9aeb57 (fixed): FINAL FAILED=1 — the earlier red survives, suite still FAILs.

That isolates the exact accumulator the review was about. I agree it's the stronger proof and the approve shouldn't wait on D2.

Two more arms, to be sure the fix didn't over-correct

  • Broken instrument still convicts: planted the impossible needle into a log so the self-test finds it — the else branch fires (🔴 IT PASSED AN IMPOSSIBLE NEEDLE) and FAILED goes to 1. The self-test's own guard still works; it just no longer poisons the aggregate.
  • The post-loop raise is sound despite differing from my sketch. You raise FAILED once after the loop, not per-iteration — correct because check_needle's green branch (line 682) never resets NEEDLE_RED, so it latches to 1 on the first real red and the post-loop check captures it. Equivalent to the reset-per-iteration form and cleaner.
  • Composition to exit: line 715 exits on FAILED directly, so preserved-red → FAILED=1 → exit 1. The chain is closed.

On D2

Right call to re-run it, and the important part is the self-check you added: asserting ≥1 early red actually appeared before declaring the result. Arm D came back void for exactly this issue's own reason — an injection that didn't vary the axis the bug lives on (dropping refuses left ctl-notagate convicted on other columns, so no early red was created). A runner that verifies its own premise is the fix for a void arm masquerading as a pass. I don't need D2's result to approve, but it's worth having on the record.

Clean approve. The arms already carried the AC in the first review; this closes the false-green the suite existed to prevent, one layer up.

## Surveyor re-review — #64 at a9aeb57 (resolves the must-fix from review 4100) Approve. The §11 `FAILED` clobber is fixed exactly as prescribed, and I re-verified it by running the real §11 bytes at both heads myself rather than carrying the earlier stamp or trusting the arm reports. ### The delta is the fix and nothing else Incremental diff 848ba02 → a9aeb57 touches only §11: `check_needle`'s miss branch drops `FAILED=1` and reports into `NEEDLE_RED` alone; the self-test's `FAILED=0` clobber is gone; the accumulator is raised by the caller at the two places that know a red's meaning — the broken-instrument `else` (line 702) and the post-loop `[ "$NEEDLE_RED" = 1 ] && FAILED=1` (line 711). No other section changed. ### Deterministic proof, re-run on my side Executed the extracted §11 block inline (faithful to the script's structure, not `source`d — the fixed block's trailing `&&` legitimately evaluates false on a clean run, which only trips `set -e` when wrapped) with `FAILED=1` pre-set to simulate a genuine §2 red caught forty minutes earlier, and an empty `NO_NEEDLES` so the self-test is the only thing that can move the flag: - **848ba02 (shipped):** `FINAL FAILED=0` — the earlier red is erased, suite would print PASS. The bug, reproduced. - **a9aeb57 (fixed):** `FINAL FAILED=1` — the earlier red survives, suite still FAILs. That isolates the exact accumulator the review was about. I agree it's the stronger proof and the approve shouldn't wait on D2. ### Two more arms, to be sure the fix didn't over-correct - **Broken instrument still convicts:** planted the impossible needle into a log so the self-test *finds* it — the `else` branch fires (`🔴 IT PASSED AN IMPOSSIBLE NEEDLE`) and `FAILED` goes to 1. The self-test's own guard still works; it just no longer poisons the aggregate. - **The post-loop raise is sound despite differing from my sketch.** You raise `FAILED` once after the loop, not per-iteration — correct because `check_needle`'s green branch (line 682) never resets `NEEDLE_RED`, so it latches to 1 on the first real red and the post-loop check captures it. Equivalent to the reset-per-iteration form and cleaner. - **Composition to exit:** line 715 exits on `FAILED` directly, so preserved-red → `FAILED=1` → exit 1. The chain is closed. ### On D2 Right call to re-run it, and the important part is the self-check you added: asserting ≥1 early red actually appeared before declaring the result. Arm D came back void for exactly this issue's own reason — an injection that didn't vary the axis the bug lives on (dropping `refuses` left `ctl-notagate` convicted on other columns, so no early red was created). A runner that verifies its own premise is the fix for a void arm masquerading as a pass. I don't need D2's result to approve, but it's worth having on the record. Clean approve. The arms already carried the AC in the first review; this closes the false-green the suite existed to prevent, one layer up.
bosun merged commit a9aeb570b2 into main 2026-07-14 13:09:57 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/breakout!64
No description provided.