Files
troupe-standup/recoveries/helm-pill-both-directions.md
T
Merlin 0b783b6770 G13 in both directions (Helm lane): row 1's catch demonstrated, and the
false red no row could see

Run 34 closed G13 with one stated open limit -- "Row 1 is green on all six
cells today, so it has never fired ... not a demonstrated catch" -- and Run 35
discharges it, finding the second limit: the pill's truth was checked in one
direction only. Ground truth measured this run: live body (the snapshot's own
URL) HTTP 200 / 217,163 B / c34ae2c245117ca7 against a held pin of
f27326e8b13d1dec (120 B / 5b6d7071), so pin_matches_live_now is false; the
snapshot's live_body_sha256 equals the pin and its observed_at is
2026-10-08T17:12:59.458Z, so the page's line "live body sha256
f27326e8b13d1dec..." is a present-tense claim of a six-day-old frozen value --
the pill's defect class, one line below it, read by no gate.

Finding 1 -- row 1's catch is real, and it is the middle of the lane's own
adoption sequence: helm-collect.py:647-662 (pin_stackchain) writes the held pin
from the live body and exits without rendering, so re-pin -> page not yet
re-rendered is reachable by the collector's own --pin. twinE (only _g13_pin
repointed at the live body's hash): row 1 FAIL, row 2 PASS -- 190/2 with the
failing G13 row moved from row 2 to row 1.

Finding 2 -- the hole between the two rows: row 2's predicate passes whenever
the green pill is absent, so a "drift" claim is unverifiable by construction.
The falsered cell under the shipped gate: control-g rc 0 / 191 passed / 0
failed / ALL GATES PASS. A false drift sails through the gate that exists to
check the pill's truth.

The fix -- G13 row 3: a red pill must also be confirmed by a fresh fetch (the
live body must not match the pin). Offline, measured with a dead proxy: rc 1,
191/1, sole failure row 3, fetch_error=URLError(ConnectionRefusedError(111,...)).
The three rows are transitively closed for the pill's class -- page-published
vs pin and pin vs live covers page vs live -- so no fourth row is owed.

Gate: base 94f9b362 (180,772 B / 3,432 lines / 141 registrations) -> shipped
helm-selftest-q64.py 182,752 B / 3,464 lines / 142 registrations /
6a887f42754a8d96a2e28e7f24df072a75c0820776a25a650bf414274ada990d
(+1,980 B / +32 lines / +1 registration), four asserted anchors, four twins and
one control each one to four asserted lines different. Matrix, prediction
stated before the run: shipped rc 1 / 190/2 (G10 deployed-page, G13 row 2 live)
twice, byte-identical after normalisation; twinE 190/2; twinF rc 0 / 192/0 /
ALL GATES PASS -- the honest remediated end state, and the SECOND configuration
this gate has ever passed (twinC was the first); twinG 191/1, row 3 only;
twinH 192/0, a true drift claim is not refused; control-g 191/0, the hole. The
twinG/control-g pair isolates row 3 and nothing else.

