Files
troupe-standup/recoveries/helm-pill-ground-truth.md
Merlin 420c826382 G13 (Helm lane): the pin pill against ground truth -- G10's predicate had no
fresh cell, and no gate asked whether the pill was true

Two findings, measured on six reachable cells of the pill x qualifier pair
(q63/make_cells.py -> R34-CELLS.json), five of them real renders of the real
renderers on the real snapshot and one constructed and labelled as such:

1. G10's predicate (helm-selftest-q62.py:2782) demands both "not re-checked
   since" and "as of ", but helm-render-plain.py:329 appends the disclaimer only
   when site_fresh != "FRESH" -- so the honest fresh generation is refused and
   the end state of G10's own prescribed remedy (re-collect -> re-render ->
   deploy) is red exactly like today's unfixed page. A red that cannot tell a
   fixed page from a broken one is not a remediation signal. The pair is the
   evidence: base gate with the fresh cell as its subject 187/1 with G10's row
   FAIL (control-q62-freshcell.py, c05dd15f), new gate on the same body same
   repoint 190/1 with G10's row PASS (twinD, ef9980cc). The fix splits the
   predicate into its two halves and reads freshness from the age the page's
   own qualifier states, against the collector's own 3600 s threshold.

2. No gate asked whether the pill was TRUE, and G11 does not close it: the
   fresh cells carry an unqualified green "match" beside a fresh-looking clock
   from BOTH the production renderer and the G11-patched one, while a fresh
   fetch of the snapshot's own URL returns HTTP 200 / 217,163 B /
   c34ae2c245117ca7 against a held pin of f27326e8b13d1dec -- so
   pin_matches_live_now is false. G13 is the guard: offline, the pill's colour
   must agree with the held pin against the live-body hash the page publishes;
   live, a fresh fetch must confirm an unqualified green pill (red today, and
   that red is the finding); plus a read-only row. Row 2 subsumes G12 on one
   cell and adds three G12 cannot see -- stated in the record, not left for a
   reader to find.

Gate: base 4b18329c (171,979 B / 3,256 lines / 138 registrations) -> shipped
helm-selftest-q63.py 180,772 B / 3,432 lines / 141 registrations /
94f9b3625e5791a724afe479315f5a49d3244c5e183cad8001ec6185e1c3f240
(+8,793 B / +176 lines / +3 registrations); four twins and one control each one
to three asserted lines different. Subject 4e45021d80395d3f / 29,954 B
throughout. Matrix, prediction stated before the run and met exactly: shipped
189/2 twice, twinA 188/3, twinB 190/1, twinD 190/1, control 187/1, and twinC
rc 0 / 191/0 / ALL GATES PASS -- the honest remediated state, the only
configuration this gate has ever been able to pass, which gives the remediation
an acceptance criterion it did not have before.

Live delta 0 across all seven legs: page 9,865 B / 427b7b54c69b18d2, snapshot
14,039 B / aa842b0fd88037f8, held pin 120 B / 5b6d70716153c3f4; deployed bin
untouched and grep -c HELM_COLLECTOR = 0 so Q40 stands; sandboxes 0/0; disk
41 G free of 154. Nothing deployed, no another-party file edited, decisions/
and inbox/ untouched, no secret printed. Adoption is now four files in one
order: renderer 306d4bee -> collector 4e45021d + gate 94f9b362 -> re-collect ->
re-render -> deploy, with the re-collect load-bearing because G13's live row
stays red until a collect recomputes manifest_match against the live body.

Four defects of mine logged first in the record's section 8: the first probe
fetched the portfolio instead of the pin's subject; the first normaliser missed
this host's TMPDIR-based mkdtemp; the first G13 block referenced four names it
had not imported; and twinC's third repoint silently did not apply until an
assertion caught it. No queue item opened. Merlin <merlin@agents.invalid>.
2026-10-15 03:54:10 +00:00

14 KiB
Raw Permalink Blame History

The pin pill against ground truth — Run 34

Deliverable: this file. Scratch tree: /root/crucible/q63/. Nothing deployed: no cp into /root/.helm/bin/, no --deploy, no write to the live document root. decisions/ and inbox/ untouched, no another-party file edited, no secret printed. No queue item opened — the Helm executable set was empty at the start of this run by both this lane's and the pipe's measurement, so the unit taken is the residual G12's own record named and left open: "no fuzzer, the enumerated render set only."

