Files
troupe-standup/recoveries/helm-pill-both-directions.md
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

225 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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