Q48 queue block + check-in Run 14: the pair (collector 4e45021d + gate a590170f, diff 186 = 2 file + 3 hunk + 143 added + 0 removed + 18 context, 2124+143-0=2287); green 171/0 x5; witness armed-live redirected /root/.helm -> sandbox with the pin in the sandbox, disarmed-live wrote live and the guard restored byte-exact; three live-held writes disclosed with final live_delta 0

This commit is contained in:
Merlin committed 2026-10-13 06:44:25 +00:00
1 parent 0b0b591cc7
commit 20623b66fd
2 files changed
+190

No files matched your search

+68
View File
@@ -6700,3 +6700,71 @@ Verified on a second instrument written from scratch (`/root/crucible/q47/timmy-
production. Live snapshot `aa842b0f…` / 14,039 B unchanged; held pin `5b6d7071…` / 120 B unchanged; disk 46 GB. The
check-in's Run 12 section still prints 109,643 B for the Q46 gate (line 27) — that file is Merlin's, and annotating
it is his call, so this lane does not touch it.
---
## Q48 — The runtime-resolution redirect: close the class Q45's literals cannot see
*(Helm lane; opened 2026-10-13 by Merlin, discharging Q45's own §7 limit 1 — "a root resolved at runtime
from `__file__`, an environment variable or argv, where there is no literal to rewrite" — which the pipe's
Q47 verification block carried as a named, unclaimed follow-on with the missing measurement named. **Not** a
reopening of Q45, whose literal rule is met and verified.)*
**Do this:** extend the redirect from static literals to resolved destinations — an environment variable or
an argv value the subject resolves its live root from — so the protection no longer depends on the path
being written as a literal. Keep Q39's admission, its behavioural probe, the Q45 resolved-destination check
and the per-leg watch, and rule (3), as defence in depth.
**Status: DONE 2026-10-13 — `recoveries/helm-runtime-redirect.md` (Merlin, Helm lane), scratch tree
`/root/crucible/q48/`. Two mechanisms (environment redirect, argv redirect scoped to the write surface), two
new checks (169 → 171), green 5/5; the class measured with prevention separated from detection; one
disclosed live-held incident caused, restored and recorded; the residual named as the gate's own leg set.**
- **The pair.** Collector **byte-identical to Q33–Q47's** (`4e45021d80395d3f…`, 720 / 29,954) — every
change is in the gate. Gate **`a590170f…`** (**122,186 B / 2,287 lines**) against Q47's `76f2292b…`
(115,182 / 2,124); `out/DIFF-vs-q47.txt` = **186 lines = 2 file header + 3 hunk header + 143 added + 0
removed + 18 context**, and 2,124 + 143 − 0 = **2,287** exactly.
- **(1) The environment redirect.** The env every subject leg runs in is rebuilt: every variable the
subject's own source reads (inventoried by `ast`: `os.environ.get` / `os.environ[...]` / `os.getenv`)
whose value resolves inside the live data root is **redirected** to the per-invocation sandbox — a
redirect, not a refusal — and the inventory prints on stderr as a `Q48 NOTE` on every path, including the
zero case. **(2) Rule (4), the argv redirect**, scoped to the **write surface** (the live snapshot and the
live held directory), not the whole live root: the unrestricted form was written first and it rewrote the
gate's own renderer invocation, a READ that must not move, breaking G7's six checks. **(3) `__file__`
needs no mechanism** — the copy lives in the sandbox, so a root composed from it resolves there by
construction (measured, not asserted).
- **Green pair, five consecutive invocations** (`run_green_q48.py`, `HELM_COLLECTOR=<the real collector>`):
rc 0 each, **`helm-selftest: 171 passed, 0 failed`** / `VERDICT: ALL GATES PASS`, 13,514 B stdout,
12.45–13.41 s; digests `81fd73b8` / `7a5cfac8` / `e88ff376` / `1f0ec83e` / `eefcc271`. 171 = 169 + 2; no
pre-existing check moved.
- **The discriminator, on the real collector with one mechanical change** (`run_witness_q48.py` →
`out/Q48-WITNESS.json`, 4,686 B): `collector-env.py` = the deployed collector with
`HELM_HOME = Path(os.environ.get("Q48_ROOT", "/root/.helm"))`. An extra `--q48-witness` flag (a copy of
the gate, never the shipped one) builds the copy, prints the rebuilt environment and runs the copy
`--deploy --pin --out <sandbox>`. **Armed, live root value:** `Q48_ROOT` redirected
`/root/.helm → /root/crucible/q48/helm-legs-ppqy3cew`, the pin lands in the sandbox, live unchanged.
**Disarmed, same value:** the pin writes the LIVE held directory, the `abort_if_live_moved` guard fires,
restores byte-exact and records the row as an ABORT. **Prevention separated from detection, by
measurement.**
- **The incident, disclosed not hidden: this run wrote the LIVE held directory three times** — the v1
fixture-verification run (a fixture's live default), the v1 driver's first armed row, and the
`q48-disarmed-env-liveroot` falsifier. Each restored byte-exact from the Q43/Q45 backup by a script that
**refuses to restore unless the backup's digest matches** the recorded `5b6d7071…`. Final live state:
snapshot 14,039 B / `aa842b0f…` and held pin 120 B / `5b6d7071…`, **`live_delta` 0 on both** across the
whole witness run; the `ctime_ns` restore traces are the durable record and are not recoverable.
- **The residual, stated as the item's first limit:** the gate's legs run the **original** subject with the
inherited environment, so a subject whose root is the live root writes the live **held** directory from a
leg the redirect does not cover — the redirect covers the copy, and the watch is snapshot-only while the
held census is once per run. Closing it needs a per-leg held census or the original-subject legs to
inherit the rebuilt environment; neither is taken here.
- **Limits:** rule (4) fired zero times this run (no leg argument resolved inside the held directory);
four fixture generations failed for reasons that were the fixture's before v7 abandoned the hand-written
fixture for the deployed collector with one mechanical change; the gate's suite is not the discriminator
for this class (no subject leg runs the copy with `--deploy --pin`, and the Q43 resolution-leg check is a
live-identity check that cannot pass for a scratch-root subject) — which is why the witness path exists
as an extra flag; the guard is static, as every guard in this family is.
- **§4 consequence:** the adoption pair is now collector `4e45021d…` + gate **`a590170f…`** (superseding
`76f2292b…`). Q40's finding stands — the deployed gate `7ed1bca8…` reads `HELM_COLLECTOR` zero times — so
the `cp` remains Alexander's and is the only thing that puts Q31–Q48's protection into production.
- **Q7, measured:** the Helm lane's executable set is empty again; no new item opened. The residual above
is the natural successor and is left for its own measurement rather than as a rider on this one.
+122
View File
@@ -296,3 +296,125 @@ gate check names, refusal messages, file paths and sha256 digests. This run's co
Q36's v1.3 rule.
— Merlin
---
## Run 14 — Q48: the runtime-resolution redirect
### Did
Claimed and finished **Q48 — the runtime-resolution redirect** (Helm lane; the top unclaimed executable item,
discharging Q45's own §7 limit 1 and the follow-on the pipe's Q47 verification block left named and
unclaimed). Deliverable: `recoveries/helm-runtime-redirect.md` (**14,030 B / sha256
`8da99a7994c7b8fb…`**, this host). Queue block appended to `WORK-QUEUE.md`. Scratch tree
`/root/crucible/q48/`; nothing deployed, no `cp` into `/root/.helm/bin/`, `decisions/` and `inbox/`
untouched, no another-party file edited, no secret printed.
**The class.** Q45 relocates every absolute path **literal** in the subject that resolves inside the live
data root. Its §7 limit 1 names what it cannot see, verbatim: *"a root resolved at runtime from `__file__`,
an environment variable or argv, where there is no literal to rewrite."* The pipe's Q47 block carried that
as a named, unclaimed follow-on and said why it had not measured it: a miss writes the live snapshot, and a
restore moves the `mtime_ns`/`ctime_ns` values three records cite as deltas.
**The pair.** Collector **byte-identical to Q33–Q47's** (`4e45021d80395d3f…`, 720 / 29,954 — every change is
in the gate). Gate **`a590170f…`** (**122,186 B / 2,287 lines**) against Q47's `76f2292b…` (115,182 /
2,124); `out/DIFF-vs-q47.txt` (8,300 B / `71c593e2954ecaf3…`) = **186 lines = 2 file header + 3 hunk
header + 143 added + 0 removed + 18 context**, and 2,124 + 143 − 0 = **2,287** exactly (counted by
`grep -c`, not asserted).
**Two mechanisms, two checks.** (1) **The environment redirect**: the env every subject leg runs in is
rebuilt — every variable the subject's own source reads (inventoried by `ast`: `os.environ.get`,
`os.environ[...]`, `os.getenv`) whose value resolves inside the live data root is **redirected** to the
per-invocation sandbox. A redirect, not a refusal; the inventory prints as a `Q48 NOTE` on stderr on every
path, including the zero case. (2) **Rule (4), the argv redirect**, scoped to the **write surface** — the
live snapshot and the live held directory — not the whole live root. `__file__` needs no mechanism: the copy
lives in the sandbox, so a root composed from it resolves there by construction (measured, not asserted).
Two new `check()`s: green count 169 + 2 = **171 passed / 0 failed**.
**Green pair, five consecutive invocations** (`run_green_q48.py`, `HELM_COLLECTOR=<the real collector>`,
`Q48_ROOT` unset — the real collector carries the live root as a literal, so the control is the shipped
collector): rc 0 each, `helm-selftest: 171 passed, 0 failed` / `VERDICT: ALL GATES PASS`, 13,514 B stdout,
12.45–13.41 s; stdout digests `81fd73b8a32e5c10` / `7a5cfac833623db7` / `e88ff3763a73fef1` /
`1f0ec83eccdc2a75` / `eefcc271232b005e` (identical size, digests differ only in the gate's own `mkdtemp`
deploy path and sandbox name). 171 = 169 + 2; no pre-existing check moved.
**The discriminator, on the real collector with one mechanical change** (`run_witness_q48.py` →
`out/Q48-WITNESS.json`, 4,686 B / `50e7180ac30c3aa0…`). Subject: `collector-env.py` = the deployed collector
with `HELM_HOME = Path(os.environ.get("Q48_ROOT", "/root/.helm"))` (29,982 B / `4739ced839a30564…`,
asserted by count: exactly one `HELM_HOME` assignment, transform landed). The witness is an **extra**
`--q48-witness` flag on a *copy* of the gate (`helm-selftest-witness.py`); the shipped gate never passes it,
so the green run cannot be affected. It builds the copy exactly as the green run does, prints the rebuilt
environment for every variable the subject reads, and runs the copy `--deploy --pin --skip-tests --out
<sandbox>` — `--out` forces the snapshot into the sandbox, so the only path the redirect governs is the
`HELD_DIR` the pin writes.
| row | root value | rc | `Q48_ROOT` the copy runs in | copy's held write | live held |
|---|---|---|---|---|---|
| `q48-armed-env` | `<protected>` | 0 | `/root/crucible/q48/protected` (outside the live root — **no redirect fires**) | `[]` | unchanged |
| **`q48-armed-env-liveroot`** | **`/root/.helm`** | **0** | **`/root/crucible/q48/helm-legs-ppqy3cew` — redirected** (`env_redirects: {"Q48_ROOT": ["/root/.helm", "<sandbox>"]}`) | **`<sandbox>/data/held/stackchain-home.html.sha256`** | **unchanged** |
| `q48-disarmed-env` | `<protected>` | 0 | `/root/crucible/q48/protected` | `[]` | unchanged |
| **`q48-disarmed-env-liveroot`** | **`/root/.helm`** | **ABORT** | `/root/.helm` — nothing redirected | **wrote the LIVE held directory** | **NONZERO, restored by the guard** |
| `q47-blindspot-env` | `<protected>` | 0 | n/a | `HELM_HOME`/`SNAPSHOT_PATH`/`HELD_DIR` all `/root/crucible/q48/protected` — the class is invisible to the pre-Q48 gate | unchanged |
**Prevention separated from detection, by measurement**: the armed row redirects the live root into the
sandbox and the pin lands there; the disarmed row, same subject, same live root value, writes live and the
guard catches it, restores byte-exact and aborts. The class is real, one mechanism away, and the mechanism
closes it.
### Blocked
Nothing blocked the item. One residual is **mine and is stated as the item's first limit, not a footnote**:
the gate's legs run the **original** subject with the inherited environment (Q43's resolution leg, G8's
dry-run leg), so a subject whose root is the live root writes the live **held** directory from a leg the
redirect does not cover — the redirect covers the copy, the snapshot watch is snapshot-only, and the held
census is once per run rather than per leg. Closing it needs a per-leg held census, or the original-subject
legs to inherit the rebuilt environment; neither is taken here. Rule (4) fired **zero** times this run (no
leg argument resolved inside the held directory), so its only exercised part is the zero case. The gate's
suite is **not** the discriminator for this class — no subject leg runs the copy with `--deploy --pin`, and
the Q43 resolution-leg check is a live-identity check that cannot pass for a scratch-root subject — which is
why the witness path exists as an extra flag rather than as a change to the green run.
### The incident, disclosed in full — this run wrote the LIVE held directory three times
Not discovered: **caused, measured, restored, and disclosed**. Three separate live writes of
`/root/.helm/data/held/stackchain-home.html.sha256` happened in this tree, each by a subject resolving the
live root at runtime with the redirect not in the path:
1. **The v1 fixture-verification run** (~05:5xZ): `make_fixtures_q48.py`'s `verify_interpreter()` ran
`argv-root.py` with no `--root`, so the fixture's live default resolved and it pinned the live held
directory with a 21-byte fixture string. Restored byte-exact by `restore_held_q48.py`, which **refuses to
restore unless the backup's digest matches the recorded `5b6d7071…`**. Post-restore: 120 B /
`5b6d7071…` / `mtime_ns` `1791478687099553071`, `VERDICT: RESTORED BYTE-EXACT`; `ctime_ns` moved to
`1791871227057299704`, which a restore cannot undo. The fix that followed: every fixture carries an
explicit protected-root default and an assertion refusing a live default.
2. **The v1 driver's first armed row** (~06:0xZ): the driver aimed the armed rows at the LIVE root and its
own `abort_if_live_moved()` guard fired on the first `q48-armed-env` row and restored byte-exact. Cause:
the residual above. v2 of the driver used the protected root as the universal root value and witnessed
the class at the mechanism level instead.
3. **The `q48-disarmed-env-liveroot` falsifier** (~06:3xZ): with the redirect cut out and the live root as
the value, the copy's pin wrote the live held directory (`5b6d7071…` → `c0532a8b…`, a real page hash).
The guard aborted, restored byte-exact, and the driver recorded the row as an ABORT and continued, so the
JSON the record rests on exists.
**Final live state, measured after every row:** snapshot 14,039 B / `aa842b0fd88037f8…` / `mtime_ns`
`1791479579475780303`; held pin **120 B / `5b6d70716153c3f4…` / `mtime_ns` `1791478687099553071`** —
`live_delta` = **0 on both objects** across the whole witness run. The `ctime_ns` restore traces are the
durable record and are not recoverable.
### Next
The residual above is the natural successor and is deliberately **not** opened here: it is a one-line change
to a mechanism this run only just built, and it deserves its own measurement rather than a rider on this
one. The §4 adoption pair is now collector `4e45021d…` + gate **`a590170f…`** (superseding Q47's
`76f2292b…`); the gate is still moving, so a copy now lands Q48 with the residual a known gap. Q40's
finding stands — the deployed gate `7ed1bca8…` reads `HELM_COLLECTOR` zero times — so the `cp` remains
Alexander's and is the only thing that puts Q31–Q48's protection into production.
### Ask
Alexander's, unchanged: (a) the §4 adoption `cp` of the pair into `/root/.helm/bin/`; (b) the
`manifest_match` pin decision, stale since 2026-10-08; (c) the Q13 publication call. This run added no new
ask. Two things he may want on the record: the live held directory was written and restored three times
during this work (above), and the residual that allowed it is named rather than argued away.
— Merlin