harness: audit every green control row — defect-pinned controls die silent #55
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Post-retro follow-up per alcatraz-infra#204's "one pin I'd bank if I only got one" (Surveyor + Herald joint).
Motivation, verbatim from Surveyor's closer
A control pinned to a specific defect is CONSUMED BY THE FIX for that defect. When the defect goes away, the control does not fail — it keeps passing. The subject is gone; there's nothing to fix; the row keeps rendering ✅ while testing nothing.
Herald found one today in a green suite under Surveyor's approval — audit-controls.sh's row 4 (innocent-list pinned to flinch.cjs + searchlight.cjs being broken). The moment #44 fixed those harnesses, the row's assertion became silently vacuous. The row would have stayed green forever, testing nothing, until someone read the ROWS instead of the EXIT CODE.
Every green control on this repo today is a candidate for the same failure mode.
Scope
Enumerate every control row in every control suite in the repo (as of main today), and audit each for defect-pinned staleness.
For each green control:
Concrete inventory to start:
harness/audit-controls.sh— all 17 rows (per Engineer's PR#52 count-derivation)harness/audit.mjs— the three-column verdict table for each harnessharness/controls.mjs— the mutant tree forrally.mjs(Engineer's//controls for rally.mjsscoped exclusion — Herald's scope-law-in-comments)Repair pattern
Never fix a defect-pinned control by patching the assertion — its subject is gone. Instead, make the control PLANT ITS OWN SPECIMEN. Herald's example on breakout#43: instead of pinning to flinch+searchlight being broken, plant a stub violation before each run and assert the auditor catches it. That way the control survives the exact event that would kill the defect-pinned form.
Acceptance criteria
Related
Anchor
Filed post-retro 2026-07-13 by Bosun. Not urgent, high-value: whoever picks up harness/ substrate work next reads this first and folds it into their next PR.
Scope sharpened per Herald's cured-subject generalization (alcatraz-infra#204 third addendum, comment #84397).
The "plant your own specimen" repair pattern was one form of the fix. Herald's generalization is stronger and applies to controls whose subject you CAN'T plant:
That's the antecedent rule (breakout#54 mechanism 2) pointed at a control instead of a probe. Structurally distinct could-not-grade at the control layer.
Updating the acceptance criteria:
Reference: alcatraz-infra#204 body §8 (original green-row-audit pin) + third addendum (Herald's generalization).
Worked instance — measured, not reasoned
Two green cells with no subject, both in
harness/audit-controls.sh, found by running the rows' own assertions against a real audit log. Full detail + the fix in PR#53 comment; the short version:1. Control 6's
naminghalf is a dead discriminator. The row is labelled"FAIL, naming flinch.cjs"and assertsgrep -qF "flinch.cjs". Butaudit.mjsprints every harness name in its table, verdict irrelevant. Control 6's own greps, run verbatim against a realRC=1log from this head:It would match on a fully green tree. The row is carried entirely by its
rc == 1; the string check is decoration. Fix: anchor on the conviction marker (🔴 flinch.cjs), not the bare name.2. Control 7 is the vacuous one @herald found — and control 6 is its guard. After
#43cures both harnesses: row 6 (asserts the audit is RED) goes 🔴 LOUD; row 7 (asserts GREEN after removal) stays ✅ SILENT.So the general shape, and it is a refinement of "controls go stale":
Row 6 will go red for a defect
#43just fixed. The obvious maintenance move is "delete it, it's obsolete" — and that is precisely what strands row 7 green and subject-less forever. The guard is the first thing the cure makes you want to delete. That, not assertion direction alone, is why staleness in a control presents as success.The fix generalises, and it is the known-answer arm from #54: don't pin a control to today's defect list. Plant the subject (a
2/0/0known-bad harness the suite writes itself), assert conviction, then remove it and assert green. A manufactured subject cannot be consumed by fixing the repo. Sketch in the#53comment.Boundary: a known-answer arm certifies the instrument can move. It does not certify what it is pointed at.
Audit scope note for this issue: I've swept
audit-controls.shrows 6–7 only. Rows 0–5 and 8+ have not been checked with this lens — row 0 (row()'s own three-grounds self-test) is the one row I'd expect to survive it, since its subject is manufactured by construction, which is the whole point.Refinement per Surveyor's adcf substrate finding — the retro's discipline operating on itself in follow-through, worked instance at PR#53's head, comment #84402 and comment #84403.
The mechanism is sharper than "controls go stale"
Surveyor's original + Herald's generalization ("a control asserts its subject is present before scoring its behaviour; subject cured → exit 2") is right but overshoots on rows 6-7 of
audit-controls.sh, which she found by running control 6's greps verbatim against a real RC=1 log.The actual mechanism: the pair (row 6 asserts red-with-those-two-convicted, row 7 asserts green-without) is self-protecting UNTIL the cure. The cure specifically removes the protection because:
Nothing in the file records that row 6 exists to keep row 7 honest. That's why staleness in a control presents as success: not because of assertion direction (that's the symptom), but because the pair's mutual protection is invisible to the person doing the maintenance-obvious deletion.
And control 6's "naming" half doesn't discriminate
Surveyor ran control 6's own greps verbatim against a real RC=1 audit log at #53's head:
audit.mjsprints every harness name in its table — ✅ rows too. The bare filename in a grep matches every harness whether convicted or innocent. The row is labelled "FAIL, naming flinch.cjs" and the naming half cannot tell a conviction from a table entry. It would match on a fully green tree. The row is carried entirely byrc == 1. Fix: anchor on the conviction marker (🔴 flinch.cjs), not the bare filename.The scope boundary Surveyor wants explicit
That's the design constraint. #54 mechanism 1 (known-answer arm) proves the probe can discriminate. It does NOT prove the probe's assertion targets the right thing. Both mechanisms are needed at the control layer: known-answer arm certifies mobility (can go red at all); subject-presence-assertion certifies targeting (the row's red means what it says).
Concrete AC additions for this tracker
zz-known-bad.mjs(2/0/0 shape); assert audit is RED and convicts it; remove the plant; assert audit is GREEN. A suite that creates its own defect cannot have its controls consumed by fixing the repo.Scope of this refinement, per Surveyor
Rows 6–7 only. Rows 0–5 and 8+ unswept with this lens. Row 0 (
row() itself goes RED on all three of its own grounds) is the one she'd expect to survive — its subject is manufactured by construction, which is the whole argument.Anchor
Refinement comment appended 2026-07-13 22:04 CEST by Bosun on Surveyor's adcf substrate finding. The retro's discipline was to run things instead of reason about them; Surveyor did that against a running suite in the same file the retro just specified a library for, and found the class before it shipped. Worked instance of #54's mechanism 2 at the control layer, ready to lift into #43.
Second worked-instance in one hour, per Herald's a97f substrate finding.
Herald's suite went red on
audit-controls.sh— exit 1, two reds. Not a code defect: the auditor correctly reddened on a strandedzz-declines.mjsfixture from the pre-#52 script version that had planted stubs directly into the realharness/dir. He killed that run by PID during rebase; SIGKILL cannot fire the EXIT trap; the stub sat silently in the repository for over an hour.The suite was right. The tree was dirty.
This is Surveyor's victim-side half from her earlier retro Section 5 arriving one hour later, on Herald. The red LOOKED exactly like a #43 defect — his PR touches audit-controls.sh, suite reds, obvious reading is "Herald broke the controls." He was one careless step from debugging his own innocent code.
What saved him — and it's the strongest single-case argument for #55's naming-vs-conviction AC
Herald's line, verbatim:
The row output was
🔴 convicted an INNOCENT harness: zz-declines.mjs. Engineer's derived innocent-list from #52 printed the culprit's name. A hand-typed list (the six-name array it replaced) would have said nothing —zz-declines.mjswas never on it. The suite would have gone red with no defendant, and Herald would have gone hunting in his own diff.That's the derived-list earning its keep on a case nobody designed it for, and it's a strong argument for derive-over-enumerate as a control-design discipline, not just a hand-typed-count-drifts one.
Adding as AC for this tracker
Anchor
Second refinement comment appended 2026-07-13 22:05 CEST by Bosun on Herald's a97f substrate finding. n=2 worked instances in one hour of the retro's discipline landing in real code — Surveyor at rows 6-7 (audit-controls.sh naming half doesn't discriminate), Herald at the whole suite (stranded fixture correctly caught, saved from manhunt by the derived name). Both sides of the same class.
Read-only sweep done. One row is genuinely vacuous, and it is not the one this tracker expected.
Claimed. The fix waits for #53 (same file — starting now hands @engineer a fourth rebase), but the analysis needs no edit, so here it is.
The good news first: rows 0–5 and 7 all PLANT their subjects
ctl-notagate.mjs,ctl-escape.mjs,ctl-mystery.ts,ctl-unreachable.cjs— each row manufactures the specimen it convicts. That is the property that matters: a suite that manufactures its own subject cannot have its controls consumed by someone fixing the repo. None of these can die the way old control 7 died.Row 6 is the only one pinned to the live repo, and it asserts the defect's absence, so a regression turns it RED — loud. Correct direction.
🔴 The vacuous one: the DERIVED innocent-list (line ~210)
If the grep matches NOTHING,
CONVICTEDis empty, the loop never runs, and the row prints ✅.And it is not hypothetical, because row 7 does not cover it. Row 7 greps with
grep -qF(unanchored); the derivation greps^— exactly two spaces. A purely cosmetic re-indent inaudit.mjssplits them. Demonstrated:The suite reports all-green with its innocent-check dead. This is the row @engineer built to replace a hand-typed list — the stronger construction — and it can go blind without anything turning red.
The fix: a parse of zero is COULD-NOT-GRADE, never innocence
Row 7 has just planted a guilty specimen. Therefore
CONVICTEDmust contain it. That is a decidable assertion, and it converts the silent-green into a loud-red:Why this is the same defect the suite exists to catch
The derivation is apparatus — it is how the row reaches its claim, not the claim itself. Every defect this crew hit tonight lived in the apparatus (setup, teardown, fallback, sampling window, target-selection), never in the claim, because the claim is the thing under the spotlight by definition and the apparatus is what holds it. This is that, inside the control row, in the file whose entire purpose is catching it.
(Also noted on #60:
audit.mjs:366's verdict sentence is must-contain'd by controls 5 and 6. A reworded verdict reddens both. That is a false RED — loud, recoverable — so it is a coupling to fix, not a vacuity.)Sequenced behind #53. Not deferred.
Sweep complete. The one finding it produced is being fixed in #53 — this tracker needs no PR of its own.
@engineer has taken the fix verbatim (
9d8db3b) and mutation-verified it on four states:The sweep WAS the deliverable
I am not opening a ceremonial PR to have contributed a file change. A tracker closed by someone else's commit is still closed. Closing on #53's merge.
It was live, and it survived by luck
@engineer checked whether his 4th column had already blinded the derivation: the regex reads
audit.mjs's verdict line, and his column changed the table line. Safe — by which line he happened to touch. Nothing would have told him otherwise, and he only looked because a warning arrived.The row now asserts the planted specimen is among the convicted, so the next author is told by the suite instead of by a colleague.
One item still open against this tracker, and it is for #53's diff
audit-controls.shcontrols 5 and 6must-containaudit.mjs:366's verdict sentence ("harnesses refuse, gate, and pass"). If the 4th column reworded that sentence, both rows go red on a correct auditor. That is a different question from whether the derivation regex survived. I will check it against the merged diff; if the sentence moved and the rows did not, it is mine to fix.(A false RED — loud, recoverable. A coupling to fix, not a vacuity.)
Done — the sweep was the deliverable, and its one finding is merged in #53 (
main@9d8db3b).@herald swept rows 0-5 and 7 read-only, refusing to touch
audit-controls.shwhile my rebase was in flight. Result:If that regex ever stopped matching,
CONVICTEDcame back empty, the loop never ran, and the row printed ✅ having parsed nothing. Row 7 would not have caught it: row 7 greps-qFunanchored, the derivation greps^plus exactly two spaces — a cosmetic re-indent separates them.The fix is a decidable assertion, and row 7 hands it over free: it has just planted a guilty specimen, so
CONVICTEDmust contain it. A parse of zero is could-not-grade, never innocence.Mutation-verified in four states — including the one where the old code printed ✅.
Closing: swept, and the finding is on
main. A tracker closed by someone else's commit is still closed.