Grade: measured, not claimed. Every figure below came from a command in this run; the instruments are named with their artifacts. Where a figure is a dated reading it says so.


1. The premise, measured before anything was built

/root/crucible/q63/make_cells.py → R34-CELLS.json. Six reachable cells of the pin-pill × qualifier pair, five of them real renders of the real renderers on the real snapshot and one a constructed fixture, labelled as one (§6):

cell bytes sha256 pill as of not re-checked G10 G12 G13r1
plain x stale 11,806 3f48643d8e7bac77… #22c55e match 1 1 PASS FAIL PASS
plain x fresh 11,624 1eec213e9e363d36… #22c55e match 1 0 FAIL PASS PASS
g11 x stale 11,819 951a8a7645fe7ef4… #f59e0b match (unverified) 1 1 PASS PASS PASS
g11 x fresh 11,624 1eec213e9e363d36… #22c55e match 1 0 FAIL PASS PASS
deployed page 9,865 427b7b54c69b18d2… #22c55e match 0 0 FAIL PASS PASS
drift x fresh (constructed) 11,624 c199045d43ee4006… #ef4444 drift 1 0 FAIL PASS PASS

Ground truth, measured in the same run (final_r34.py → out/R34-FINAL.json, generated_at 2026-10-15T03:50:56+00:00):

  • held pin /root/.helm/data/held/stackchain-home.html.sha256, 120 B / sha256 5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297, content f27326e8b13d1dec9eb158fe40e5091f79dcaf73b47312c4e7d3958ba1d95d18 stackchain-home.html pinned 2026-10-08T16:58:07.100Z
  • the snapshot's stackchain_site: manifest_match: true, live_body_sha256: f27326e8b13d1dec…, observed_at 2026-10-08T17:12:59.458Z, url https://www.stackchainmagazine.net/
  • a fresh fetch of that URL: HTTP 200 / 217,163 B / sha256 c34ae2c245117ca73ba5720b2c22b6fab689840070ff68cda7bffe3e723986d4, so pin_matches_live_now is false — measured, and byte-identical to every reading the pipe and this lane took on 2026-10-14.

Defect of mine, logged first: the first version of probe_r34.py hardcoded https://alexanderwhitestone.com/ — the portfolio, a different artifact from the pin's subject — and read 13,016 B / b6bae048a2f6bf19…, which would have made pin_matches_live_now: false true for the wrong reason. The URL is now read from the snapshot's own stackchain_site.url; the comparison is in refetch_r34.py. Nothing published before that correction.


2. Finding 1 — G10's predicate has no cell for the honest fresh state

helm-selftest-q62.py:2782 demands both "not re-checked since" and "as of ". The honest FRESH generation omits the disclaimer by construction: helm-render-plain.py:329 appends " · not re-checked since" only when site_fresh != "FRESH". So cells 2 and 4 — the real renderers at a fresh clock — are refused, and the end state of G10's own prescribed remedy (re-collect → re-render → deploy) is red exactly like today's unfixed page. A red that cannot tell a fixed page from a broken one is not a remediation signal.

Measured, and the pair is the evidence (run_matrix_r34.py):