Live delta 0 across all seven legs (bytes + sha256 + mtime_ns): 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/0; disk 41 G free of 154. Adoption is four files in one
order: renderer 306d4bee -> collector 4e45021d + gate 6a887f42 -> re-collect ->
re-render -> deploy, acceptance criterion rc 0 / 192 / 0 / ALL GATES PASS
(twinF's shape, demonstrated twice), with the re-collect load-bearing twice:
G13's live row stays red until a collect recomputes manifest_match, and
Finding 1 shows the re-pin inside a collect can leave the page and the pin
disagreeing until the re-render lands.

Four defects of mine logged first in the record's section 8: my twinE
prediction named two failures while printing 189/3 (the row-level prediction
was met exactly); the first cell set left observed_at at the 2026-10-08 stamp
so twinF was the stale cell and came back red on G12; the runner's first run
died on its own set-in-JSON bug before writing the artifact; and the runner's
docstring still carries the original prediction, because a prediction edited
after the run is not a prediction. Nothing deployed, no another-party file
edited, decisions/ and inbox/ untouched, no secret printed. No queue item
closed, none opened. Merlin <merlin@agents.invalid>.
2026-10-15 06:13:31 +00:00

13 KiB
Raw Blame History

The pin pill in both directions — G13 row 1's demonstrated catch, and the false red no row could see

Run 35, Helm lane. Merlin, 2026-10-15T06:00–07:2xZ. Scratch /root/crucible/q64/. Deliverable: this record. Gate helm-selftest-q64.py (182,752 B / 3,464 lines / 142 registrations / sha256 6a887f42754a8d96a2e28e7f24df072a75c0820776a25a650bf414274ada990d), built from Run 34's shipped gate 94f9b3625e5791a7… (180,772 B / 3,432 lines / 141 registrations) at four asserted anchors: +1,980 B / +32 lines / +1 registration. Four twins and one control, each one to four asserted lines different. Subject collector 4e45021d80395d3f… / 29,954 B throughout.

Nothing was deployed: no cp into /root/.helm/bin/, no --deploy, no write to the live document root, no write anywhere under /root/.helm. Live state measured before and after every leg: delta 0 (bytes + sha256 + mtime_ns on all three objects). No another-party file edited; no secret printed; decisions/ and inbox/ untouched.


1. Why this unit

Run 34 closed G13 with one limit stated and left open in its own record: "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." This run discharges that limit — and in discharging it finds the second one: the pill's truth was being checked in one direction only.

Two questions, both answerable with objects already on this host:

  1. Is there a real state that makes row 1 fire? If not, row 1 is dead code and the record must say so.
  2. Row 2 confirms a green pill against a fresh fetch. What confirms a red one? Nothing. A page whose pill says drift while the live body equals the held pin passes every row the lane has.

2. Ground truth, measured this run

python3 /root/crucible/q64/probe_r35.py, exit 0, and python3 /root/crucible/q64/make_cells_r35.py → R35-CELLS.json:

object reading
live body (https://www.stackchainmagazine.net/, the snapshot's own URL) HTTP 200 / 217,163 B / sha256 c34ae2c245117ca73ba5720b2c22b6fab689840070ff68cda7bffe3e723986d4
held pin /root/.helm/data/held/stackchain-home.html.sha256 120 B / f27326e8b13d1dec9eb158fe40e5091f79dcaf73b47312c4e7d3958ba1d95d18 stackchain-home.html pinned 2026-10-08T16:58:07.100Z / file sha256 5b6d70716153c3f4…
pin_matches_live_now false — the live body differs from the held pin
snapshot stackchain_site.manifest_match / live_body_sha256 / evidence.observed_at true / f27326e8b13d1dec… (the pin, not the body) / 2026-10-08T17:12:59.458Z — six days and change stale
deployed page /var/www/alexander-whitestone/helm/index.html 9,865 B / 427b7b54c69b18d2…, carries live body sha256 <span class="mono">f27326e8b13d1dec… and held copy <span style="color:#22c55e">match</span> (pinned vs live), as of ×0, not re-checked since ×0

Two consequences, stated because the record must not read around them:

  • The page's line "live body sha256 f27326e8b13d1dec…" is a present-tense claim of a six-day-old frozen value. The live body is c34ae2c2…. This is the same defect class as the pill, one line below it, and it is covered by nothing — G10 owns the missing qualifier, G12 the pill's pairing, G13 the pill's truth. The hash line is read by no gate.
  • manifest_match: true with live_body_sha256 equal to the pin is internally consistent only at the instant of collect. It is a frozen claim, and every gate that reads it reads a 2026-10-08 reading.

3. The cells

Three subjects (make_cells_r35.py → cells/, all readings at the run's clock 2026-10-15T06:07:22.000Z):

cell built by bytes / sha256 pill published hash vs held pin r1/r2/r3 vs fresh pin r1/r2/r3
deployed page (production, read-only copy) the document root 9,865 / 427b7b54c69b18d2… green match f27326e8b13d1dec PASS / FAIL / PASS FAIL / PASS / PASS
r35-match-fresh.html scratch renderer copy (SNAPSHOT repointed, Q45's class) on a scratch snapshot whose manifest_match is true and whose live_body_sha256 and evidence.observed_at are the real live body's hash and this run's clock 11,742 / 7e2a4cb677555ec8… green match c34ae2c245117ca7 FAIL / FAIL / PASS PASS / PASS / PASS
r35-falsered-fresh.html same renderer, manifest_match false, hash and clock real 11,742 / 0e0e20b52b73b341… red drift c34ae2c245117ca7 PASS / PASS / PASS PASS / PASS / FAIL

Neither constructed cell is drift theatre: the hash is the live body's own digest measured minutes earlier, and the observation clock is the run's. The match cell is the state a correct re-collect produces; the falsered cell is the state a page reaches when the pill says drift while the held pin is the live body.

Finding 1 — row 1 has a real state, and it is the middle of the lane's own adoption sequence. helm-collect.py:647–662 (pin_stackchain) writes the held pin from the live body's hash and exits without rendering. So the sequence re-pin → (page not yet re-rendered) is reachable by running the collector's own --pin, and in that state the deployed page publishes f27326e8… while the held pin is c34ae2c2…. Measured on the first table's last two columns: row 1 FAIL, row 2 PASS. The catch is demonstrated, and it is not hypothetical — the lane's own §4 order is renderer → collector → re-collect → re-render → deploy, and between the re-collect (which can re-pin) and the re-render, the gate's offline row is the only thing that sees the discrepancy.

Finding 2 — the hole between the two rows. Row 2's predicate passes whenever the green pill is absent, so a page claiming drift is unverifiable by construction. The falsered cell against the fresh pin: row 1 PASS, row 2 PASS — and with the shipped gate as the subject, control-g returns rc 0, 191 passed, 0 failed, ALL GATES PASS. A false drift claim sails through the gate that exists to check the pill's truth.


4. The fix, and why it is not a fourth instrument

G13 gains row 3: a red pill is confirmed by a fresh fetch too — the body it claims to have drifted from must still differ from the live one. Predicate (_g13_red not in text) or (_g13_matches is False); when the fetch cannot be made _g13_matches is None, the row is red, and the reason is named in its own evidence line (measured, §6).

The three rows are transitively closed for the pill's class, which is the argument that no fourth row is owed: row 1 is page-published hash vs pin, rows 2 and 3 are pin vs live (green and red directions), and together they cover page-published vs live without ever fetching inside row 1. Row 2 subsumes G12 on the stale cell (Run 34's finding, unchanged); row 3 subsumes nothing and is subsumed by nothing.


5. The matrix

python3 /root/crucible/q64/run_matrix_r35.py → out/R35-GATE.json (20,078 B). Prediction stated in build_r35.py before the run; measured:

config predicted measured verdict
shipped (q64) rc 1, 190/2 rc 1, 190 passed, 2 failed (G10 deployed-page row, G13 row 2 live) met exactly
shipped again byte-identical stdout identical after normalisation, residual 0 met
twinE — only _g13_pin repointed at the live body's own hash rc 1, 189/3 rc 1, 190 passed, 2 failed — G10, and G13's failing row MOVED from row 2 to row 1 (row 2 flips to PASS) the catch demonstrated; my count was wrong, §8
twinF — three page subjects at the match cell + fresh pin rc 0, 192/0 rc 0, 192 passed, 0 failed, ALL GATES PASS met exactly — the honest remediated end state, and the second configuration this gate has ever been able to pass (twinC was the first, on the drift cell)
twinG — falsered cell + fresh pin rc 1, 191/1, row 3 only rc 1, 191 passed, 1 failed — row 3 only, its evidence line reading unqualified_red_pill=True live_sha256=c34ae2c245117ca7 held_pin_digest=c34ae2c245117ca7 pin_matches_live_now=True met exactly
twinH — same cell against the held pin (a true drift claim) rc 0, 192/0 rc 0, 192 passed, 0 failed, ALL GATES PASS met exactly — row 3 does not over-refuse an honest drift
control-g — the shipped q63 gate under twinG's exact repoints rc 0, 191/0 rc 0, 191 passed, 0 failed, ALL GATES PASS met exactly — the hole, measured: the false-red page passes the gate as it stands

The twinG / control-g pair isolates row 3 and nothing else: same three page subjects, same pin, the only difference the row's existence. Asserted in the runner (pair_isolates_row3: true).

Offline behaviour, measured not read. twinG with both proxies pointed at a dead port (offline_row3_r35.py, out/R35-OFFLINE.txt): rc 1, 191/1, sole failure row 3, fetch_error=URLError(ConnectionRefusedError(111,…)), pin_matches_live_now=None. A red pill that cannot be checked is refused, the same trade row 2 takes knowingly, and it will read as noise on a disconnected host — stated, not hidden.


6. Live state, delta 0 across all seven legs

Bytes + sha256 + mtime_ns, censused before every leg and after the last (out/R35-GATE.json, live_delta_empty_all_legs: true, per-object unchanged ×3):

  • deployed page 9,865 B / 427b7b54c69b18d2…
  • snapshot 14,039 B / aa842b0fd88037f8…
  • held pin 120 B / 5b6d70716153c3f4…

Deployed /root/.helm/bin/ untouched (five digests re-read) and grep -c HELM_COLLECTOR /root/.helm/bin/helm-selftest.py = 0, so Q40 stands and nothing of Q31–Q63 is in production. Sandboxes 0/0/0 before and after. Disk 41 G free of 154.


7. Adoption — four files, one order, unchanged in kind

adopt renderer 306d4bee… (22,731 B) → adopt collector 4e45021d… (29,954 B) + gate 6a887f42… (182,752 B) → re-collect → re-render → deploy.

The gate supersedes 94f9b362… (Run 34's) and everything before it. The acceptance criterion is unchanged and now demonstrated twice: the sequence is done when the gate reaches twinF's shape, rc 0 / 192 passed / 0 failed / ALL GATES PASS. The re-collect is load-bearing twice over — G13's live row stays red until a collect recomputes manifest_match against the live body, and Finding 1 shows the re-pin inside a collect can leave the page and the pin disagreeing until the re-render lands.

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


8. Defects of mine, logged first

  1. My own prediction for twinE was wrong and internally contradictory. It read "189 passed, 3 failed (G10, G13 row 1; row 2 flips PASS)" — two named failures is 190/2, not 189/3. The measured result is 190/2 with the failing G13 row moved from row 2 to row 1, which is what the sentence's second half says and its first half does not. No finding depends on the count; the row-level prediction (row 1 fires, row 2 passes) was met exactly.
  2. The first cell set rendered the STALE cell, not the remediated one. The scratch snapshots kept the live snapshot's evidence.observed_at of 2026-10-08, so a cell rendered at today's clock carried a six-day age and the renderer appended not re-checked since — twinF came back 191/1 red on G12, and I nearly recorded the remediated state as unpassable. The cause is the renderer's own rule (helm-render-plain.py:329), the same rule Run 34's G10 fix was built around; the fix was to stamp the observation clock with the run's clock, because that is what a re-collect does. The cells are 11,742 B now against 11,806 B in the first set.
  3. The matrix runner's first run died on its own artifact. pair_isolates built a set and json.dumps refused it, so out/R35-GATE.json did not exist until the second run. The figures above are from the run that wrote the artifact; the first run's stdout agreed with it cell for cell, which is why the second run was a re-run and not a re-measurement.
  4. run_matrix_r35.py's docstring still carries the original twinE prediction (189/3). Left as written, because a prediction edited after the run is not a prediction.

Limits, stated as the item's first limits:

  • Row 3 needs the network, like row 2. Offline it is red with the reason named — the conservative direction, and noise on a disconnected host.
  • The three rows detect and cannot repair. The remedy is still re-collect → re-render → deploy, an operator's call under §4.
  • The pill's substance is still the collector's frozen field. These rows make a false pill visible; they do not make the field fresh.
  • The page's "live body sha256" line — a present-tense label on a frozen value — is now covered transitively through the pin, but nothing checks the label itself. A renderer-side wording fix ("last checked body sha256, as of …") would retire the class at the source; it is a live-page change and therefore Alexander's, alongside Q13's.

— Merlin (Run 35), Helm lane