Taken on the pipe's own offer (reply 34, asks 1). The Q48 value-redirect and Q49
default-redirect are factored into _q50_rebuild_env(_target) and called twice: at the
rule's original site for the legs (target the legs' sandbox) and above the admission
probe's spawn for the probe (target the probe's own tree, which exists before the
spawn -- the legs' sandbox does not). The spawn now carries env=, and a per-window
census of both live objects around the spawn is the class's detector: a move is
restored byte-exact in-gate, recorded, printed as a dated Q50 DETECTOR note, and
fails the named check "Q50 the admission probe's spawn moved neither live object".
Measured, all five matrix cells under a digest-verified guard (subject env-root-v1.py):
base-q49 x named MOVED held pin 120 B / 5b6d7071... -> 14 B / 784b9bde..., guard-restored
q50-armed x unset delta 0 0 value + 1 default redirect
q50-armed x named delta 0 1 value redirect -- the blank cell, filled
q50-dis x unset delta 0 the probe copy's own Q45 literal relocation covers the
default shape; the redirect is load-bearing only in the named cell
q50-dis x named delta 0 the DETECTOR fires: pin moves inside the gate, restored
byte-exact, foot prints FAIL Q50 (165/10 vs armed 166/9)
Green 5 x rc 0 / 175 passed / 0 failed (174 + 1) / 13,929 B / live delta 0.
Regressions 11/11 hold (n1-n5, noparse, dep-unparseable, undecodable, broken_dep rc 2;
latin1 and bom green 175/0). Live objects byte-identical to session start on
(bytes, sha256, mtime_ns); deployed bin untouched (ee0b36a8... / 7ed1bca8...,
HELM_COLLECTOR count 0 -- Q40's finding stands). Named follow-on, not fixed here:
hoist the run-wide held census above the probe. Three harness defects of mine logged
first in the record. Nothing deployed; no another-party file edited; no secret.
The record's deferred table and the check-in's deferred line are filled from the
anonymous raw read at main, taken after the push (a pre-push readback returns 404
for a new file), so the figures are stable for any outsider. All three HTTP 200
and byte-identical to disk.
- (a) ATTRIBUTION, measured not withdrawn. env-root-v1.py = q48/env-root.py with its
two default literals returned to /root/.helm (asserted count 2). Under a
digest-verified guard: the fixture run --dry-run / bare / --deploy --out <scratch>
with Q48_ROOT UNSET each moved the live held pin, and
HELM_COLLECTOR=<that fixture> Q48_ROOT unset python3 q48/helm-selftest.py moved it
too. All three Q48_ROOT=<scratch> controls: no move. Written bytes measured by a
5 ms watcher: 14 B / sha 784b9bded20e9e22... / 'q48-env-pin\n'. Q48's 6.2
attribution is upheld as a measurement; the pipe's negative reproduces exactly.
The writing leg is named verbatim by the per-leg census: the G8 --dry-run
original-subject leg, whose own source comment asserts "it writes nothing".
- (b) THE CLASS IS CLOSED, green 5/5. helm-selftest-q49.py (128,948 B / 2,445 lines /
085ddf4f42ae80ea...): the DEFAULT redirect (every os.environ.get("X","<default>")
pair inventoried by ast; a default literal resolving inside the live data root is
redirected to the per-invocation sandbox), a per-leg census of BOTH live objects as
detection, and a guard on the in-process --deploy leg. Checks 120 -> 123
(+3 check("Q49"), nothing else moved). Five green runs: rc 0, 174 passed /
0 failed, 13,863 B stdout, digests 13cf5cf7 / d4666b9f / 0abd28cd / 5ed81c37 /
bbbd1901, live delta 0 on both objects.
- TWO FINDINGS BEYOND THE ITEM. (i) G8's --deploy branch calls hcg.main() IN-PROCESS
with only SNAPSHOT_PATH patched, so a subject that resolved its root at import time
wrote the LIVE SNAPSHOT (14,039 B -> 137 B) -- reproduced, restored, and now
guarded. (ii) In the fully disarmed configuration the live pin still moves and no
spawn the traced instrument can attribute it: one fixture main() per run, banner
naming the sandbox, both censuses silent, watcher still seeing 120 B -> 14 B at
t+280 ms. The write is real, the mechanism is UNATTRIBUTED, and it is named as the
Helm lane's next unit rather than guessed at.
- Six live writes under guard, every one restored from a digest-verified backup that
refuses to restore unless the backup digest matches. Both live objects byte-identical
at session end: snapshot aa842b0fd88037f8... / 14,039 B and held pin
5b6d70716153c3f4... / 120 B. Nothing deployed: /root/.helm/bin/helm-selftest.py is
still 7ed1bca8... and reads HELM_COLLECTOR 0 times, so none of Q31-Q49 is in
production and the cp of collector 4e45021d... + gate 085ddf4f... stays Alexander's.
Deliverable: recoveries/helm-resolved-root-live-path.md (15,220 B).
Scratch tree /root/crucible/q49/. Record, check-in Run 15 and queue block.
The second-instrument rows for all fifteen discriminator rows and the four regression rows; the E6 mechanism
correction (Q39 compiles the subject's text at legacy/q39:273 -- record-and-continue, not avoidance) with its two
supporting figures (164 = Q39's suite size on the plain collector too; the BOM stderr is the shorter one because
the dropped tree suppresses the assignment rows); the E5 residual logged, one unannotated 109,643 at
checkins/2026-10-13-merlin.md:27; the capture-identity check Q47's green digests pass and Q46's failed; Q40
re-measured (deployed gate 7ed1bca8 reads HELM_COLLECTOR zero times), so the adoption pair 4e45021d + 76f2292b
remains the only path into production; and no new item opened with the reason stated rather than implied -- the
runtime-declared path class is held as a limit, not a measurement, and its measurement would aim a subject at the
live snapshot (14,039 B / aa842b0f), where a miss writes the live file and a restore would move the mtime_ns and
ctime_ns values three records cite as deltas. No lane is dry.
The pair reproduced (gate 76f2292b, 115,182 B / 2,124 lines; collector 4e45021d, 720 / 29,954, byte-identical
across the q46 and q47 trees), the diff decomposition reproduced (130 = 2 file + 4 hunk + 96 added + 4 removed +
24 context; 2,032 + 96 - 4 = 2,124; my 128 non-header lines byte-identical to his out/DIFF-vs-q46.txt), the three
read-path rows re-run directly with HELM_COLLECTOR (latin1 rc 0 / 169 passed / 13,312 B / iso-8859-1 NOTE; bom
rc 0 / 169 / 13,312 B / utf-8-sig NOTE; undecodable rc 2, stdout 0 B, dated refusal, no traceback, no leftover),
the legacy controls (Q39-bom green 164 at 11,398 B; Q43/Q44/Q45 rc 1 with sandboxes left; Q39/Q43/Q45 rc 1 on
latin1 and on undecodable), the regressions (noparse rc 2 with the dated Q46 REFUSAL; n1-n5 all rc 2), the five
green digests checked field by field against the .out files (the Q46 capture-identity trap not repeated), and
live delta 0 across every invocation.
One correction, E6: Q39 does compile the subject's text (legacy/q39/helm-selftest.py:273, caught at :275-276 and
printed at :393/:412) -- the class is what a gate does with the failed parse, not whether it parses; Q39's 164 is
its suite size, not a BOM casualty. E5's residual logged (the unannotated 109,643 at
checkins/2026-10-13-merlin.md:27). His three Alexander-facing asks relayed; the runtime-declared path follow-on
left named and unclaimed with the reason no item was opened.
The subject's source is now read the way CPython reads it: bytes through
tokenize.detect_encoding (BOM stripped, PEP 263 cookie honoured), with a
dated exit-2 refusal for a file that cannot be read that way, at Q46's
guard point — after Q35's precondition, before the admission probe,
before any leg, before any sandbox. All four subject-source reads route
through the one reader; one stderr NOTE when the encoding is not plain
utf-8; the Q46 parse guard, the Q45 redirect, every check() and the 169
count untouched.
Deliverable recoveries/helm-read-path-guard.md (12,821 B), scratch tree
/root/crucible/q47/, evidence out/Q47-NEGATIVES.json (21 rows),
out/Q47-VERDICT.json, out/Q47-GREEN.json, out/DIFF-vs-q46.txt.
Measured, not asserted: latin-1 cookie subject rc 0 / 169 passed / ALL
GATES PASS under the shipped gate (Q39-Q45 crash with UnicodeDecodeError);
BOM'd collector rc 0 / 169 passed (Q43/Q45 SyntaxError at the sandbox
copy, Q44 AttributeError, sandboxes left); genuinely undecodable subject
rc 2 with the dated Q47 REFUSAL and no sandbox. Q39 runs the BOM subject
green with 164 passed — the read-path class is the text-compiling gates
(Q43-Q46), not subject handling generally. Green pair 5x rc 0, 169/0,
13,312 B stdout / 425 B stderr, live and held delta 0 on all 26
invocations. Adoption pair moves to collector 4e45021d + gate 76f2292b.
Nothing deployed, no cp into /root/.helm/bin/, decisions/ and inbox/
untouched, no another-party file edited, no secret. Run 13 in the
check-in; queue block appended.
An unparseable subject is refused with exit 2 and a dated message naming the
parse failure, not admitted-then-crashed. Discriminator on all five gates,
digest-identical to the revision history: Q39 rc 1 SyntaxError at the legs
import of the original subject, Q43 rc 1 SyntaxError at the sandbox-copy
import, Q44 rc 1 AttributeError at the unguarded _q39_tree.body, Q45 rc 1
SyntaxError at the sandbox-copy import, Q46 rc 2 dated refusal with stdout 0
B and no sandbox created. dep-unparseable refused by Q39 repair 3 on all five
gates. C2 reproduced: the ROOT glob sees no leftover while the recursive
census sees legacy/q4X/helm-legs-*. Green pair 5x rc 0, 169 passed, 13,312 B,
live delta 0; atexit sandbox cleanup closes the n5 leak measured before and
after. Live snapshot aa842b0f 14,039 B and held pin 5b6d7071 delta 0 across
27 invocations. Adoption pair is now collector 4e45021d + gate ae69d5dd.
One rule replaces Q44's two: every absolute path literal in the subject that
resolves inside the live data root is relocated to the same relative path inside
the per-invocation sandbox, on the parsed node's own span, wherever in the module
it sits and whatever the constant holding it is called. Q44's HELM_HOME =
assignment rewrite is subsumed, not removed; the SNAPSHOT_PATH rewrite (Q39/Q43's
mechanism) is kept. Q39's literal refusal is retired for this class and its reason
printed where the refusal stood -- the refusal's own text said the rewrite "cannot
redirect a path that is not the module constant the rule keys on", which is the
statement Q45 makes false.
Gate 2bbca218871bc5613e1fe3c4d3a84fe2e6da05ffc526e51b2865a8c8ad00ee5e (105,477 B /
1,942 lines) against Q44's 18580c102ddb1c3f (94,819 / 1,731); diff = 426 lines =
2 file headers + 7 hunk headers + 284 added + 73 removed + 60 context, sums exactly;
1,731 + 284 - 73 = 1,942. Collector byte-identical to Q44's 4e45021d80395d3f
(measured by sha256 comparison, not asserted).
Green pair 5 consecutive: rc 0, 13,312 B stdout each, 169 passed / 0 failed,
VERDICT: ALL GATES PASS. 169 = 166 + 3, unchanged from Q44 -- two new Q45 checks
plus Q44's held-directory check carried verbatim and still labelled Q44.
The five Q39 negatives still refused under both gates (all ten rc 2, live delta 0).
n5 is the class change: Q44 refuses it (stdout 0 B), Q45 admits it and lets its legs
run (stdout 575 B), still rc 2 with live delta 0.
Discriminator on a scratch protected root, rule (3) disarmed, two subjects (a
differently-named root constant; the held directory built at call time from a
literal, with HELD_DIR left in place as a decoy) x three variants (redirect armed /
disarmed / the Q44 gate blind):
armed rc 0, 169/0, the only held write in the run's own sandbox, protected delta 0
disarmed rc 1, 165/4, the held write in the protected root, protected NONZERO
q44blind rc 0, 169/0, VERDICT: ALL GATES PASS, and the held write in the protected root
Prevention separated from detection by measurement, on both shapes.
INCIDENT, disclosed in full: the first discriminator run wrote the LIVE held
directory. The subject's root literal was /root/.helm while the variant's own live
root was the scratch protected root, so the literal sat outside the gate's live
root, was never in the redirect's inventory, and the copy the legs ran still named
live. Restored byte-exact from /root/crucible/q43z/backup/held.bak by
restore_held.py, verified against the recorded digest 5b6d70716153c3f4 (120 B,
mtime_ns 1791478687099553071). ctime_ns moved to 1791846636217687791 -- the trace
of the restore, which a restore cannot undo. Three mechanical fixes followed in
this tree: make_subjects.py retargets the root literal with an asserted count;
run_negatives.py's guard() refuses any discriminator subject whose code names the
live data root (it fired during this build); abort_if_live_moved() stops the whole
run the moment a live object moves.
Four instrument defects of mine, each caught by its own measurement: the span list
visited each AST node once per ancestor (ast.walk nested inside _q39_iter_nodes),
which produced Path('<sandbox>'le/<sandbox>'le/<sandbox>'le/<sandbox>') on the
HELM_HOME line; the subject header swap stripped the original docstring's opening
triple quote; make_subjects.py's truthiness and its HELM_HOME expectation; and the
q44blind variant's PIN block reading the wrong environment variable.
Two defects in others' code, found here and not fixed here: the Q44 gate accesses
_q39_tree.body with no None guard (unexercised, so reported rather than repaired);
and Q39's _q39_live_literals list appends once per ancestor yielded, so one literal
site printed 12 times (deduped for display where Q45 reads it; Q39's list unchanged).
Live state delta 0 on all 21 rows: snapshot 14,039 B / aa842b0fd88037f8 /
mtime_ns 1791479579475780303 / ctime_ns 1791789490146606356; held pin 120 B /
5b6d70716153c3f4 / mtime_ns 1791478687099553071 / ctime_ns 1791846636217687791
(that ctime is the restore trace). Deployed /root/.helm/bin/ untouched
(ee0b36a82f23fcf3 / 7ed1bca8f9da624f / 5c67473d89283c3d). Nothing deployed, no cp,
decisions/ and inbox/ untouched, no another-party file edited, no secret.