20 KiB
2026-10-14 — merlin
Screen. Every claim below carries a path, a hash, a URL, or a command with its output, or the word
unverified. Nothing secret is printed anywhere in this check-in or in the files it lands.
Run 22 — Q45 §9: the pwd channel
Did
Claimed and finished the Q45 §9 follow-on — the pwd channel (Helm lane; the lane's own named
residual, the limit the Q45 §9 record carried: "a subject reading pwd.getpwuid(...).pw_dir directly
bypasses HOME and the redirect cannot see it"). Deliverable:
recoveries/helm-pwdir-channel-refusal.md (14,808 B / sha256
d4c381f713e9fe95beefbd14a93220ab4049625f280c116e656419f3e11b7b89, this host). Queue block appended
at the foot of WORK-QUEUE.md (951,756 B / sha256
d8f54086edbcbbc96e39533d7b6dcf0e9effff108b596ed18685b03d1045e1db, +5,419 B / 63 lines, trailing
newline asserted before and after). Scratch tree /root/crucible/q55/; nothing deployed, no cp into
/root/.helm/bin/, decisions/ and inbox/ untouched, no another-party file edited, no secret.
The class, measured on the shipped gate before the change. The base gate is
/root/crucible/q52/helm-selftest-q52.py = 78b290ecf2d93e0c… (140,365 B / 2,677 lines / 126
registrations), copied into q55/ and re-verified by sha256sum. Two fixtures transform the real
collector (4e45021d…, 720 / 29,954, byte-identical to Q45 §9's) into a subject whose root comes from
the user database — collector-pwdir-named.py (4d62da91…, 29,994 B) and collector-pwdir-root.py
(8b368ead…, 29,979 B, the constant renamed HELM_HOME→ROOT). Run under a scratch HOME, both
resolve ROOT=/root/.helm and HELD_DIR=/root/.helm/data/held with rc 0 — the interpreter's own
verdict of the class. Under the shipped gate: the default run is 175/1 (Q45 FAIL, escapes={"ROOT": "/root/.helm", "HELD_DIR": "/root/.helm/data/held"}) while Q52 PASSES — the check asserts the
legs' HOME is redirected, and pwd.getpwuid never reads HOME. Under the gate's own --q52-witness
flag — the flag that exists to measure this class's write path: rc 0,
copy_pin_files_anywhere_in_sandbox [], and the live held pin moves
(5b6d7071…→fdd45f74…, mtime_ns 1791478687099553071→1791940472306970986; guard
q55_guard.py compare after-pwr-witness: "moved": true), restored byte-exact. The named-constant
fixture writes live through the same path (302bfda5…). A foot check reports after the legs; only a
precondition refuses before them.
The fix. Gate cd43284ff009d1cceb3aaa6a65b701d1076eaf801e32b705672601b4122b746a (143,385 B /
2,735 lines / 126 registrations — unchanged; one edit, +3,020 B / +58 lines, 2,677 + 58 = 2,735
exactly) on the Q52 gate: a precondition after Q46's parse guard and the ast import, before the Q39
sandbox, the admission probe and any leg — a subject whose own AST reads the pwd module is refused
(exit 2, dated, naming the subject, every pwd site with its line, the live snapshot before/after). No
check() registered, so the green pair still reports exactly 176 / 0. Disarmed twin
8adad99bdc872ecd09ddea88ae55b5fc55a3886571ffaa5f49a053b52430586d (143,416 / 2,735 / 126), one line
different, 31 B larger (the Q52-twin pattern). The internal label is Q45S9, not a queue number —
the lane's own collision lesson applied to a fresh artifact before any readback or push, so these are
the only digests this run carries.
The matrix, 25 cells, all guarded (run_matrix_q55.py → out/Q55-MATRIX.json, 12;
run_matrix2_q55.py → out/Q55-MATRIX2.json, 13). Armed × pwr / pwr-witness / pwn → rc 2 refusal,
stdout 0 B (e3b0c442…), live delta {}. Disarmed × pwr-witness → the escape reproduces
(probe HELD_DIR=/root/.helm/data/held, pin in sandbox [], live pin 5b6d7071…→ced810a9… /
1791941106156792591, restored byte-exact) — the refusal is load-bearing. Disarmed × pwr → 175/1,
Q52 PASS, Q45 FAIL (the shipped behaviour). Green pair ×5: 176/0, 14,044 B stdout / 1,216 B stderr,
live delta {} each, 20.5–24.1 s. Regressions 11/11 (n1–n5, noparse, dep-unparseable,
undecodable, broken_dep rc 2; latin1 and bom 176/0). Covered shapes are not over-refused and stay
protected: armed × collector-home.py --q52-witness puts the pin inside the sandbox
(q52-home/.helm/data/held/…) with the live pin unmoved; and the covered fixtures fail Q43
identically under the shipped gate (175/1 both, PASS/FAIL lists identical modulo sandbox names —
measured side by side, so the fix introduces no behaviour change for them).
Live state, sandboxes, deployed. Delta 0 on bytes/sha256/mtime across all 25 cells
(q55_guard.py compare final2, "moved": false): snapshot 14,039 B / aa842b0fd88037f8… /
mtime_ns 1791479579475780303; pin 120 B / 5b6d70716153c3f4… / 1791478687099553071. ctime moved
on the pin across the deliberately-live witness cells (guard restores) — disclosed. Sandboxes: the
q55 tree 0/0 both ways (the refusal exits before the sandbox is created); the E14 leak re-measured
at 26 across /root/crucible and all 26 removed (842,401 B reclaimed, after-count 0 both ways,
out/Q55-CLEANUP.json), plus the q55 __pycache__ (the C32 class). Deployed /root/.helm/bin/
untouched (five digests re-read: ee0b36a8… / 5c67473d… / 7ed1bca8… / 12570786… / 73869998…),
grep -c HELM_COLLECTOR = 0 — Q40 stands, so none of Q31–Q45 §9 is in production. Disk 45 G avail
of 154 (71 %).
Five defects of mine, logged first in the deliverable: part 1's d/e rows pointed at fixtures not
yet copied into the tree (a Q35 refusal against a nonexistent path — void rows, re-run in part 2, kept
with the note); part 1's restored field compared a 12-char prefix to a full digest; part 1's Q45
filter matched the one-space rendering and missed the row it existed to find; my d/e expectation of
176/0 was assumed and the shipped-gate baseline taken after was the correction; and the gate's
first-written Q55 label.
Blocked
Nothing blocks the lane. The standing human gates are unchanged: the §4 adoption cp — now
collector 4e45021d… + gate cd43284ff009… (superseding 78b290ec… / 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-13 23:18Z hygiene ledger (git log --oneline --since=2026-10-13T20:00: nothing after 8dbaf23; checkins/ has no 2026-10-14 file but this one).
Next
- The pipe's verification of this run, when it lands. Everything re-runs from
/root/crucible/q55/:make_fixtures_q55.py,patch_gate_q55.py,run_matrix_q55.py,run_matrix2_q55.py,q55_guard.py,census_q55.pyandcleanup_sandboxes.pyare self-contained;out/holds every cell's stdout and stderr plusQ55-MATRIX.json,Q55-MATRIX2.json,Q55-CENSUS.jsonandQ55-CLEANUP.json(host-local — the repo carries 0 paths underout/, E13's rule). - No new item opened. The Helm lane's executable set is empty and a task invented to fill it would
be invented work; the next Helm unit is the
cpdecision, not a task.
Ask
Alexander's, unchanged: (a) the §4 adoption cp — collector 4e45021d… + gate
cd43284ff009… — the only thing between Q31–Q45 §9 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 (the hygiene ledger's Q52 is Mercury's),
and the lane's own limits are discharged by measurement above.
— Merlin (Run 22)
Run 22 landing evidence
Read back over the anonymous raw path
(https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>, no
credential) by python3 /root/crucible/q55/readback_q55.py <revision>; artifact
out/Q55-READBACK.txt (host-local — the repo carries 0 paths under out/, E13's rule). All rows
HTTP 200, served = disk = git cat-file -p <revision>:<path>:
| file | HTTP / bytes | sha256 (served = disk = git) |
|---|---|---|
recoveries/helm-pwdir-channel-refusal.md |
200 / 14,808 | d4c381f713e9fe95beefbd14a93220ab4049625f280c116e656419f3e11b7b89 |
WORK-QUEUE.md |
200 / 951,756 | d8f54086edbcbbc96e39533d7b6dcf0e9effff108b596ed18685b03d1045e1db |
checkins/2026-10-14-merlin.md |
200 / (this file at the pushed revision — a file cannot hash itself, so this row cites the revision it was written against; this append lands as its own commit) | — |
Live state at readback, unchanged: snapshot 14,039 B / aa842b0f… / mtime_ns 1791479579475780303;
held pin 120 B / 5b6d7071… / mtime_ns 1791478687099553071; deployed /root/.helm/bin/ untouched,
HELM_COLLECTOR count 0. Nothing deployed, no another-party file edited, decisions/ and inbox/
untouched, no secret printed.
— Merlin (Run 22, landing)
Landing fill (c4addca, read at 2026-10-14T01:31:36.418624587Z by
python3 /root/crucible/q55/readback_q55.py c4addca; artifact
out/Q55-READBACK.txt, host-local). The push was 8dbaf23..c4addca on
main, 3 files. All three rows HTTP 200, served = disk =
git cat-file -p c4addca:<path>:
| file | bytes | sha256 |
|---|---|---|
recoveries/helm-pwdir-channel-refusal.md |
14,808 | d4c381f713e9fe95beefbd14a93220ab4049625f280c116e656419f3e11b7b89 |
WORK-QUEUE.md |
951,756 | d8f54086edbcbbc96e39533d7b6dcf0e9effff108b596ed18685b03d1045e1db |
checkins/2026-10-14-merlin.md |
9,279 | 2d815c65542f7ea2722865b47fd19b0fbfcfe688ecfba97e03c84ea8c31ad132 (at c4addca, before this fill — the rule above) |
The check-in's own Run-22 body block cites the same two artifact digests, so the table and the block
agree by construction rather than by one chasing the other. Live state re-read at the fill: snapshot
14,039 B / aa842b0f… / mtime_ns 1791479579475780303; held pin 120 B / 5b6d7071… / mtime_ns
1791478687099553071; deployed /root/.helm/bin/ untouched, HELM_COLLECTOR count 0; disk 45 G
avail of 154; the q55 tree holds 0 sandboxes.
— Merlin (Run 22, landing fill)
Run 23 — record correction: the four numbers, and a readback that survives its own overwrite
Did
No unclaimed queue item was executable this run, and I did not invent one: Q42 is zephyrus-sparkborn's,
Q52 is Mercury's, Q53 is the career lane held for Alexander, and both this lane (Run 22) and the pipe
(1ccf944, reply 45 §6) have independently measured the Helm executable set empty — the next Helm unit is
a decision, not a task. So the unit is the one reply 44 (0f9ac82) and reply 45 (1ccf944) handed back:
four byte figures and one identifier in my own Run 22 record are wrong, and the wrong pairing sits
behind the §4 adoption cp cite, which is the one thing standing between Q31–Q45 §9 and production.
Deliverable: recoveries/helm-pwdir-channel-refusal.md 14,808 B → 20,820 B / sha256
8d67248fd9acb73cb5cb0c39a5fb774232c02730f97e998a5f3292d54efbbcc1 (+6,012 B, append-only — nothing
above the anchor edited, anchor count asserted == 1 before the write, trailing newline asserted before
and after on the written file).
Cause, and it is mine. rename_q55.py renames Q55 → Q45S9 (+2 chars per occurrence) and changed the
gate's bytes after the byte figures were taken and before the digests were computed, so the record
published a post-rename digest beside pre-rename bytes. Measured this run from disk and the interpreter,
not from either reply: instrument /root/crucible/q55/run23_verify.py, artifact out/R23-VERIFY.json
(2,685 B / sha256 1bb9cd78e394d25ccea46a5d38c67b598d694c49462269911f357c3e858fc0c5,
generated_at 2026-10-14T03:36:23.456605839Z).
$ cd /root/crucible/q55 && python3 run23_verify.py
armed 143389 cd43284ff009d1cceb3aaa6a65b701d1076eaf801e32b705672601b4122b746a 2735 126
twin 143422 8adad99bdc872ecd09ddea88ae55b5fc55a3886571ffaa5f49a053b52430586d 2735 126
twin-armed 33
sites [435, 442, 451] [435, 451] q45S9: 0 0
differing [{"line": 442, "armed": "if _q55_pwd_sites:",
"twin": "if False: # Q45S9 disarmed: the pwd refusal is cut"}]
rc 0 stdout 14044 stderr 1216 12.2s
verdict ['helm-selftest: 176 passed, 0 failed']
q52 [" PASS Q52 the subject's home-directory reads resolve inside the sandbox when the subject reads the home database"]
live_moved [] ctime_moved []
| figure | Run 22 said | measured | status |
|---|---|---|---|
| armed gate bytes | 143,385 | 143,389 | corrected |
| armed gate sha256 | cd43284ff009…b746a |
identical | holds — the §4 cp cite is sound |
| twin bytes | 143,416 | 143,422 | corrected |
| twin sha256 | 8adad99bdc87…86d |
identical | holds |
| twin − armed | 31 B | 33 B | corrected |
| insertion block | +3,020 B / +58 lines | +3,024 B / +58 lines | corrected |
| differing line's identifier | if _q45S9_pwd_sites: |
if _q55_pwd_sites: (line 442) |
corrected |
Both gates: 2,735 lines / 126 check(" registrations / trailing newline true; Q55 (upper) occurs 0
times in both and Q45S9 2 (armed) / 3 (twin — the third is the twin's own cut comment), so the
rename is total. _q45S9_pwd_sites 0 in both; _q55_pwd_sites at :435, :442, :451 armed and
:435, :451 twin — 3 vs 2 sites, which is the single cut line and nothing else. The reply's
"3,043 minus 23" derivation is wrong in kind, not wrong by arithmetic: the anchor is the insertion
point, so the block is 3,024 B post-rename and 3,020 B pre-rename, and the subtraction only appears to
explain it.
The gate re-run once on the real collector (HELM_COLLECTOR=/root/crucible/q48/helm-collect.py, subject
sha256 4e45021d80395d3f03fc58d7e99610e3c1c0d2fcf9c85f1db50b16cfd2043c6c, 29,954 B): rc 0,
helm-selftest: 176 passed, 0 failed, ALL GATES PASS, 14,044 B stdout / sha256
585e0e4b0508b565a18ca52cde3c464b9f92673b8fad538a12a33fd8a07131c1 / 1,216 B stderr, 12.2 s. Live delta
{} on bytes, sha256, mtime_ns AND ctime_ns for both live objects — snapshot 14,039 B /
aa842b0fd88037f8… / mtime_ns 1791479579475780303; held pin 120 B / 5b6d70716153c3f4… / mtime_ns
1791478687099553071; ctime 1791941985122465693 / 1791941985123465776, unmoved this run (it is Run
22's witness-restore trace, disclosed there and not re-created here).
The readback now survives its own overwrite — reply 45 §5.1's finding, closed. out/Q55-READBACK.txt
on disk is the 8d105e9 read, so the c4addca read it was written to hold could not be re-derived from its
own artifact. New instrument /root/crucible/q55/readback_r23.py, artifact out/R23-READBACK.json, reading
/raw/commit/<rev>/<path> so the served body is the body at that revision, permanently:
$ cd /root/crucible/q55 && python3 readback_r23.py c4addca b31c727
c4addca recoveries/helm-pwdir-channel-refusal.md 200 14808 d4c381f713e9fe95 git=True disk=True
c4addca WORK-QUEUE.md 200 951756 d8f54086edbcbbc9 git=True disk=False
c4addca checkins/2026-10-14-merlin.md 200 9279 2d815c65542f7ea2 git=True disk=False
b31c727 recoveries/helm-pwdir-channel-refusal.md 200 14808 d4c381f713e9fe95 git=True disk=True
b31c727 WORK-QUEUE.md 200 957453 d60d6dee32376ef2 git=True disk=True
b31c727 checkins/2026-10-14-merlin.md 200 10499 eae1c6b2c62983f0 git=True disk=True
head_at_read b31c727f77d1c50cdb9019b915170a47684351c8
6 rows, 6 × served = git. The two served = disk false rows at c4addca are the pipe's own three
appends since that revision (queue 951,756 → 957,453 B / d8f54086… → d60d6dee…; check-in 9,279 →
10,499 B / 2d815c65… → eae1c6b2…) — named and dated, not a serve failure. The record is
byte-identical at both revisions (d4c381f7…), which is what makes today's corrected figures the first
change to this file since Run 22 landed.
A defect of mine, hit inside this run and logged here rather than in a reply: the first version of
run23_verify.py extracted the Q52 line with startswith("PASS Q52"), which never matches the two-space
rendering — the lane's own logged defect, reproduced by its author on a fresh artifact, corrected to a regex
before the run was recorded. The measured line is quoted above.
Blocked
Nothing blocks the lane. The standing human gates are unchanged and none is new: the §4 adoption cp —
now collector 4e45021d… + gate cd43284ff009…, whose digests this run re-verified against the files on
disk, 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's. Nothing deployed this run: grep -c HELM_COLLECTOR /root/.helm/bin/helm-selftest.py = 0, so Q40 stands and none of Q31–Q45 §9 is in
production.
Next
- Nothing is owed to the pipe from this run: reply 45 asks nothing of me, and both replies' corrections are now applied to the artifact they correct.
- No new item opened. The Helm executable set is empty and the queue's genuinely open items belong to
other lanes or to Alexander; the next Helm unit is the
cpdecision.
Ask
Alexander's, unchanged: (a) the §4 adoption cp — collector 4e45021d… + gate
cd43284ff009d1cceb3aaa6a65b701d1076eaf801e32b705672601b4122b746a (143,389 B / 2,735 lines / 126
registrations), re-verified on disk this run; (b) the manifest_match pin, stale since 2026-10-08;
(c) the Q13 publication call. No ask of the pipe.
— Merlin (Run 23)
Run 23 landing evidence
Read back over the anonymous raw commit path
(https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/commit/<rev>/<path>, no
credential) by python3 /root/crucible/q55/readback_r23.py eec3ff3; artifact out/R23-READBACK.json
(1,229 B / sha256 9846ea9050802ca24d67a869e4facae7c750ee6a0bdbe3c8a9b07bd808372c18, host-local — the
repo carries 0 paths under out/, E13's rule). Push b31c727..eec3ff3, 3 files / 252 insertions / 0
deletions. All three rows HTTP 200, served = disk = git cat-file -p eec3ff3:<path>:
| file | bytes | sha256 |
|---|---|---|
recoveries/helm-pwdir-channel-refusal.md |
20,820 | 8d67248fd9acb73cb5cb0c39a5fb774232c02730f97e998a5f3292d54efbbcc1 |
WORK-QUEUE.md |
962,664 | 972efe4a2a83414b4c32f7acc142701e7d39164e38c46f8870b6229d96e60380 |
checkins/2026-10-14-merlin.md |
18,265 | 45223797da62ae9c70bcef6b2945f31b9417d1fb6b2c24386d9ef01b5fbd4684 |
This file's own row defers to the artifact above — appending this block changes this file's digest, so
the row for this commit is the next revision's readback and the chain stops here by design (Run 22's
landing-fill shape, with the regress named instead of chased). The artifact's revision field names which
revision each of its rows is dated at, which is the property reply 45 §5.1 asked for.
Live state at readback, unchanged: snapshot 14,039 B / aa842b0fd88037f8… / mtime_ns
1791479579475780303; held pin 120 B / 5b6d7071… / mtime_ns 1791478687099553071; ctime unmoved on both
this run. Deployed /root/.helm/bin/ untouched, grep -c HELM_COLLECTOR = 0 (Q40 stands). Sandbox census
in /root/crucible/q55/: 0 (ls | grep -c helm-legs → 0). Nothing deployed, no another-party file
edited, decisions/ and inbox/ untouched, no secret printed.
— Merlin (Run 23, landing)