Q39: the destination guard's admission is keyed on the subject's own destination, and every leg is watched (Helm lane)

Five repairs to the Q38 gate (74aba348 -> 9b09f328, +309/-38): the probe injects
from pathlib import Path so the rewritten line cannot NameError; EVERY SNAPSHOT_PATH
assignment is rewritten; a probe that dies with a traceback is refused; an ast scan
refuses an absolute path literal resolving inside /root/.helm/data/; and live bytes
and mtime are read around every subprocess and around the subject's in-process
import, a change dying the run and restoring the bytes it read.

Negative controls (q39-negatives.py, Q39-NEGATIVES.json): five fixtures, each run
under BOTH gates. n1 (the incident's shape) and n2 (a probe that dies with a
traceback) are ADMITTED by the Q38 gate - n1's in-process import writes the
fixture's destination inside the gate's own run - and refused by the Q39 gate.
Green pair: 5 consecutive invocations, rc 0, 164 passed / 0 failed, 17 legs
watched, live delta 0 on every run. Live snapshot aa842b0f delta 0 throughout;
nothing deployed, decisions/ and inbox/ untouched.
This commit is contained in:
Merlin committed 2026-10-12 09:32:18 +00:00
1 parent f57c0e74fa
commit fad802c0f5
3 files changed
+271

No files matched your search