config G10's deployed row
control-q62-freshcell.py — the base gate, subject repointed at the fresh cell FAIL (187/1)
helm-selftest-q63-twinD.py — the new gate, same body, same repoint PASS (190/1, its one failure is G13's live row)

Same body, same repoint, one difference: the predicate.

The fix. The predicate is two halves, the second conditional: the cell states the clock behind its claim, and says "not re-checked since" exactly when the reading behind it is stale. Freshness is read from the age the page's own qualifier states, parsed against the same 3600 s threshold the collector uses (hc.PER_METRIC_STALENESS_S["stackchain_site.http_status"]), so the gate cannot be argued into accepting a page by changing a clock it does not read.


3. Finding 2 — no gate checked the pill against the pin, and G11 does not close it

G10 owns the missing clock. G12 owns the incoherent pair. Neither asks whether the pill is true. Cells 2 and 4 carry an unqualified green match beside a fresh-looking clock, emitted by both the production renderer and the G11-patched one, while the held pin does not match the live body a fresh fetch returns. G12's predicate pairs the pill only with the disclaimer, so a green pill with a fresh-looking clock passes it.

The mechanism, read in the source rather than inferred: the pill's colour and label come from the frozen manifest_match field (helm-render-plain.py:323, :326) while the qualifier is computed at render time (:327–:330), and site_fresh is derived from the render clock — which --as-of supplies. So a clock can launder a six-day-old reading into a live-looking claim, and nothing read the claim against the pin.

The fix — G13, three rows:

  1. offline — the pill's colour must agree with the held pin compared against the live-body hash the page itself publishes. Catches a collector that freezes a claim contradicting the two hashes it printed. Green on all six cells today (the published hash is the pin), so this is a real check that is currently satisfied, not a vacuous one.
  2. live — a fresh fetch of the snapshot's own URL must confirm an unqualified green pill. Red today, and that red is the finding: the deployed page claims a match a fresh fetch refutes. If the fetch cannot be made the row is red with the reason named — a green claim that cannot be checked is not a claim a gate may pass. That is Q35's trade, taken knowingly and stated rather than buried.
  3. read-only — G13 reads the deployed page and writes nothing.

Overlap stated, not hidden: row 2 subsumes G12 on cell 1 — both refuse it — and adds cells 2, 4 and 5, which G12 cannot see. G12 stays load-bearing as the offline half, because row 2 needs the network.


4. The gate

Base ../q62/helm-selftest-q62.py 171,979 B / 3,256 lines / 138 check(" registrations / sha256 4b18329c7437bec4c5c05be86ddd8376a7396eda9c97739410b1ab5952e4d270.

file bytes lines regs sha256
helm-selftest-q63.py (shipped) 180,772 3,432 141 94f9b3625e5791a724afe479315f5a49d3244c5e183cad8001ec6185e1c3f240
helm-selftest-q63-twinA.py 180,768 3,432 141 f5452b17ef136c65d1eca759d781624dcd7e171d73c82cd389b1d533d0eaad71
helm-selftest-q63-twinB.py 180,766 3,432 141 041a5766251a6eabb467eb066ade4cb48b26c8ab873a661efb0259e91b6931e3
helm-selftest-q63-twinC.py 180,760 3,432 141 a7a5bb1b5f3c82d1f08862055dce4da8eb8c0d01868e10c81d6e2c63e4f8d53b
helm-selftest-q63-twinD.py 180,768 3,432 141 ef9980ccd7fe1ee529068333bdd9a708affa1cdc75a139e8269c252a54ac5ed8
control-q62-freshcell.py 171,975 3,256 138 c05dd15fac35734e5082734f834440859ccda1399b20137edfddef38d9569b74

+8,793 B / +176 lines / +3 registrations on the base; every twin is one, two or three asserted lines different from the shipped gate, each printed by build_g13.py (twinA L3107, twinB L3274, twinC L2764+L3107+L3274, twinD L2764, control L2764 on the base). Subject collector throughout: HELM_COLLECTOR=/root/crucible/q48/helm-collect.py, 29,954 B / 4e45021d80395d3f03fc58… (asserted by digest before the run).


5. The matrix — prediction stated before the run, met exactly

run_matrix_r34.py → out/R34-GATE.json (21,662 B, generated_at in the artifact), seven configurations, live census around each:

config rc passed / failed the failures
shipped 1 189 / 2 G10 deployed row; G13 live row
shipped-again 1 189 / 2 the same two — byte-identical after normalisation
twinA (G12 subject = plain-stale) 1 188 / 3 the same two + G12 row 1
twinB (G13 subject = g11-stale) 1 190 / 1 G10 deployed row only — G13's rows green on the honest remediated body
twinC (all three subjects = drift-fresh) 0 191 / 0 ALL GATES PASS
twinD (G10 subject = plain-fresh) 1 190 / 1 G13 live row only
control (base gate, old predicate, same body as twinD) 1 187 / 1 G10 deployed row

Two results carry the run:

  • twinC reaches ALL GATES PASS, and it is the only configuration that does. It is the honest remediated state — a fresh clock with a pill that is not claiming a match. The gate has never been able to go green; now it can, and only there. That is the remediation's acceptance criterion, which did not exist before this run.
  • twinD vs control isolates finding 1's fix and nothing else: same body, same repoint, old predicate red, new predicate green.

Determinism: the two shipped runs are byte-identical after normalising the four mkdtemp shapes, residual 0. Defect of mine, logged first: the first normaliser carried only the /tmp/tmp pattern, but this host's TMPDIR is /root/.hermes/profiles/merlin/cache/scratch, so mkdtemp(prefix="tmp") lands at scratch/tmpXXXXXXXX and exactly one line (the deploy leg's render destination) survived. The same blind spot Run 33 logged against its own normaliser, reproduced by its author on a fresh artifact; the raw stdouts are kept in out/R34-SHIPPED-{1,2}.txt so the residual can be read rather than asserted away.

Live state, delta 0 across all seven legs (out/R34-FINAL.json, 2026-10-15T03:50:56+00:00): deployed page 9,865 B / 427b7b54c69b18d2… / mtime_ns 1791709034017837233; snapshot 14,039 B / aa842b0fd88037f8… / 1791479579475780303; held pin 120 B / 5b6d70716153c3f4… / 1791478687099553071. Deployed /root/.helm/bin/ untouched — five files re-read (ee0b36a82f23… / 5c67473d8928… / 7ed1bca8f9da… / 12570786ba70… / 738699986778…) plus the __pycache__/ an adoption must not copy in — and grep -c HELM_COLLECTOR /root/.helm/bin/helm-selftest.py = 0, so Q40 stands and none of Q31–G13 is in production. Sandboxes 0/0 across /root/crucible. Disk 41 G free of 154 (74 %). ctime on the snapshot and the pin has moved to 1791957230760646867 / 1791957230761646950 (guard restores of earlier runs; disclosed, and it is why the run-wide instrument reads ctime as a restore trace rather than as proof of a write).


6. The one constructed cell, and the limits

drift-fresh.html is not a render of anything on disk. No snapshot the collector has written carries a frozen manifest_match of false — every one says true — so the honest remediated state cannot be rendered from the live data. It is produced by one boolean flip in a scratch copy of the renderer (q63/helm-render-drift.py, SNAPSHOT repointed at q63/snapshot-drift.json), which is Q45's redirect class applied to a fixture. It is labelled CONSTRUCTED everywhere it is cited, and twinC's result rests on it: the claim is that the gate can pass that body, not that the body exists in production.

Limits, stated as the item's first limits:

  • G13 detects and cannot repair. The remedy is still re-collect → re-render → deploy, an operator's call under §4 — but it now has an acceptance criterion (twinC's shape) and a gate that can see whether it landed.
  • Row 2 needs the network. Offline it is red with the reason named, which is the conservative direction and will read as noise on a disconnected host.
  • Row 1 is green on all six cells today, so it has never fired. It is a real check (it compares three published objects), not a demonstrated catch.
  • No fuzzer: the six cells are enumerated, not generated. The pair's space is small and reachable-by-construction, which is why enumeration is honest here, but it is still enumeration.
  • The pill's substance is still the collector's frozen field. G13 makes a false green visible; it does not make the field fresh.

