diff --git a/WORK-QUEUE.md b/WORK-QUEUE.md index 4b1ab0c..f413aac 100644 --- a/WORK-QUEUE.md +++ b/WORK-QUEUE.md @@ -8270,3 +8270,87 @@ point). **The §4 `cp` pair is sound and needs no re-cite** — collector `4e450 - **One premise of the brief does not hold: the green stdout *is* kept.** The brief reports the published gate-stdout digest `585e0e4b…` as unre-derivable because "its raw output was not kept under `out/`". It is there — `out/h-green-1.out` through `h-green-5.out`, each **14,044 B**, with `out-control.txt` and the r10/r11 refusals at the same size. The digest's five other occurrences are in the cite files (`r23-commit-msg.txt`, `out/R23-VERIFY.json`, the three append scripts), not in a missing artifact. **So the finding is not a missing file but a property: the green stdout varies per run** because it prints per-run tmp and sandbox names — which is what the pipe isolated, and why the right citation is the byte count plus verdict and rc, with the digest marked per-run. - **Live, deployed and boundary unchanged.** Snapshot 14,039 B / `aa842b0f…` / mtime_ns `1791479579475780303`; pin 120 B / `5b6d7071…` / `1791478687099553071`; ctime_ns `1791907371554631194` on both; `HELM_COLLECTOR` 0 in every deployed file, so none of Q31–Q45 §9 is in production; zero sandboxes under `q55/`; disk 45 G of 154 G. Replies 45 and 46 exist and carry the read closure and the two corrections; nothing is owed the pipe or the lane. - **Standing set unchanged, with one item the recent blocks keep dropping: the §4 `cp` of collector `4e45021d…` + gate `cd43284f…`, the `manifest_match` pin stale since 2026-10-08, Q13, Q9, Q19, and Q53 — the career lane, held for Alexander, item 7 expiring.** + + +--- + +**Q45S10 (Helm lane) — Run 24: the discovery channel closed by a seeded sandbox, with the artifact as +the detector (Merlin, 2026-10-14).** The named residual every record since Q45 has carried — *resolve every +path the subject declares at runtime* — is discharged: Q48 closed environment values and argv, Q52 closed +`Path.home()`/`expanduser`, Q45S9 closed `pwd.getpwuid`, and **the filesystem search was the remainder, the +one channel no redirect can reach, because every redirect keys on how the destination is declared and this +class declares nothing.** Deliverable: `recoveries/helm-discovery-channel-seed.md`. Scratch tree +`/root/crucible/q56/`; nothing deployed, no `cp` into `/root/.helm/bin/`, `decisions/` and `inbox/` +untouched, no another-party file edited, no secret printed. Internal label `Q45S10` follows `Q45S9`; the +queue's Q52 is Mercury's and Q53 the career lane's, so neither number is reused. + +- **The class, measured on the shipped gate before the change.** `collector-discover.py` (the real collector + `4e45021d…`, 720 / 29,954, with the held directory resolved at call time by walking up from the module's + own location and then scanning the candidate roots for the held pin) is **admitted on the same terms as + every other collector** — `Q39 OK: the subject refused its sentinel destination (probe rc=2, sentinel + written=False, other probe files=0, no traceback, live delta 0)` — and the suite is **green**: + `helm-selftest: 176 passed, 0 failed`, `VERDICT: ALL GATES PASS`, live delta `{}`. The Q45 + resolved-destination probe prints `HELD_DIR=None` (the module-level constant the copy declares), so check 2 + passes **vacuously**: the gate is green on a subject whose held directory is the live one. The interpreter's + own verdict of the class: run bare, both fixtures read the LIVE held pin (`held_body_sha256` = + `f27326e8b13d1dec…`, the live pin's digest), and a scratch HOME changes nothing — the subject never reads + HOME, so Q52's redirect is satisfied by a mechanism the subject does not use. The control shows the probe + is not broken: the **eager** form (`HELD_DIR = _discover_helm_home() / "data" / "held"` at module level) is + **reported**, `FAIL Q45 … HELM_HOME=/root/.helm, HELD_DIR=/root/.helm/data/held` (175/1). The call-time + form is the blind one. +- **The escape's write path, measured:** `shipped × discover --q52-witness` → rc 0 and **the live held pin + moves** (`5b6d70716153c3f4…` → `4e98bb00650e…`), restored byte-exact by the guard, with + `copy_pin_files_anywhere_in_sandbox` `[]` — the pin is not in the sandbox because it is in the live tree. + Nothing inside the gate sees it. +- **The fix, two inserts.** (1) **The seed — prevention:** at the sandbox-creation site the sandbox is given + its own `.helm/data/held/stackchain-home.html.sha256` carrying a **decoy** digest + (`1e0c8aeefeadd3a1af732b94b2b2b342dfc0a38446714f812305416323ee1ce3`), so the copy's walk-up — the copy sits + at `/subject-legs.py` — finds the sandbox's own tree first and every discovery resolves inside + the sandbox. A decoy, never the live bytes. (2) **The artifact check — detection:** one more subject leg + writes a snapshot into the sandbox (through the same wrapper as every other leg) and the artifact must not + carry the live held pin's digest; this is the only instrument that can see a call-time resolution, because + the probe is vacuous on it by construction. +- **The pair.** Gate **`c56230e5a075c5a12fd2f0d336dcac71c1078cb692a9e6c995780098a051f13e`** (147,151 B / + **2,798** lines / **127** `check("` registrations — 126 + 1, the new one) on the Q45S9 gate + `cd43284ff009…` (143,389 / 2,735 / 126): `out/DIFF-vs-q55.txt` = **2 hunks, +63 −0 lines, +3,762 −0 B**, + and 143,389 + 3,762 = 147,151 exactly (asserted in `patch_gate_q56.py`). Disarmed twin + **`820b7afdff6821a092a64d8a5c24d27f33baaa624534e9f1bfe351ef065a6e4a`** (147,074 / 2,796 / 127): the seed's + `write_text` statement cut, 3 lines removed and 1 added, **77 B smaller** — the Q50/Q51 twin pattern. +- **The matrix, 8 cells under the digest-verified guard** (`out/Q56-MATRIX.json`, + `out/Q56-MATRIX2.json`): shipped × discover **176/0 silent**; shipped × witness **the live pin moves** + (restored); armed × discover **177/0**, the artifact carrying the **decoy** and not the live digest; + armed × witness `live delta {}` with the pin **inside the sandbox**; **disarmed × discover 176/1** — + `FAIL Q45S10 … live_pin_digest=f27326e8b13d1dec… live_digest_in_artifact=True`, detection without + prevention; **disarmed × witness the live pin moves again** — the seed is load-bearing; shipped × eager + 175/1 (the probe reports the import-time form); armed × eager **177/0** — the seeded sandbox resolves even + the eager form inside. **Green pair ×5: rc 0, 177/0, 14,254 B each** (byte-stable), live delta `{}`; the + shipped gate's own control on the real collector reproduces its historical baseline to the byte + (**176/0 at 14,044 B**). The +210 B on the armed runs is the seed's paths in the Q43 sandbox-census print + plus the artifact leg and the new check's name; **no pre-existing check moved** (176 → 177 is the one new + check). **Regressions 11/11:** n1–n4 and dep-unparseable → Q39 rc 2; noparse → Q46 rc 2; undecodable → Q47 + rc 2; broken_dep → Q35 rc 2; n5 → rc 2 (its own destination rule, on the redirected sandbox dest); latin1 + and bom → green 177/0 at 14,254 B, live delta `{}` on all eleven. +- **Live, deployed, sandboxes, disk** (`out/Q56-CENSUS.json`, re-measured): delta 0 on bytes/sha256/mtime + across all 25 invocations — snapshot 14,039 B / `aa842b0fd88037f8…` / mtime_ns `1791479579475780303`; pin + 120 B / `5b6d70716153c3f4…` / mtime_ns `1791478687099553071`; **ctime moved on both** + (`1791957230760646867` / `1791957230761646950`), the guard restores of the four deliberately-live cells — + disclosed. Deployed `/root/.helm/bin/` untouched (five digests re-read) and `grep -c HELM_COLLECTOR` = + **0**, so **Q40 stands and none of Q31–Q45S10 is in production**. Sandboxes **0 in the q56 tree and 0 + across `/root/crucible`**; 406,212 B reclaimed. Disk 45 G free of 154 (72 %). +- **Adoption:** the §4 `cp` is collector `4e45021d…` + gate **`c56230e5a075…`**, superseding `cd43284ff009…` + (Q45S9), `78b290ecf2d9…` (Q52), `e4967da9…` (Q51), `a951dbe8…` (Q50). Alexander's, unchanged. Beside it: + the `manifest_match` pin stale since 2026-10-08, the Q13 publication call, Q9's checksum handover, Q19's + onboarding. +- **Limits, stated in the record as the item's first limits:** the seed answers a search that walks up from + the subject's own location or scans the candidate roots — a subject that globs the whole filesystem from + `/` finds the live tree too, and there the artifact check is the only instrument; the check is + artifact-shaped, so a discovery subject that reads the live pin and emits nothing catches nothing; the + marker is the collector's own held-pin filename; and a destination handed to the subject at runtime by a + *third party* (a config file, a sibling process) is the next channel and is not measured here. **Six + defects of mine are logged first in the record**, the first being that the initial PEP 562 `__getattr__` + design was wrong twice over — a global name lookup never consults module `__getattr__`, and the gate + refuses a subject with no `SNAPSHOT_PATH =` assignment — so the fixture was rebuilt to move only the held + channel to call time, and the class statement moved with it. +- **Q7, measured:** the Helm lane's executable set is empty again — the adoption, Q9, Q13/Q19 and Q42 are + human- or counterparty-gated, and Q52 is Mercury's and Q53 the career lane's. **No new item opened** — the + next Helm unit after this is a decision, not a task. diff --git a/checkins/2026-10-14-merlin.md b/checkins/2026-10-14-merlin.md index 1071016..5b720ea 100644 --- a/checkins/2026-10-14-merlin.md +++ b/checkins/2026-10-14-merlin.md @@ -294,3 +294,119 @@ in `/root/crucible/q55/`: **0** (`ls | grep -c helm-legs` → 0). Nothing deploy edited, `decisions/` and `inbox/` untouched, no secret printed. — Merlin (Run 23, landing) + + +--- + +## Run 24 — Q45S10: the discovery channel + +### Did + +Claimed and finished **the lane's named residual — the filesystem-discovery channel** (Helm lane; the limit +every record since Q45 has carried: *resolve every path the subject declares at runtime*. Q48 closed env +and argv, Q52 closed `Path.home()`/`expanduser`, Q45S9 closed `pwd.getpwuid`; **the search was the +remainder and the one channel no redirect can reach**). Deliverable: +`recoveries/helm-discovery-channel-seed.md` (this host). Queue block appended at the foot of +`WORK-QUEUE.md`. Scratch tree `/root/crucible/q56/`; nothing deployed, no `cp` into `/root/.helm/bin/`, +`decisions/` and `inbox/` untouched, no another-party file edited, no secret printed. Internal label +`Q45S10` follows `Q45S9`; the queue's Q52 is Mercury's and Q53 the career lane's. + +**The class, measured on the shipped gate before the change.** `collector-discover.py` (31,076 B / +`1f3dae9e7018a656…`, the real collector `4e45021d…` with the held directory resolved at call time: walk up +from the module's own location, then scan the candidate roots, for the held pin) is **admitted on the same +terms as every other collector** — `Q39 OK: the subject refused its sentinel destination (probe rc=2, +sentinel written=False, other probe files=0, no traceback, live delta 0)` — and the suite is **green**: +**176 passed / 0 failed, ALL GATES PASS, live delta `{}`**, 13,918 B stdout, 11.9 s. The Q45 +resolved-destination probe prints `HELD_DIR=None` — the module-level constant the copy declares — so check 2 +passes **vacuously**: the gate is green on a subject whose held directory is the live one. The interpreter's +own verdict: run bare, both fixtures read the LIVE held pin (`held_body_sha256` = +`f27326e8b13d1dec9eb158fe40e5091f79dcaf73b47312c4e7d3958ba1d95d18`, the live pin's digest), and a scratch +HOME changes nothing (`probe-scratch-home.json`) — the subject never reads HOME, so Q52's redirect is +satisfied by a mechanism the subject does not use. The control shows the probe is not broken: the **eager** +form is **reported** (`FAIL Q45 … values={"HELM_HOME": "/root/.helm", "HELD_DIR": +"/root/.helm/data/held", …}`, 175/1). The call-time form is the blind one. + +**The escape's write path, measured:** `shipped × discover --q52-witness` → rc 0 and **the live held pin +moves** (`5b6d70716153c3f4…` → `4e98bb00650e…`), restored byte-exact by the guard, with +`copy_pin_files_anywhere_in_sandbox` `[]`. Nothing inside the gate sees it. + +**The fix, two inserts** (`patch_gate_q56.py`, every anchor asserted `count == 1`, trailing newline asserted +on the written file). (1) **The seed — prevention:** at the sandbox-creation site the sandbox is given its +own `.helm/data/held/stackchain-home.html.sha256` carrying a **decoy** digest +(`sha256(b"Q45S10 sandbox decoy pin")` = `1e0c8aeefeadd3a1af732b94b2b2b342dfc0a38446714f812305416323ee1ce3`), +so the copy's walk-up finds the sandbox's own tree first. A decoy, never the live bytes. (2) **The artifact +check — detection:** one more subject leg writes a snapshot into the sandbox (through the same wrapper as +every other leg: argv rewrite, rebuilt environment, per-leg census, live watch) and the artifact must not +carry the live held pin's digest — the only instrument that can see a call-time resolution, because the +probe is vacuous on it by construction. + +**The pair.** Gate **`c56230e5a075c5a12fd2f0d336dcac71c1078cb692a9e6c995780098a051f13e`** (147,151 B / +**2,798** lines / **127** `check("` registrations — 126 + 1) on the Q45S9 gate `cd43284ff009…` (143,389 / +2,735 / 126): `out/DIFF-vs-q55.txt` = **2 hunks, +63 −0 lines, +3,762 −0 B**, and 143,389 + 3,762 = 147,151 +exactly. Disarmed twin **`820b7afdff6821a092a64d8a5c24d27f33baaa624534e9f1bfe351ef065a6e4a`** (147,074 / +2,796 / 127): the seed's `write_text` statement cut, 3 lines removed and 1 added, **77 B smaller**. + +**The matrix, 8 cells under the digest-verified guard** (`out/Q56-MATRIX.json`, `out/Q56-MATRIX2.json`): +shipped × discover **176/0 silent**; shipped × witness **the live pin moves** (restored); armed × discover +**177/0** with the artifact carrying the **decoy** and not the live digest (*"the live held pin's digest is +NOT in the sandbox artifact, and the sandbox decoy's digest IS"*); armed × witness `live delta {}` with the +pin **inside the sandbox**; **disarmed × discover 176/1** — `FAIL Q45S10 … artifact=… exists=True leg_rc=0 +live_pin_digest=f27326e8b13d1dec… live_digest_in_artifact=True`; **disarmed × witness the live pin moves +again** — the seed is load-bearing; shipped × eager 175/1 (reported); armed × eager **177/0** — the seeded +sandbox resolves even the eager form inside. **Green pair ×5: rc 0, 177/0, 14,254 B each** (byte-stable), +live delta `{}` each; the shipped gate's own control on the real collector reproduces its historical +baseline to the byte (**176/0 at 14,044 B**). The +210 B on the armed runs is the seed's paths in the Q43 +sandbox-census print plus the artifact leg and the new check's name; **no pre-existing check moved**. +**Regressions 11/11:** n1–n4 and dep-unparseable → Q39 rc 2; noparse → Q46 rc 2; undecodable → Q47 rc 2; +broken_dep → Q35 rc 2; n5 → rc 2 (its own destination rule, on the redirected sandbox dest); latin1 and bom +→ green 177/0 at 14,254 B, live delta `{}` on all eleven. + +**Live, deployed, sandboxes, disk** (`out/Q56-CENSUS.json`, re-measured): delta 0 on bytes/sha256/mtime +across all 25 invocations — snapshot **14,039 B / `aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d` / +mtime_ns `1791479579475780303`**; held pin **120 B / `5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297` / +mtime_ns `1791478687099553071`**; **ctime moved on both** (`1791957230760646867` / +`1791957230761646950`) — the guard restores of the four deliberately-live cells, disclosed. Deployed +`/root/.helm/bin/` untouched (five digests re-read: `ee0b36a82f23…` / `5c67473d8928…` / `7ed1bca8f9da…` / +`12570786ba70…` / `738699986778…`) and `grep -c HELM_COLLECTOR` = **0** — **Q40 stands, so none of +Q31–Q45S10 is in production.** Sandboxes **0 in the q56 tree and 0 across `/root/crucible`**; 406,212 B +reclaimed. Disk **45 G free of 154 (72 %)**. + +**Six defects of mine, logged first in the record**, the first being that the initial PEP 562 `__getattr__` +design was wrong twice over — a global name lookup inside a function never consults module `__getattr__`, and +the gate *refuses* a subject carrying no `SNAPSHOT_PATH =` assignment (Q39's failed-conditions list) — so the +fixture was rebuilt to move only the held channel to call time, and the class statement moved with it. The +others: the patch script read and wrote one path (double-insert, caught by the byte identity); the first twin +cut one line of a three-line statement (`IndentationError`); the first diff-vs-shipped compared the file with +itself; the first byte assertion added line counts where bytes were needed; and the green byte count moved +14,044 → 14,254 on the real collector — recorded, not smoothed over. + +### Blocked + +Nothing blocks the lane. The standing human gates are unchanged and none is new: the **§4 adoption `cp` — +now collector `4e45021d…` + gate `c56230e5a075…`** (superseding `cd43284ff009…` / `78b290ecf2d9…` / +`e4967da9…` / `a951dbe8…`), the **`manifest_match` pin** (stale since 2026-10-08), **Q13's publication +call** (item 13's decided note controls over its `proposed_action`), **Q9's checksum handover**, **Q19's +onboarding**. Q42 is zephyrus-sparkborn's, Q52 is Mercury's, Q53 is the career lane held for Alexander. No +counterparty check-in or reply has landed since the 2026-10-14 03:50Z hygiene ledger +(`git log --oneline --since=2026-10-14T00:00`: nothing after `8ba7c8e`). + +### Next + +1. **The pipe's verification of this run**, when it lands. Everything re-runs from `/root/crucible/q56/`: + `setup_q56.py`, `patch_gate_q56.py`, `run_matrix_q56.py`, `run_matrix2_q56.py`, `census_q56.py` and + `q56_guard.py` are self-contained; `out/` holds every cell's stdout and stderr plus `Q56-MATRIX.json`, + `Q56-MATRIX2.json`, `Q56-CENSUS.json` and `DIFF-vs-q55.txt` (host-local — the repo carries 0 paths under + `out/`, E13's rule). +2. **No new item opened.** The Helm lane's executable set is empty again — the adoption, Q9, Q13/Q19 and Q42 + are human- or counterparty-gated — so the next Helm unit is a decision, not a task. + +### Ask + +Alexander's, unchanged: **(a)** the §4 adoption `cp` — collector `4e45021d…` + gate +`c56230e5a075c5a12fd2f0d336dcac71c1078cb692a9e6c995780098a051f13e` (147,151 B / 2,798 lines / 127 +registrations) — the only thing between Q31–Q45S10 and production protection in `/root/.helm`; **(b)** the +`manifest_match` pin, stale since 2026-10-08; **(c)** the Q13 publication call. No ask of the pipe: this run +returned nothing to the pipe's own queue (Q52 is Mercury's, Q53 Alexander's), and the lane's named residual +is discharged by measurement above. + +— Merlin (Run 24) diff --git a/recoveries/helm-discovery-channel-seed.md b/recoveries/helm-discovery-channel-seed.md new file mode 100644 index 0000000..4f53c93 --- /dev/null +++ b/recoveries/helm-discovery-channel-seed.md @@ -0,0 +1,184 @@ +# The discovery channel: a subject that finds its held root by searching the filesystem + +**Helm lane — Q45S10 (Run 24), 2026-10-14.** Scratch tree `/root/crucible/q56/`; nothing deployed, no +`cp` into `/root/.helm/bin/`, `decisions/` and `inbox/` untouched, no another-party file edited, no secret +printed. Internal label `Q45S10` follows Run 22's `Q45S9`; the queue's Q52 is Mercury's and Q53 the career +lane's, so neither number is reused. + +The named residual this discharges is the one every record since Q45 has carried: *resolve every path the +subject declares **at runtime***. Q48 closed environment values and argv; Q52 (Run 18) closed +`Path.home()`/`expanduser`; Q45S9 (Run 22) closed `pwd.getpwuid`. **The filesystem search was the remainder, +and it is the one channel no redirect can reach**, because every redirect keys on how the destination is +*declared* — a literal, a variable, an argument, a home read — and this class declares nothing. + +--- + +## 1. The class + +`collector-discover.py` is the real collector (`4e45021d80395d3f…`, 720 / 29,954, verified by sha256) with +one change: the held directory is resolved **at call time, by searching the filesystem** — walk up from the +module's own location, then scan the candidate roots, for the held pin: + +```python +def _discover_helm_home(): + here = Path(__file__).resolve().parent + for parent in (here, *here.parents): + cand = parent / ".helm" + if (cand / _MARKER).is_file(): + return cand + for scan in (Path("/"), Path("/root")): + ... +``` + +No absolute literal (Q45 relocates those), no environment read (Q48 rebuilds those), no argv (Q48 rule 4 +rewrites those), no home-database read (Q52 redirects HOME, Q45S9 refuses `pwd`). The snapshot destination +keeps its literal, so the Q39 admission probe still has a module constant to rewrite and the subject is +admitted **on the same terms as every other collector** — which is the point. + +**The interpreter's verdict, measured not asserted.** Run bare from `/root/crucible/q56/`, both fixtures +read the LIVE held pin (`probe-collector-discover.py.json`, `probe-collector-discover-eager.py.json`): + +``` +held_body_sha256: f27326e8b13d1dec9eb158fe40e5091f79dcaf73b47312c4e7d3958ba1d95d18 +reads the LIVE held pin: True (live pin digest, 120 B, same value) +``` + +And under a **scratch HOME** the resolution does not move (`probe-scratch-home.json`): the subject never +reads HOME, so Q52's redirect is satisfied by a mechanism the subject does not use — the Q45S9 finding in a +new place. + +| fixture | bytes | sha256 | lines | +|---|---|---|---| +| `collector-discover.py` (lazy) | 31,076 | `1f3dae9e7018a656722b8151226e4654931925f750f3154e49d2a103f987a0ba` | 753 | +| `collector-discover-eager.py` (control) | 31,094 | `8e58abeda872df2973ff1ce93b208f9c38f8efd4a9425c582f1f0b776efabdb3` | 753 | + +## 2. The class on the shipped gate: silent + +Shipped gate = `helm-selftest-q55.py` (`cd43284ff009d1cceb3aaa6a65b701d1076eaf801e32b705672601b4122b746a`, +143,389 B / 2,735 lines / 126 registrations, verified by sha256 from `/root/crucible/q55/`). + +- **Cell A — `shipped × discover`, green shape:** rc 0, **`helm-selftest: 176 passed, 0 failed`**, + `VERDICT: ALL GATES PASS`, 13,918 B stdout, 11.9 s, **live delta `{}`**. The admission is normal + (`Q39 OK: the subject refused its sentinel destination (probe rc=2, sentinel written=False, other probe + files=0, no traceback, live delta 0)`), Q48/Q49 are vacuous on a subject that reads no variable, and the + Q45 resolved-destination probe prints `HELD_DIR=None` — the module-level constant the copy declares — + so check 2 passes **vacuously**. The suite is green on a subject whose held directory is the live one. +- **Cell A2 — `shipped × discover --q52-witness`:** rc 0 and **the live held pin moves** + (`5b6d70716153c3f4…` → `4e98bb00650e…`), restored byte-exact by the guard; + `copy_pin_files_anywhere_in_sandbox` = `[]` — the pin is not in the sandbox because it is in the live + tree. The gate's own witness writes live from an admitted subject and nothing inside the gate sees it. +- **Cell D — `shipped × discover-eager` (the control):** rc 1, **175/1**. The import-time form *is* + reported: `FAIL Q45 no module-level constant of the copy resolves inside the live data root` with + `values={"HELM_HOME": "/root/.helm", "SNAPSHOT_PATH": "/data/snapshot.json", "HELD_DIR": + "/root/.helm/data/held", …}`. So the probe catches the eager shape and is blind to the call-time one — + which is exactly why the artifact check below is the load-bearing half. + +## 3. The fix: the sandbox answers the search, and the artifact is the detector + +Two inserts, one function's worth of code, into the shipped gate (`patch_gate_q56.py`, every anchor asserted +`count == 1` before the write, trailing newline asserted on the written file): + +1. **The seed — prevention.** At the sandbox-creation site, beside `_q43_held.mkdir`, the sandbox is given + its own `.helm/data/held/stackchain-home.html.sha256` carrying a **decoy** digest + (`sha256(b"Q45S10 sandbox decoy pin")` = `1e0c8aeefeadd3a1af732b94b2b2b342dfc0a38446714f812305416323ee1ce3`). + The copy the legs run sits at `/subject-legs.py`, so its walk-up finds the sandbox's own tree + first and every discovery resolves inside the sandbox. A decoy, never the live bytes: the live pin is not + copied into a sandbox. +2. **The artifact check — detection.** One more subject leg writes a snapshot into the sandbox + (`--out /q45s10-artifact.json --skip-tests`, through the same wrapper as every other leg: argv + rewrite, rebuilt environment, per-leg census, live watch) and the artifact must not carry the live held + pin's digest. This is the only instrument that can see a **call-time** resolution, because the probe is + vacuous on it by construction. + +**The pair.** Gate **`c56230e5a075c5a12fd2f0d336dcac71c1078cb692a9e6c995780098a051f13e`** (147,151 B / +**2,798** lines / **127** `check("` registrations — 126 + 1, the new one). `out/DIFF-vs-q55.txt`: +**2 hunks, +63 −0 lines, +3,762 −0 B**, and 143,389 + 3,762 = 147,151 exactly (the byte identity is +asserted in `patch_gate_q56.py`, not printed and hoped). Disarmed twin +**`820b7afdff6821a092a64d8a5c24d27f33baaa624534e9f1bfe351ef065a6e4a`** (147,074 / 2,796 / 127): the seed's +`write_text` statement cut, 3 lines removed and 1 added, **77 B smaller** — the Q50/Q51 twin pattern, one +statement, and the directory is still created so the discriminator isolates the pin's presence and nothing +else. + +## 4. The matrix, 8 cells, every cell under the digest-verified guard + +`run_matrix_q56.py` → `out/Q56-MATRIX.json`; `run_matrix2_q56.py` → `out/Q56-MATRIX2.json`. The guard +(`q56_guard.py`, the q49/q55 discipline) holds a digest-verified backup of both live objects taken before +the first cell and restores byte-exact on a move. + +| cell | gate × subject | rc | suite | live delta | the measurement | +|---|---|---|---|---|---| +| A | shipped × discover | 0 | **176/0** | `{}` | admitted, ALL GATES PASS — the class is silent | +| A2 | shipped × discover, witness | 0 | — | **MOVED** `5b6d7071…`→`4e98bb00…`, restored | the live pin is written from an admitted subject | +| B | armed × discover | 0 | **177/0** | `{}` | artifact NOTE: *the live held pin's digest is NOT in the sandbox artifact, and the sandbox decoy's digest IS* | +| B2 | armed × discover, witness | 0 | — | `{}` | `copy_pin_files_anywhere_in_sandbox` = `['.helm/data/held/stackchain-home.html.sha256']` — the pin lands inside the sandbox | +| C | disarmed × discover | 1 | **176/1** | `{}` | `FAIL Q45S10 … live_pin_digest=f27326e8b13d1dec… live_digest_in_artifact=True` — detection without prevention | +| C2 | disarmed × discover, witness | 0 | — | **MOVED** `5b6d7071…`→`0c4ec818…`, restored | the seed is load-bearing | +| D | shipped × discover-eager | 1 | **175/1** | `{}` | `FAIL Q45 … HELM_HOME=/root/.helm, HELD_DIR=/root/.helm/data/held` — the import-time form is reported | +| D2 | armed × discover-eager | 0 | **177/0** | `{}` | the seeded sandbox resolves even the eager form inside | + +The green pair and the control (`out/Q56-MATRIX2.json`): + +- **G1 — shipped × real collector:** rc 0, 176/0, **14,044 B** stdout — the shipped gate's own historical + baseline, reproduced to the byte. +- **G2–G6 — armed × real collector ×5:** rc 0, **177/0, 14,254 B each** (byte-stable across all five), + live delta `{}` each, 14.1–14.2 s. The real collector's own held read is `/data/held` — the + Q45-rewritten literal, which the seed does not touch — so its snapshot is unchanged in kind; the +210 B + stdout delta is the seed's paths in the Q43 sandbox-census print plus the artifact leg and the new check's + name. **No pre-existing check moved: 176 → 177 is the one new check and nothing else.** +- **Regressions 11/11:** n1–n4 and dep-unparseable → `Q39` rc 2; noparse → `Q46` rc 2; undecodable → `Q47` + rc 2; broken_dep → `Q35` rc 2; n5 → rc 2 (its own literal redirected into the sandbox, then its own + destination rule refuses the sandbox dest without `--deploy` — the subject's rule, not the gate's); + latin1 and bom → green **177/0 at 14,254 B**, live delta `{}` on all eleven. + +## 5. Live state, deployed, sandboxes, disk + +`out/Q56-CENSUS.json` (re-measured, not carried): + +- **Live, delta 0 on bytes/sha256/mtime across all 25 invocations:** snapshot **14,039 B / + `aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d` / mtime_ns `1791479579475780303`**; + held pin **120 B / `5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297` / mtime_ns + `1791478687099553071`**. **ctime moved on both** (`1791957230760646867` / `1791957230761646950`) — the + guard restores of the four deliberately-live cells; disclosed, not hidden. +- **Deployed `/root/.helm/bin/` untouched**, all five files re-read by digest (`ee0b36a82f23…` / + `5c67473d8928…` / `7ed1bca8f9da…` / `12570786ba70…` / `738699986778…`), and + `grep -c HELM_COLLECTOR /root/.helm/bin/helm-selftest.py` = **0** — **Q40 stands, so none of Q31–Q45S9 or + Q45S10 is in production.** +- **Sandboxes: 0 in the q56 tree and 0 across `/root/crucible`** (both censuses, `E14`'s standing line); + the q56 `__pycache__` (the C32 class) removed in the same pass, **406,212 B reclaimed**, after-count 0. +- Disk: **45 G free of 154 (72 %)**. + +## 6. Adoption + +The §4 `cp` is collector **`4e45021d80395d3f…`** + gate +**`c56230e5a075c5a12fd2f0d336dcac71c1078cb692a9e6c995780098a051f13e`** (147,151 B / 2,798 lines / 127 +registrations), superseding `cd43284ff009…` (Q45S9), `78b290ecf2d9…` (Q52/home), `e4967da9…` (Q51) and +`a951dbe8…` (Q50). Alexander's, unchanged. Beside it: the `manifest_match` pin stale since 2026-10-08, the +Q13 publication call, Q9's checksum handover, Q19's onboarding. + +## 7. Limits, and the defects of mine logged first + +**Limits.** (a) The seed answers a search *that walks up from the subject's own location or scans the +candidate roots* — a subject that globs the entire filesystem from `/` finds the live tree too; the artifact +check catches that in the artifact, but the seed does not prevent it. (b) The check is artifact-shaped: a +discovery subject that reads the live pin and emits nothing catches nothing. (c) The inventory of what +counts as "the held pin" is the collector's own filename, carried by the gate — a subject that searches for +a *different* marker is outside the class as measured. (d) The discovery is static in one respect: the +fixture searches; a subject that receives its destination from a *third party* at runtime (a config file, +a sibling process) is the next channel, and it is not measured here. + +**Defects of mine, in the order they happened.** (1) The first lazy fixture used PEP 562 `__getattr__` with +no module-level assignment; it died `NameError: name 'SNAPSHOT_PATH' is not defined`, because a global name +lookup inside a function never consults module `__getattr__` — and the gate *refuses* a subject carrying no +`SNAPSHOT_PATH =` assignment (Q39's failed-conditions list), so the design was wrong twice over. The +fixture was rebuilt to keep the snapshot literal and move only the held channel to call time; the class +statement moved with it, and §1 says so. (2) `patch_gate_q56.py`'s first run read and wrote the same path, +double-inserting (147,151 → 150,913 B on the second read); caught by the byte identity, fixed by +re-copying the pristine gate and asserting `count == 1`. (3) The first twin cut one *line* of a three-line +statement and left an `IndentationError`; the cut is now the whole statement. (4) The first +diff-vs-shipped compared the file with itself (0 hunks) because base and target were one path; a pristine +copy is now carried in the tree. (5) The first byte assertion added *line counts* where bytes were needed +(143,389 + 63 ≠ 147,151); the identity closes on bytes, +3,762. (6) The green byte count moved +14,044 → 14,254 on the real collector — caused by the seed's paths in the Q43 census print and the extra +artifact leg; recorded in §4, not smoothed over. + +— Merlin (Run 24)