+10
View File
@@ -5155,3 +5155,13 @@ Read from source and from the forge API, not from the PR's narrative.
**The four fix candidates, in priority order, from reply 21:** key admission on the subject's own **resolved destination** (refuse anything resolving inside `/root/.helm/data/`, and refuse a probe whose stderr carries a traceback rather than a refusal); rewrite **every** `SNAPSHOT_PATH =` assignment and make the probe independent of the subject's imports (`from pathlib import Path` injected, or `__import__('pathlib').Path(...)`); stop running the original subject in the legs, or assert live bytes **and** mtime after every leg; add the negative control for the class.
**Evidence to hand:** `replies/2026-10-12-to-merlin-21.md`; `/root/troupe-verify/q38/` (my reproduction, `containment/`); `/tmp/hermes-probe/` (the incident's probe, fixtures, transcript and restore, mtimes 07:17–07:18Z); commit `8d2b56c` and this file's Q38 section. **Not in scope:** re-litigating the delivered transcripts — they reproduce exactly; the defect is in the criterion and the leg path, not in the measurements.
**Status: DONE — `recoveries/helm-destination-guard-fix.md` (12,253 B), Merlin, 2026-10-12, scratch tree `/root/crucible/q39/`. Fixed gate `9b09f328…` (1,412 lines / 77,704 B, +309/−38 against Q38's `74aba348…`); subject collector byte-identical at `4e45021d…`; nothing deployed, no `cp` into `/root/.helm/bin/`, live snapshot `aa842b0f…` delta 0 across every run.**
- **Five repairs:** (1) the probe injects `from pathlib import Path` above the subject's body, so the rewritten line cannot NameError on a subject that never imported it (C22's mechanism); (2) **every** `SNAPSHOT_PATH =` assignment is rewritten, not the first; (3) a probe whose stderr carries a traceback is refused — a crash is not a refusal; (4) an ast-based destination-resolution scan refuses any **absolute** path literal in the subject that resolves inside `/root/.helm/data/` (docstrings excluded by a walk that does not descend into `Expr`, which is why the deployed collector's *composed* live path is admitted); (5) live **bytes and mtime** are read around every `subprocess.run` and around the subject's in-process import, a change dying the run with exit 2 and **restoring** the bytes it read.
- **Negative controls, all refused with stdout 0 B, live delta 0, no probe dir left:** `n1-incident-shape` (probe rc=0, sentinel written 2 B) — **Q38 admits it, rc 0, and its in-process import writes the fixture's destination inside the gate's own run**; `n2-traceback` (traceback condition) — **Q38 admits it and then crashes at the import, rc 1**; `n3-decoy` (sentinel written) — **Q38's probe writes the decoy's *real* destination, the containment failure reply 21 measured**; `n4-comment-only`; `n5-live-literal` (absolute-literal rule) — Q38 admits it. `Q39-NEGATIVES.json` at 2026-10-12T09:28:09Z.
- **Green pair, 5 consecutive invocations:** rc 0, `helm-selftest: 164 passed, 0 failed`, `VERDICT: ALL GATES PASS`, `Q39 OK` with probe rc=2, `Q39: 17 legs watched … delta 0 on each`, live delta 0 on all five; the five log digests are in the record.
- **Leg watch measured both ways** against a scratch watched file (`q39-legguard-test.py`, guard extracted by its own BEGIN/END markers): clean leg passes and counts; a leg whose subprocess writes the watched file exits 2, restores bytes **and** mtime, and prints both digests.
- **Two self-corrections logged:** a three-tuple state including atime made every leg fail (reading updates atime) — the state is `(bytes, mtime_ns)`; and the summary line moved from stderr to a flushed stdout `print` because the two streams interleave into one log.
- **Limits:** the static scan is literal-based; repair 4 refuses a legitimate absolute-literal shape (a design decision, not a measurement); the legs still run the original subject, so repair 5 detects-and-restores rather than prevents; the timeout branch and the direct-CLI limit from Q38/Q35 are unchanged; 5 fixtures are not a census.
- **Adoption, Alexander's as before:** the pair is collector `4e45021d…` + gate `9b09f328…`; deployed bin unmoved (`helm-collect.py` `ee0b36a8…`, `helm-selftest.py` `7ed1bca8…`); public page 200 / 9,865 B / `427b7b54c69b18d2…` at 2026-10-12T09:29:03Z; `decisions/` and `inbox/` untouched.
- **Q7, measured:** the archive lane's unclaimed executable set is still empty (Q9 audio handover, Q13/Q19 Alexander); the Helm lane's open items are Q31 (`cp` decision) and Q34-adjacent gates, all gated on the same adoption call. **No new item opened this tick** — the queue is not thin and the lane's next unit is a decision, not a task.
+96
View File
@@ -467,3 +467,99 @@ authored `Merlin <merlin@agents.invalid>` (`git -c`), so the monitor sees them a
content per Q36's v1.2 rule.
— Merlin
---
## Run 5 — Q39: the admission admits a writer, and its legs run the unrewritten subject
**Did.** Claimed **Q39**, opened by the pipe on Run 4's falsified protective claim (reply 21, C22/C23) —
the top open item and the only executable work in the queue: the archive lane's unclaimed set is empty
(Q9 waits on the audio handover, Q13/Q19 on Alexander), and the Helm lane's remaining items are all
gated on the same adoption call. Deliverable `recoveries/helm-destination-guard-fix.md` (12,253 B);
fixed gate `/root/crucible/q39/helm-selftest.py` **1,412 lines / 77,704 B / sha256
`9b09f3283008e695bb0634bc2d5492f2c24067b9eeb9ee2100099b7cbfcd1429`**, **+309 / −38** against Run 4's
`74aba348…` (1,141 / 64,454 B); `DIFF.txt` 408 lines / `b8adc9126397f61a…`; subject collector
byte-identical to the Q34/Q35/Q38 pair (`4e45021d…`).
Five repairs, each with a measurement behind it: (1) the probe injects `from pathlib import Path` above
the subject's body, so the rewritten line cannot `NameError` on a subject that never imported it — C22's
mechanism, removed rather than detected; (2) **every** `SNAPSHOT_PATH =` assignment is rewritten, not the
first; (3) a probe whose stderr carries a traceback is refused, because a crash is not a refusal; (4) an
ast scan refuses any **absolute** path literal in the subject that resolves inside `/root/.helm/data/` —
docstrings are excluded by a walk that does not descend into `Expr` nodes, which is why the deployed
collector's *composed* live path is admitted (`assign line 30: SNAPSHOT_PATH <- 'data' / 'snapshot.json'
-> resolves inside the live data root: /root/.helm/data/snapshot.json`, printed on every green run);
(5) live **bytes and mtime** are read around every `subprocess.run` and around the subject's in-process
import, a change dying the run with exit 2 and **restoring** the bytes it read.
**Measured, not asserted** — `python3 /root/crucible/q39/q39-negatives.py` →
`RESULT: ALL NEGATIVE CONTROLS REFUSED AS EXPECTED`, `Q39-NEGATIVES.json` at 2026-10-12T09:28:09Z. Each
fixture runs under **both** gates, so every row is a discriminator; the fixtures' destination files are
deleted before each run so "created" is per-run:
| fixture | Q39 exit | Q39 condition named | Q38 exit | Q38 admitted? | side-effect files created (Q39 / Q38) |
|---|---|---|---|---|---|
| `n1-incident-shape` (the incident's shape) | 2 | probe rc=0, sentinel written 2 B | **0** | **yes** | `[]` / `['n1-dest']` |
| `n2-traceback` (raises at import) | 2 | `the probe died with a traceback …` | 1 | **yes** | `[]` / `[]` |
| `n3-decoy` (decoy first assignment) | 2 | probe rc=0, sentinel written 2 B | 2 | no | `[]` / `['n3-real']` |
| `n4-comment-only` (markers in the docstring) | 2 | probe rc=0, sentinel written 2 B | 2 | no | `[]` / `[]` |
| `n5-live-literal` (proper refusal, live path as a literal) | 2 | `names the live destination as an absolute literal` | 2 | **yes** | `[]` / `[]` |
Every Q39 run: stdout 0 B, live delta 0, no `helm-q39-*` probe directory left behind. `n1` is the
incident's own shape: **Q38 admits it, and the gate's in-process import writes the fixture's destination
inside the gate's own run.** `n3` reproduces reply 21's containment finding — Q38's probe writes the
decoy's **real** destination; Q39 writes nothing.
**Green pair, 5 consecutive invocations** (`bash /root/crucible/q39/run-green.sh 5`): rc 0 each,
`helm-selftest: 164 passed, 0 failed`, `VERDICT: ALL GATES PASS`, `Q39 OK … (probe rc=2, sentinel
written=False, other probe files=0, no traceback, live delta 0)`, and `Q39: 17 legs watched … delta 0 on
each`. Log digests: `f0bfaca19d5d2a56…` / `a13a184de21a45a7…` / `e305e9f7dfd5fdc9…` /
`0b2343b6a2fb64bd…` / `eaaf90e14ba85777…`. The leg watch itself is measured both ways
(`q39-legguard-test.py`, guard extracted from the shipped gate by its own `Q39-LEG-GUARD-BEGIN/END`
markers, lines 416–474 / 2,207 B, run against a **scratch** watched file): a clean leg passes and counts;
a leg whose subprocess writes the watched file exits **2**, restores bytes **and** mtime, and prints both
digests (`aef3121c6c5097a3…` before, `8ddb948bf967125e…` after).
**Three instrument defects of mine, logged first.** (1) A three-tuple live state including **atime** made
every leg refuse — reading the file updates atime on this filesystem — so the state is `(bytes,
mtime_ns)`. (2) The Q39 summary line on stderr landed concatenated onto the last `PASS` row (stdout is
block-buffered when redirected); it is now a flushed stdout `print`. (3) Twenty empty `helm-q39-*` probe
directories were left by the runs that crashed with `NameError` during the build (four `_q38_*` names had
been renamed to `_q39_*` in the setup block but not in the body); removed by `cleanup-temp.py` — 20 dirs,
0 kept — and the final runs leave none.
**Live state, delta 0 across every run in this item.** `/root/.helm/data/snapshot.json` **14,039 B /
`aa842b0fd88037f8…` / mtime_ns `1791479579475780303`**. Deployed bin unmoved: `helm-collect.py`
`ee0b36a82f23fcf3…`, `helm-selftest.py` `7ed1bca8f9da624f…`, `helm-render.py` `5c67473d89283c3d…`.
Public page `https://alexanderwhitestone.com/helm/` **200 / 9,865 B / `427b7b54c69b18d2…`** at
2026-10-12T09:29:03Z. `/root/stackchain-legends-build/build_blocks.py` still `97fedb5dd5e85d2b…`, nothing
under that tree modified since 2026-10-11 08:00Z. `decisions/2026-09-26.md` `40b7cc14a829…` and
`inbox/seed-2026-09-26.json` `e4429147bc1b…` unchanged. No another-party file edited; no secret printed.
## Blocked
Nothing. One limit named rather than buried: repair 5 is **detect-and-restore, not prevention** — the
legs still run the original subject. Running the legs against a rewritten copy is the stronger form and
is not built.
## Next
1. **The stronger form, if you want it:** run the legs against a copy of the subject with every
destination rewritten, so an admitted writer can never execute against live. Measured effort: the
rewrite already exists in the probe path; the legs' `COLLECTOR` references would point at it.
2. **Q37 is open and unclaimed** — can this pipe distinguish its own commits from a counterparty's pushes
under its credential? It is the only queue item with no human in front of it, and it is the pipe's
tooling, not mine. I am not taking it without your nod, because it is Timmy's lane.
3. No new queue item opened: the Helm lane's next unit is the adoption decision, not capacity.
## Ask
Alexander — the adoption call Run 4 asked for is now sharper, because the gap is measured rather than
argued: **the gate in production today (`7ed1bca8…`) admits `n1` and `n2`**, the two classes that wrote
the live snapshot on 2026-10-12, while the fixed gate (`9b09f328…`) refuses both before any leg. The pair
is collector `4e45021d…` + gate `9b09f328…`, a one-file `cp` plus the collector. Say **adopt**, **hold**,
or **build the stronger form first** — my recommendation is adopt-with-the-stronger-form as the next
unit, since the fixed gate already removes the two measured holes and the stronger form closes the last
one. Nothing else is blocking.
— Merlin
+165
View File
@@ -0,0 +1,165 @@
# Q39 — the destination guard's admission admits a writer, and its legs run the unrewritten subject
**Merlin, 2026-10-12, this host. Scratch tree `/root/crucible/q39/`. Nothing deployed, nothing published, no
`cp` into `/root/.helm/bin/`, `decisions/` and `inbox/` untouched.**
Q38 delivered a behavioural destination guard and the pipe falsified its protective claim the same day
(`replies/2026-10-12-to-merlin-21.md`, corrections C22/C23). This item is the repair. The fixed gate is
`/root/crucible/q39/helm-selftest.py`, **1,412 lines / 77,704 B / sha256
`9b09f3283008e695bb0634bc2d5492f2c24067b9eeb9ee2100099b7cbfcd1429`**, a **+309 / −38** unified diff against
Q38's gate (`74aba348…`, 1,141 lines / 64,454 B); `DIFF.txt` 408 lines / sha256 `b8adc9126397f61a…`. The
subject collector is byte-identical to the Q34/Q35/Q38 pair (`4e45021d…`, 720 lines / 29,954 B).
## 1 What was broken, restated from the falsification
| # | Defect | Mechanism | Consequence measured by the pipe |
|---|---|---|---|
| C22 | the probe injected `SNAPSHOT_PATH = Path(<sentinel>)` and `Path` lives in the **gate's** namespace, not the subject's | a subject importing `pathlib` without the name raises `NameError` inside the probe → rc=1, nothing written, live delta 0 → **admitted** | a writer reached the legs |
| C23 | only the **first** `SNAPSHOT_PATH =` line was rewritten, and the legs run the **original** subject | the probe tested a destination the subject does not use; the legs then executed the subject against its live default | 2026-10-12T07:18Z: the live snapshot became `{}` (2 B / `44136fa3…`) inside the gate's own run, while the gate printed `live delta 0` |
## 2 The five repairs, with line numbers in the fixed gate
1. **The probe is import-independent** (`:330` rewrite loop, `:333–338` preamble). The probe file is now the
subject's source with an injected `from pathlib import Path` **above** the body, so the rewritten line
cannot `NameError` on a subject that never imported the name. This is the C22 mechanism removed rather
than detected.
2. **Every** `SNAPSHOT_PATH =` assignment is rewritten, not the first (`:330` loops over `_q39_assign`).
A decoy first assignment can no longer hide the real destination from the probe.
3. **A crash is not a refusal** (`:356–358`, condition at `:380–381`). A probe whose stderr carries
`Traceback (most recent call last)` is refused. Q38's own injection was the class that produced exactly
that stderr, which is why this condition and repair 1 are both needed.
4. **The destination-resolution scan** (`:225–302`, refusal at `:304–320`). Every `SNAPSHOT_PATH =`
assignment is parsed with **ast** (not regex) and every **absolute** path literal in the subject's
source is resolved — cumulatively onto three bases (the subject's directory, the live data root's
parent, the cwd) — and refused if it lands inside the live data root. Bare string statements
(docstrings) are excluded by a walk that does not descend into `Expr` nodes (`:236–249`), which is why
the deployed collector is admitted: its live path is **composed** (`HELM_HOME / "data" /
"snapshot.json"`, `helm-collect.py:29–30`) and never written as one absolute literal. The report is
printed on both the refusal and the green path.
Measured on the gated collector, every green run:
`assign line 30: SNAPSHOT_PATH <- 'data' / 'snapshot.json' -> resolves inside the live data root:
/root/.helm/data/snapshot.json`
5. **Every leg is watched** (`:415–474`, markers `# Q39-LEG-GUARD-BEGIN/END`; import watch at
`:1047–1049`; summary at `:1407`). Live **bytes and mtime** are read around every `subprocess.run`
the gate spawns and around the subject's in-process import; a change dies the run with **exit 2**,
prints both digests, and **restores the bytes it read** (plus the mtime). Q38 read live once before the
legs and once at the end and summarised the difference — C23 is that a mid-run write is invisible to
that.
Two self-corrections made while building this, logged rather than hidden:
- the first `_q39_live_state()` returned `(bytes, mtime_ns, atime_ns)` and **every leg failed**: reading
the file updates its atime on this filesystem, so a three-tuple comparison flags a clean leg as a
change. The state is `(bytes, mtime_ns)` (`:431–438`); the requirement is live bytes **and** mtime, and
mtime is the stamp a writer moves.
- the Q39 summary line was first written to stderr and landed concatenated onto the last `PASS` line when
both streams go to one file (stdout is block-buffered, stderr is not). It is now a `print` after
`sys.stdout.flush()` (`:1405–1411`), and the `Q39 OK` line flushes stdout first (`:405`).
## 3 The negative-control suite — five refusals, each re-run under Q38 as the discriminator
`python3 /root/crucible/q39/q39-negatives.py` → `RESULT: ALL NEGATIVE CONTROLS REFUSED AS EXPECTED`,
`Q39-NEGATIVES.json` written at 2026-10-12T09:28:09Z, gate digest inside it matching the file above.
The suite resets the fixtures' destination files first, so "created" is measured per run, not inherited.
| fixture | Q39 exit | Q39 condition named | Q38 exit | Q38 admitted? | side-effect files created (Q39 / Q38) |
|---|---|---|---|---|---|
| `n1-incident-shape` (the incident's shape: writes at import, imports `pathlib` not `Path`) | 2 | `the probe did not refuse (rc=0); the probe wrote the sentinel (2 B)` | **0** | **yes** | `[]` / `['n1-dest']` |
| `n2-traceback` (raises at import) | 2 | `the probe died with a traceback, which is a crash, not a refusal` | 1 (crashed at the import) | **yes** | `[]` / `[]` |
| `n3-decoy` (first assignment a decoy, real destination on the next line) | 2 | `the probe did not refuse (rc=0); the probe wrote the sentinel (2 B)` | 2 | no | `[]` / `['n3-real']` |
| `n4-comment-only` (markers in the docstring, no rule) | 2 | `the probe did not refuse (rc=0); the probe wrote the sentinel (2 B)` | 2 | no | `[]` / `[]` |
| `n5-live-literal` (refuses its default properly, names the live path as an absolute literal) | 2 | `names the live destination as an absolute literal` | 2 | **yes** | `[]` / `[]` |
Every Q39 run: **stdout 0 B, live delta 0** (bytes and mtime), no `helm-q39-*` probe directory left
behind. Two of the five are the C22/C23 classes Q38 got wrong, and both are admitted by Q38 to this day —
`n1` is admitted **and** its in-process import writes the fixture's destination inside the gate's own run,
`n3`'s probe writes the decoy's **real** destination inside the probe, which is the containment failure
reply 21 measured. Under Q39 neither file is created.
## 4 The leg watch, measured both ways
`python3 /root/crucible/q39/q39-legguard-test.py` extracts the shipped guard **by its own
`# Q39-LEG-GUARD-BEGIN/END` markers** (lines 416–474, 2,207 B) and runs it against a **scratch** watched
file, because the live snapshot cannot be clobbered to prove a clobber is caught:
```
clean leg: rc=0 watch_calls 0 -> 1 bytes_unchanged=True
writing leg: exit_code=2 restored=True mtime_ns 1791797218872835164 (original 1791797218872835164)
refusal: Q39 REFUSAL: a leg's subprocess (… open('/tmp/q39-legguard-669_7xhk/snapshot.json',
'w').write('CLOBBERED')) changed the live snapshot - sha256 aef3121c6c5097a3… before,
sha256 8ddb948bf967125e… after; the before-bytes were restored and the run is refused.
RESULT: LEG WATCH MEASURED BOTH WAYS
```
## 5 The green pair — 5 consecutive invocations
`bash /root/crucible/q39/run-green.sh 5`, `HELM_COLLECTOR=/root/crucible/q39/helm-collect.py`:
```
run 1..5 rc=0 live_delta=0 pass_lines=164 legs_watched=17 q39_ok_lines=1
live=aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d
mtime=2026-10-08 17:12:59.475780303 +0000
```
Each log carries `Q39 OK: … (probe rc=2, sentinel written=False, other probe files=0, no traceback, live
delta 0)`, the destination-resolution report, `helm-selftest: 164 passed, 0 failed`, `VERDICT: ALL GATES
PASS`, and `Q39: 17 legs watched … delta 0 on each`. Log digests:
```
f0bfaca19d5d2a56c42e8bd3b7c112c076544dfe90e9d874b395a29219604be5 green-run-1.log
a13a184de21a45a72ed4ec2409e5aa969dc18591752b82d5fac256a1cfad99a0 green-run-2.log
e305e9f7dfd5fdc9d8a34bc10ccbc4a3d3f0f0c1feb77863b376a66437771b70 green-run-3.log
0b2343b6a2fb64bd5078a7ecef5fcfbdfb5e9e0f9271cb4cdc11626f5a7e9d8a green-run-4.log
eaaf90e14ba8577749c718d5430ec2cd969a1bad07839bfc3826baded16efad9 green-run-5.log
```
**17** legs is the count of `subprocess.run` calls the gate makes on the green path (10 in the Q38 gate's
own text plus G7's renderer runs), each watched individually — the number is printed so the watch is not
vacuous.
## 6 Live state and what was not touched
- `/root/.helm/data/snapshot.json` **14,039 B / sha256 `aa842b0fd88037f8…` / mtime_ns
`1791479579475780303`** before and after every run in this item — 5 green, 5 fixtures × 2 gates, the
leg-watch test, and the cleanup. **Delta 0 throughout.**
- `/root/.helm/bin/` unmoved: `helm-collect.py` `ee0b36a8…` (the deployed pre-Q35 collector — it carries
no destination rule, which is why the gate's default `HELM_COLLECTOR` is refused at Q35 and the gated
pair is named explicitly), `helm-selftest.py` `7ed1bca8…`, `helm-render.py` `5c67473d…`,
`helm-validate.py` `12570786…`, `summarize.py` `73869998…`. **No `cp` was made; adoption stays
Alexander's.** The adoption pair is now collector `4e45021d…` + gate `9b09f328…`.
- Public page `https://alexanderwhitestone.com/helm/` **200 / 9,865 B / sha256
`427b7b54c69b18d270288910fc810732463129f48ec4bdd7dbc75cdb22997ce4`** at 2026-10-12T09:29:03Z — the
Q38 record's figure.
- `/root/stackchain-legends-build/build_blocks.py` still `97fedb5dd5e85d2b…`, nothing under that tree
modified since 2026-10-11 08:00Z (`find … -newermt` → 0 files).
- `decisions/2026-09-26.md` `40b7cc14a829…` and `inbox/seed-2026-09-26.json` `e4429147bc1b…` unchanged and
not opened for content. No other party's file edited. No secret printed.
## 7 Limits, stated
- **The static scan is literal-based.** A subject that composes the live path from a variable the scan
cannot see, or reads it from the environment, is not caught by repair 4; the behavioural probe and the
leg watch are what cover it, and the leg watch is detection-with-restore, not prevention.
- **Repair 4 refuses a legitimate shape.** A subject that names the live snapshot as one absolute literal
— even one that guards it properly — is refused. That is the conservative reading and it is a design
decision, not a measurement: the gate cannot redirect a path that is not the module constant.
- **The legs still run the original subject.** Repair 5 makes a live write fatal to the run and restores
it; it does not stop the subject from executing with its live default. Running the legs against a
rewritten copy would be the stronger form and is not built.
- **The probe substitution still touches one module constant.** A subject that resolves its destination
by another route is not covered by the rewrite (Q38's limit, unchanged); the live-delta assertion
catches an actual write only after the fact.
- **The timeout branch is coded and not exercised** (Q38's limit, unchanged).
- **The guard protects the gate's legs, not a direct CLI run** of a pre-gate collector (Q35's limit,
unchanged).
- 5 fixtures are the item's own four classes plus the decoy containment case; they are not a census of
subject shapes. Byte counts and digests are dated readings from this host, 2026-10-12 ~08:5x–09:3xZ.
## 8 What is left for Alexander
The same gate as Q38: **do not `cp` `9b09f328…` into `/root/.helm/bin/` without a decision**, and note
that the shipped state is now measurably the weaker one — pre-Q39, a subject that carries no destination
rule is refused at Q35 but a subject that *documents* one is admitted and executed; with `9b09f328…` the
four classes above die before any leg. The publish precondition the queue already carries stands:
**adopt the fixed gate into the shared tree first, then publish** — and it is a one-file change plus the
collector, not a build change.