7. Adoption — now four files in one order

The §4 cp is unchanged in kind and longer by one object. Order:

adopt renderer 306d4bee… (22,731 B) → adopt collector 4e45021d… (29,954 B) + gate 94f9b362… (180,772 B) → re-collect → re-render → deploy.

The gate supersedes 4b18329c… (this run's base, Run 33's) and 125754b270bf… (Q45S10+G10's). The re-collect step is now load-bearing rather than cosmetic: G13's live row stays red until a collect recomputes manifest_match against the live body, because the pin does not match it today. Deploying without re-collecting publishes a page this gate refuses.

Standing, unchanged and still human-gated: that cp; the stale manifest_match pin (measured false, twice, on two instruments); the Q13 publication call; Q9's checksum handover; Q19's onboarding. No queue item opened.


8. Defects of mine, logged first

  1. probe_r34.py fetched the wrong URL (§1) — caught by this run's own re-read, corrected before anything was recorded, comparison kept in refetch_r34.py.
  2. The first normaliser missed this host's TMPDIR-based mkdtemp (§5).
  3. The first G13 block referenced _g13_Path, _g13_sh, _g13_sys and _g13_tf without importing them; the gate died at line 3274 with a NameError on the first run. Caught by running it, not by reading it.
  4. build_g13.py's twinC was first derived from twinB, so its third repoint silently did not apply and the twin differed on two lines rather than the three it claimed. The assertion twinC.count("drift-fresh.html") == 3 now catches that class; the claim and the artifact agree.

— Merlin (Run 34), Helm lane