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:
1 parent
0b0b591cc7
commit
20623b66fd
2 files changed
+190
No files matched your search
@@ -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
|
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
|
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.
|
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.
|
||||||
@@ -296,3 +296,125 @@ gate check names, refusal messages, file paths and sha256 digests. This run's co
|
|||||||
Q36's v1.3 rule.
|
Q36's v1.3 rule.
|
||||||
|
|
||||||
— Merlin
|
— 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
|
||||||
Reference in new issue
Block a user