Files
Merlin a41f0b97ec helm: Run 21 landing evidence -- three-way readback at 258e3ad, and the clock correction the run's own Screen line needed
The fill for Run 21 (content at 258e3ad). Read back over the anonymous raw path at
revision 258e3ad by /root/crucible/q54/readback_q54.py (artifact out/Q54-READBACK.txt,
398 B, mtime 2026-10-13 23:04:19.489552154Z, host-local): record 200 / 34,311 /
4ba00ce427b85079adedf34524c8334a92e949b205efcc682c8cdd47a99a1cd7, queue 200 / 935,526 /
c5316986a532ce2ba4c479e89b0a4839c7bcd6e6c613d859511616b9fb7323e0, check-in 200 / 94,099 /
1da711a046950f73979bfaa52fe04479c76cbd573ba1421c937d3f53dd8d4ba7 -- all three
served = disk = git, all newline-terminated, ALL ROWS EQUAL.

Clock correction, appended not edited in place: the Run-21 blocks cite "~21:2xZ",
which no instrument supports. The Run-21 content commit 258e3ad was made at
2026-10-13T23:03:50Z (git log -1 --format=%cI) and the readback artifact at
23:04:19.489552154Z. The cite was assumed from reply 42's 21:07Z timestamp rather than
measured -- the same defect class as reply 42 section 1, reproduced by this run's own
Screen line and corrected here.

Live and deployed unchanged across the whole run: snapshot 14,039 B / aa842b0fd880 /
mtime_ns 1791479579475780303; held pin 120 B / 5b6d70716153 / mtime_ns
1791478687099553071; deployed bin ee0b36a8 / 5c67473d / 7ed1bca8 / 12570786 / 73869998
with grep -c HELM_COLLECTOR = 0 on the gate (Q40 stands, nothing of Q31-Q45s9 in
production); disk 45 G avail of 154; worktree clean.

Read-only run: no gate invocation, no live write, no deployment, no edit to another
party's file, decisions/ and inbox/ untouched, no secret printed.
2026-10-13 23:05:10 +00:00

95 KiB
Raw Permalink Blame History

2026-10-13 — 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 12 — Q46: the parse guard

Did

Claimed and finished Q46 — the parse guard (Helm lane; the top open item, opened by the pipe on reply 29's C1). Deliverable: recoveries/helm-parse-guard.md (12,284 B / sha256 19fa3ff6d25c85ce4ae5dfbde5af00b832651f76ca17ca42d3eadf17731f3eba, this host). Queue block appended to WORK-QUEUE.md. Scratch tree /root/crucible/q46/; nothing deployed, no cp into /root/.helm/bin/, decisions/ and inbox/ untouched, no another-party file edited, no secret.

The item. A subject carrying the Q35 markers whose source does not parse was admitted by the Q39 admission and then crashed the gate, on every gate from Q39 up. The mechanism, as the pipe named it: the crash detector tests for the literal 'Traceback (most recent call last)' and a top-level SyntaxError prints no such line, so "probe rc≠0, wrote nothing, no traceback" is satisfied by a subject that cannot run at all. What failed was the refusal-path property every gate claims for every subject — and a crashed run left its sandbox behind.

The pair. Collector byte-identical to Q45's (4e45021d80395d3f…, 720 / 29,954) — every change is in the gate. Gate ae69d5dd735b6f3cfe82b3682b02acf4557b2939d104b9f15b81cffaeef016d4 (2,032 lines / 109,643 B) against Q45's 2bbca218… (1,942); diff -u = 113 lines = 2 file + 3 hunk + 90 added + 0 removed + 18 context, and 1,942 + 90 − 0 = 2,032 exactly (out/DIFF-vs-q45.txt, counted by grep -c, not asserted).

Two changes. (1) A parse guard after Q35's source precondition and before the admission probe: compile() the subject's own source; a SyntaxError is refused with exit 2 and a dated message naming the subject, the failure and its position, with the live snapshot read before and after — and the probe directory and the sandbox do not exist yet, so the refused class creates neither. It registers no check(): the green count stays 169 passed / 0 failed. (2) An atexit handler removes the per-invocation sandbox on every exit path — refusal, propagated leg rc, or crash — closing a leak this run measured on the n5 negative (before/after below).

The discriminator, ten invocations, all five gates digest-identical to the revision history (run_negatives.py → out/Q46-NEGATIVES.json, 58,433 B / 028b6b1c68ab48cd…, 21 rows, generated_at 2026-10-13T01:31:42.240730+00:00):

fixture Q39 (9b09f328…) Q43 (c22601ec…) Q44 (18580c10…) Q45 (2bbca218…) Q46 (ae69d5dd…)
noparse-with-markers.py rc 1, 575 B, SyntaxError at the legs' import of the original subject; no sandbox exists yet rc 1, 575 B, sandbox-copy import; legacy/q43/helm-legs-jkij8r1x left rc 1, 0 B, AttributeError: 'NoneType' object has no attribute 'body' at :482 (the Q45 record's unexercised §8(a), now exercised); legacy/q44/helm-legs-8tkclld3 left rc 1, 575 B, sandbox-copy import; legacy/q45/helm-legs-wgn7u3v2 left rc 2, stdout 0 B (e3b0c44298fc1c149…), Q46 REFUSAL: … does not parse - invalid syntax (noparse-with-markers.py, line 13) (line 13, offset 12) - refused at 2026-10-13T01:31:45.419033+00:00, before the admission probe, before any leg, and before any sandbox is created.; no traceback; no leftover
dep-unparseable.py (parses; its dependency does not) rc 2 — Q39 repair 3 rc 2 — repair 3 rc 2 — repair 3 rc 2 — repair 3 rc 2 — repair 3

The class is split, and both halves are measured: the subject's own source is refused by the parse guard; a dependency SyntaxError raises with a traceback and is refused by repair 3 on all five gates. Repair 3 stays load-bearing — the guard is the gap between them, not a second layer.

C2 reproduced mechanically. On the crashed rows the ROOT-anchored leftover() reports [] while the recursive census reports legacy/q4X/helm-legs-…: a gate creates its sandbox beside itself, so a glob anchored at ROOT cannot see it. The harness takes both censuses per row; the shipped gate's atexit handler means no run of it leaves one.

The n5 leak, before/after. The pre-atexit gate (1fd889ca…, the shipped gate minus the handler) run with n5: rc 2, leftover work/helm-legs-3fancddl (out/q46-noatexit-n5.{out,err}, measured live); the shipped gate, same fixture: rc 2, leftover []. The leak is not the item's class (n5 parses) — the criterion generalises to every early exit, and the measurement said the refusal path did not cover a propagated leg rc.

Green pair, five consecutive invocations (run_green.py, logs on disk at out/q46-green-{1..5}.{out,err}): rc 0 each, 169 passed / 0 failed, VERDICT: ALL GATES PASS, 13,312 B stdout, 12.17–12.62 s, live delta 0, held delta 0, no leftover.

Live state, delta 0 across all 27 invocations (21 harness rows + 5 green runs + the noatexit run): snapshot /root/.helm/data/snapshot.json 14,039 B / sha256 aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d / mtime 2026-10-08 17:12:59.475780303 +0000; held pin /root/.helm/data/held/stackchain-home.html.sha256 120 B / 5b6d70716153c3f4…. Deployed bin untouched (ee0b36a82f23fcf3… / 7ed1bca8f9da624f… / 5c67473d89283c3d…). Final tree: 0 sandboxes (find /root/crucible/q46 -name 'helm-legs-*' -o -name 'helm-q39-*' → 0, after cleanup_final.py). Host disk 46 GB free of 154 GB (71 % used) (df -h /).

Four defects of mine, logged first in the deliverable: the first harness run crashed on a missing fixture path (the C1 fixture was at the tree root, not in fixtures/); the first harness wrote the green logs as empty files (re-measured with run_green.py, real logs on disk); in this tree the Q44 crash carries 0 B of stdout where the pipe measured 4 B on the same fixture — a tree-and-clock difference, recorded not reconciled; and the n5 leak was found by this run's own census and fixed here rather than left as somebody else's finding.

Blocked

Nothing in my lane. Same standing gates, all Alexander's: the §4 adoption cp — now collector 4e45021d… + gate ae69d5dd… (superseding 2bbca218…); Q40's finding stands (the deployed gate 7ed1bca8… reads HELM_COLLECTOR zero times), so none of Q31–Q46's protection is in production until it lands — Q9 (checksum handover), Q13 (wording fixes), Q19 (wizard onboarding).

Next

  1. The pipe's verification of this run, when it lands. Everything is re-runnable from /root/crucible/q46/: run_negatives.py and run_green.py are self-contained, and figures.py / print_figs.py / show_rows.py regenerate the record's figures from the JSONs.
  2. Merlin's Q45 §9 follow-on stays open and unclaimed: resolve every path the subject declares at runtime, rather than rewriting the literals it declares statically. Beside the adoption decision, that is the one Helm-side follow-on I would name.
  3. Q7, measured: the Helm lane's executable set is empty again. The adoption, Q9, Q13/Q19 and Q42 are human- or counterparty-gated. No new item opened — the next Helm unit is a decision, not a task.

Ask

Alexander: nothing blocking. The standing items, consolidated: (a) rule on the §4 adoption cp — collector 4e45021d… + gate ae69d5dd…, the pair that makes python3 helm-selftest.py green with no environment and puts Q31–Q46's protection into production (the deployed gate today has no subject-selection path at all); (b) the manifest_match pin decision (stale since 2026-10-08; a static render cannot say so); (c) the Q13 publication call (item 13's decided note — escalate, do not edit the live page — still controls over its proposed_action).


Landing evidence, appended after the commit and read back over the anonymous raw path (https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>), no credential — each HTTP 200 and cmp byte-identical to disk:

file status / bytes sha256
recoveries/helm-parse-guard.md 200 / 12,284 19fa3ff6d25c85ce4ae5dfbde5af00b832651f76ca17ca42d3eadf17731f3eba
WORK-QUEUE.md 200 / 751,695 1c2d9a3937994d068d02c7c3d59d6df46e6e6513525b83547d71c69b3db64f99
checkins/2026-10-13-merlin.md 200 / 9,599 (the committed revision a6b1ae3, which is what the server served at readback time and what git cat-file -p a6b1ae3:checkins/2026-10-13-merlin.md reproduces locally — a file cannot hash itself, so this row cites the revision it was written against, and the fill below lands as its own commit) 36123a348755789cf2d862ccbd6f1387619f73598a5e07f891065a034a6c4d8a

Read-back method: python3 /root/crucible/q46/readback.py (anonymous GET, no credential), exit 0, VERDICT: ALL READBACKS IDENTICAL — all three files HTTP 200 over the anonymous raw path and byte-identical on three sides: the bytes the server served, the bytes on this host's disk, and git cat-file -p a6b1ae3:<path>. The fill block below lands as its own commit; its revision is readable over the same path by the same script.

Re-measured after the push, from this host: the live snapshot /root/.helm/data/snapshot.json is 14,039 B / sha256 aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d / mtime 2026-10-08 17:12:59.475780303 +0000 — delta 0 across the whole run — and the deployed /root/.helm/bin/ is untouched (ee0b36a82f23fcf3… / 7ed1bca8f9da624f… / 5c67473d89283c3d…). Nothing was deployed, published, rebuilt or re-run beyond the measurements above; decisions/ and inbox/ were not touched; no another-party file was edited; no secret is printed in this check-in or in the files it lands — the long strings are gate check names, refusal messages, file paths and sha256 digests. This run's commits are authored Merlin <merlin@agents.invalid> (git -c), so the monitor sees them as counterparty content per Q36's v1.3 rule.

—

Run 13 — Q47: the read path

Did

Claimed and finished Q47 — the read path (Helm lane; opened by the pipe on reply 30's C1, its new Documented finding). Deliverable: recoveries/helm-read-path-guard.md (12,821 B / sha256 5bf9ba115071a97f07a4d6e09bd4d4add78646680724ff63e32f2d101cdc1516, this host). Queue block appended to WORK-QUEUE.md. Scratch tree /root/crucible/q47/; nothing deployed, no cp into /root/.helm/bin/, decisions/ and inbox/ untouched, no another-party file edited, no secret.

The defect, both directions, one cause. A subject with # -*- coding: latin-1 -*- and one latin-1 byte — bytes-compile OK, python3 <fixture> rc 0, so the interpreter runs it — crashed the gate at COLLECTOR.read_text(): UTF-8 decode raises UnicodeDecodeError, rc 1, a traceback, no dated refusal. The real collector with a UTF-8 BOM — CPython strips a BOM when it reads a source file — was falsely refused by the Q46 guard: the decoded text still carries U+FEFF and compile() calls it an invalid non-printable character. The gate reads a decoded str; the interpreter compiles the file's bytes.

The pair. Collector byte-identical to Q46's (4e45021d80395d3f…, 720 / 29,954, measured by sha256) — every change is in the gate. Gate 76f2292b9a6cad08… (115,182 B / 2,124 lines) against Q46's ae69d5dd… (110,509 / 2,032); out/DIFF-vs-q46.txt = 130 lines = 2 file + 4 hunk + 96 added + 4 removed + 24 context, and 2,032 + 96 − 4 = 2,124 exactly (the lane decomposition rule: added = ^+ minus +++, removed = ^- minus ---).

What changed — one reader, four read sites, one refusal. (1) _q47_subject_text() reads the subject the CPython way: bytes through tokenize.detect_encoding (BOM first, then the PEP 263 cookie, then utf-8), decoding with utf-8-sig when a BOM is present so it is stripped exactly as the interpreter strips it. (2) A dated exit-2 refusal at Q46's guard point — after Q35's source precondition, before the admission probe, before any leg, before any sandbox — with the live snapshot read before and after. (3) All four subject-source reads routed through the one reader (Q35's _q35_src, the admission's _q39_src_text, the G8 source read, the G8 source-guard check). (4) One Q47 NOTE on stderr, never stdout, and only when the subject's encoding is not plain utf-8, so a green pair's stdout shape is unchanged and the positive side is visible. The parse guard, the redirect, every check() and the 169 count are untouched.

The interpreter's own verdict, measured not assumed (make_fixtures.py, fixtures built from the real collector with asserted counts): collector-latin1.py (30,028 B / 6ce8bf90292d83f1…) → python3 <fixture> --skip-tests rc 2, the destination rule refusing — the file runs; collector-bom.py (29,957 B / d14906c868e24997…) → rc 2, runs; collector-undecodable.py (30,006 B / 47fc3580fdfe8308…) → rc 1, SyntaxError: Non-UTF-8 code starting with '\xe9'.

The discriminator, fifteen invocations, five gates (run_negatives_q47.py → out/Q47-NEGATIVES.json, 57,247 B, 21 rows, generated_at 2026-10-13T03:46:55.002706+00:00; legacy gates digest-verified 9b09f328… / c22601ec… / 18580c10… / 2bbca218…):

fixture Q39 Q43 Q44 Q45 Q47 (shipped)
collector-latin1.py rc 1 — UnicodeDecodeError … position 30026 (0.16 s) rc 1 — same (0.13 s) rc 1 — same (0.15 s) rc 1 — same (0.14 s) rc 0, 169 passed / 0 failed, ALL GATES PASS, 13,312 B, 12.44 s, Q47 NOTE … (iso-8859-1), no leftover
collector-bom.py rc 0, 164 passed, ALL GATES PASS, 11,398 B, 10.12 s (see the finding below) rc 1 — SyntaxError: invalid non-printable character U+FEFF at the sandbox copy's import, 575 B, legacy/q43/helm-legs-_sja2yko left (0.61 s) rc 1 — AttributeError: 'NoneType' object has no attribute 'body', 0 B, legacy/q44/helm-legs-sl1v6yx5 left (0.22 s) rc 1 — SyntaxError … U+FEFF, 575 B, legacy/q45/helm-legs-8qmmr11u left (0.66 s) rc 0, 169 passed / 0 failed, ALL GATES PASS, 13,312 B, 12.22 s, Q47 NOTE … (utf-8-sig), no leftover
collector-undecodable.py rc 1 — UnicodeDecodeError … position 30004 (0.14 s) rc 1 — same (0.14 s) rc 1 — same (0.19 s) rc 1 — same (0.14 s) rc 2, stdout 0 B (e3b0c44298fc1c149…), dated Q47 REFUSAL: … cannot be read the way CPython reads a source file - 'utf-8' codec can't decode byte 0xe9 in position 30004: invalid continuation byte - refused at 2026-10-13T03:47:32.685519+00:00, before the admission probe, before any leg, and before any sandbox is created. — no traceback, no leftover (0.13 s)

The item's done-criteria, measured: the latin-1 subject proceeds past the guard and runs the whole suite green; the BOM subject is not refused and runs green; a genuinely undecodable subject is a dated exit-2 refusal on the shipped gate (the four pre-Q46 gates stay frozen controls at rc 1, measured, not patched); green still 169 passed / 0 failed; no sandbox left; live_delta = 0 and live_held_delta = 0 on all 21 rows.

The Q39-bom row is a finding, not noise. The oldest gate runs the BOM subject green with 164 passed while Q43/Q44/Q45 crash on it. Q39's own report says why — parse line -: the subject does not parse: invalid non-printable character U+FEFF — and continues: Q39 never compiles the subject's text; it imports the file (where CPython strips the BOM) and runs the probe copy as a subprocess whose SyntaxError the crash detector cannot see. The read-path class is a property of the gates that compile the subject's text (Q43/Q45's sandbox-copy import, Q44's ast), not of subject handling generally.

Regression, all still refused. q47-q46reg-noparse: rc 2, the dated Q46 REFUSAL unchanged — the read-path fix did not loosen the parse guard. q47-neg-n1…n5: all five Q39 negatives rc 2, live delta 0.

Green pair, five consecutive invocations (run_green_q47.py → out/Q47-GREEN.json, 2,725 B; logs out/q47-green-{1..5}.{out,err}): rc 0 each, 169 passed / 0 failed, ALL GATES PASS, 13,312 B stdout / 425 B stderr, 12.03–12.58 s, live delta 0, no leftover; stdout digests 21920260cade855a… / 580021754ed55d3d… / 49025d65cc3082e5… / c8155f076d214d24… / 1d2c7d69a8531d39…. out/q47-green-1.out vs Q46's green log: 184 lines each, exactly 4 differ, all four randomized names (the /tmp render dest, the deploy temp dir, the two sandbox-path lines) — the read path changed nothing the suite prints.

Live state, delta 0 across all 26 invocations (21 harness rows + 5 green runs), censused on (bytes, sha256, mtime_ns, ctime_ns): snapshot 14,039 B / aa842b0fd88037f8… / mtime_ns 1791479579475780303 / ctime_ns 1791789490146606356; held pin 120 B / 5b6d70716153c3f4… / mtime_ns 1791478687099553071 / ctime_ns 1791846636217687791 (the Q45 restore's trace). Deployed bin untouched (ee0b36a82f23fcf3… / 7ed1bca8f9da624f… / 5c67473d89283c3d…, plus helm-validate.py 12570786ba703787… and summarize.py 7386999867789694…). Final tree: 0 sandboxes.

Four defects of mine, logged first in the deliverable. (1) The harness's verdict block passed fixture names with .py into a row-name builder that strips it, so the verdict raised StopIteration → RuntimeError after the rows JSON was written; the verdict was recomputed from the rows by recompute_verdict.py and run_negatives_q47.py is patched (the strip) — no gate invocation was re-run. (2) The negative fixtures' destination literals still name the q46 tree (inherited by cp -a), so this run's fixture-dest census was vacuous; evidence no cross-tree write happened: ls /root/crucible/q46/fixtures shows no n*-dest/dep-dest directories, and each negative row's stderr shows the leg refusing its own destination. (3) The copies this gate writes are UTF-8 by construction (their header lines push the subject's cookie past PEP 263's line-2 limit), so non-ASCII in executable strings under a cookie would be re-encoded — the fixture carries its byte in a comment only; recorded as a limit, not fixed. (4) The guard stays static — runtime-generated code is out of every static guard's reach (carried from Q46).

Blocked

Nothing in my lane. Same standing gates, all Alexander's: the §4 adoption cp — now collector 4e45021d… + gate 76f2292b… (superseding ae69d5dd…); Q40's finding stands (the deployed gate 7ed1bca8… reads HELM_COLLECTOR zero times), so none of Q31–Q47's protection is in production until it lands — Q9 (checksum handover), Q13 (wording fixes), Q19 (wizard onboarding), Q42 (zephyrus's).

Next

  1. The pipe's verification of this run, when it lands. Everything is re-runnable from /root/crucible/q47/: run_negatives_q47.py, run_green_q47.py, recompute_verdict.py, figures_q47.py and show_rows_q47.py are self-contained.
  2. Merlin's Q45 §9 follow-on stays open and unclaimed: resolve every path the subject declares at runtime, rather than rewriting the literals it declares statically. Beside the adoption decision, that is the one Helm-side follow-on I would name.
  3. Q7, measured: the Helm lane's executable set is empty again. The adoption, Q9, Q13/Q19 and Q42 are human- or counterparty-gated. No new item opened — the next Helm unit is a decision, not a task.

Ask

Alexander: nothing blocking. The standing items, consolidated: (a) rule on the §4 adoption cp — collector 4e45021d… + gate 76f2292b…, the pair that makes python3 helm-selftest.py green with no environment and puts Q31–Q47's protection into production (the deployed gate today has no subject-selection path at all); (b) the manifest_match pin decision (stale since 2026-10-08); (c) the Q13 publication call (item 13's decided note — escalate, do not edit the live page — still controls over its proposed_action).

Landing evidence for this run lands as its own commit after the push, over the anonymous raw path, the same way Run 12's did.

—

Landing evidence, appended after the push and read back over the anonymous raw path (https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>), no credential — each HTTP 200 and cmp byte-identical on three sides: the bytes the server served, the bytes on this host's disk, and git cat-file -p 8cb941f:<path>. Method: python3 /root/crucible/q47/readback_q47.py, exit 0, VERDICT: ALL READBACKS IDENTICAL (run at 2026-10-13T03:54:02Z, after the push c104fbb..8cb941f).

file status / bytes sha256
recoveries/helm-read-path-guard.md 200 / 12,821 5bf9ba115071a97f07a4d6e09bd4d4add78646680724ff63e32f2d101cdc1516
WORK-QUEUE.md 200 / 774,704 30d735ef91bcd5f094516b6950f02e3cecd03d9de83b4d70c0a15f80163e5a35
checkins/2026-10-13-merlin.md 200 / 20,685 (the committed revision 8cb941f, which is what the server served at readback time and what git cat-file -p 8cb941f:checkins/2026-10-13-merlin.md reproduces locally — a file cannot hash itself, so this row cites the revision it was written against, and this fill lands as its own commit) 88670dbf8094cd0a47ff194424e6d68cc18b55c66a20e225cba3b8710bb2e12a

Re-measured after the push, from this host: the live snapshot /root/.helm/data/snapshot.json is 14,039 B / sha256 aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d — delta 0 across the whole run — and the deployed /root/.helm/bin/ is untouched (ee0b36a82f23fcf3… / 7ed1bca8f9da624f… / 5c67473d89283c3d…). Nothing was deployed, published, rebuilt or re-run beyond the measurements above; decisions/ and inbox/ were not touched; no another-party file was edited; no secret is printed in this check-in or in the files it lands — the long strings are gate check names, refusal messages, file paths and sha256 digests. This run's commits are authored Merlin <merlin@agents.invalid> (git -c), so the monitor sees them as counterparty content per Q36's v1.3 rule.

— 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


Run 14 landing evidence

Read back over the anonymous raw path with no credential (curl against …/raw/branch/main/…), and byte-compared on three sides — the bytes the server served, the bytes on disk, and git cat-file -p 20623b6:<path>:

file HTTP / bytes sha256 (served = disk = git)
recoveries/helm-runtime-redirect.md 200 / 14,030 8da99a7994c7b8fb…
checkins/2026-10-13-merlin.md 200 / 32,103 6c6eeded0c2bb2c5…
WORK-QUEUE.md 200 / 791,037 bba7bc803b449c9b…

Three-way identical on all three. HEAD = 20623b66fd6d66da8bb38d95ba3a136f606a02dc. The check-in's own row carries no self-hash, per the lane's no-self-hash convention; the blob above is the pre-append revision and this append is the post-append one.

Run 15 — Q49: the runtime-resolved root's live write path

Screen

Merlin, Helm lane, 2026-10-13, this host. Item Q49 — the top open item in the queue and the only Helm unit not human- or counterparty-gated (checked against WIZARDS-TABLE.md first: no named lane for it). Scratch tree /root/crucible/q49/. Every figure measured this run; the two things I could not measure are labelled.

Did

  • (a) Named the invocation and reproduced it. env-root-v1.py (5,634 B / 76b55b8a…) = q48/env-root.py with its two default literals put back to /root/.helm (asserted count 2). Seven rows under a digest-verified guard (q49_guard.py, refuses to restore unless the backup digest matches): 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 (rc 1). All three Q48_ROOT=<scratch> controls: no move. Written content measured by a 5 ms polling watcher: 14 B / 784b9bde… / 'q48-env-pin\n'. Artifact out/Q49-ATTRIBUTION.json (6,495 B / 89a82729…).
  • (b) Closed the class, green 5/5. helm-selftest-q49.py (128,948 B / 2,445 lines / 085ddf4f…): the DEFAULT redirect (inventory every os.environ.get("X","<default>") by ast, redirect a default literal resolving inside the live data root), a per-leg census of both live objects, and a guard on the in-process --deploy leg. Checks 120 → 123 (+3 check("Q49", nothing else). Five green runs: rc 0, 174 passed, 0 failed, 13,863 B stdout, digests 13cf5cf7 / d4666b9f / 0abd28cd / 5ed81c37 / bbbd1901, live delta 0. Artifact out/Q49-GREEN.json.
  • The 2×2 discriminator, predictions written first. Armed/unset → delta 0; default-redirect off → the pin moves and the census names the leg; in-process rebind off and both off → the pin moves. Prevention and detection measured separately. Artifact out/Q49-WITNESS.json (13,785 B / 877138d0…).
  • Two findings beyond the item. (i) G8's --deploy branch runs hcg.main() in-process with only SNAPSHOT_PATH patched, so an import-time-resolved root wrote the live snapshot (14,039 → 137 B, reproduced and restored). (ii) See Blocked.

Blocked

  • One unattributed live write, and it is a residual, not a closed item. In the fully disarmed configuration the live pin moves (three runs), the traced twin records exactly one fixture main() per run and its banner names the sandbox, no spawn names the live path, both Q49 censuses report no move — and the watcher still sees 120 B → 14 B at t+280 ms. The write is real and its content is the env fixture's own pin string; the mechanism is unattributed. I will not guess. It is the Helm lane's next unit.
  • Nothing deployed, by design. /root/.helm/bin/helm-selftest.py is still 7ed1bca8… and reads HELM_COLLECTOR 0 times, so none of Q31–Q49 is in production. The cp of collector 4e45021d… + gate 085ddf4f… is Alexander's under §4.

Next

  • The §5 residual: find the writer the trace cannot see, or narrow the census window.
  • Unchanged and still his: the cp, the manifest_match pin stale since 2026-10-08, the Q13 publication call.

Ask

  • Alexander: authorise the cp of collector 4e45021d… + gate 085ddf4f… into /root/.helm/bin/, or say to keep iterating. Nothing else in this run needs a decision.

Run 15 landing evidence

Pushed as de74527 (a7b52e5..de74527, remote main), 3 files / +335. Anonymous raw reads at main, all HTTP 200 and byte-identical to disk:

  • recoveries/helm-resolved-root-live-path.md — 15,220 B, sha256 a64f26e740f61cd0e2f305f7f5e915cd269522b85e68c0c51e0709eeba4edd2b
  • checkins/2026-10-13-merlin.md — 36,515 B, sha256 cdfed86a1a0be6886fa4ba1b905084295f6ac43d669fbb8dff15eb0991eefc36
  • WORK-QUEUE.md — 823,541 B, sha256 d0bf9080f9ef61570d30cb85a639b56adbf98bceb3ba30adf2b15e142677b8d2
  • Commit: git -c user.name=Merlin -c user.email=merlin@agents.invalid commit -F /root/crucible/q49/q49-commit-msg.txt → de74527.
  • Scratch tree /root/crucible/q49/ is not committed; the gate copies (helm-selftest-q49.py 085ddf4f42ae80ea…, -nodefault 46ba830cd4b9e690…, -inproc-off d1481ca890fcd543…, -disarmed 63d5409b3502a22e…) and the fixture (env-root-v1.py 76b55b8ab0203c4f…) stay in the scratch tree, reproducible by patch_gate_q49.py and reproduce_q49.py.

—


Run 16 — Q50: the admission probe's environment

Did

Claimed and finished Q50 (Helm lane; the top unclaimed executable item, opened by the pipe in replies/2026-10-13-to-merlin-34.md §Asks 1 with an explicit offer to take it — "the gate is your file and I will not edit it, only propose"). Deliverable: recoveries/helm-probe-spawn-env.md. Queue block appended to WORK-QUEUE.md. Scratch tree /root/crucible/q50/; nothing deployed, no cp into /root/.helm/bin/, decisions/ and inbox/ untouched, no another-party file edited, no secret printed.

The item's three parts, all measured. (1) The spawn's rebuilt environment: the Q48 value-redirect + Q49 default-redirect, factored into one function _q50_rebuild_env(_target) with two callers — the legs (original site, target the legs' sandbox) and the admission probe (target its own tree, hoisted above the spawn because the legs' sandbox does not exist there). (2) The blank cell (armed × named root): the base gate with Q48_ROOT=/root/.helm moves the live held pin 120 B / 5b6d7071… → 14 B / 784b9bde… (guard-restored; the defect reproduced from this host, same payload digest as my Q49 attribution record); the Q50 gate in the same cell holds delta 0 with the value redirect firing (Q50 NOTE … 1 value redirect(s) … Q48_ROOT /root/.helm -> <probe tree>). (3) The detector: a per-window census of both live objects around the spawn — a move is restored byte-exact in-gate, recorded, printed as a dated Q50 DETECTOR note, and fails the named check. Exercised on the disarmed variant (prevention cut): the pin moves inside the gate, is restored, and the foot prints FAIL Q50 the admission probe's spawn moved neither live object (165/10 against the armed rows' 166/9 — the counts isolate the check; the 9 fixture-subject failures are pre-existing scratch-root checks, identical on the base gate).

The pair. Collector byte-identical to Q33–Q49's (4e45021d…, 29,954 B, measured by sha256) — every change is in the gate. Gate a951dbe87d3394e0… (134,086 B / 2,552 lines / 125 check( registrations, 2 × check("Q50" in mutually exclusive branches) on the Q49 gate 085ddf4f… (128,948 / 2,445 / 123, digest verified against the queue's record); out/DIFF-vs-q49.txt = 388 lines = 5 hunks + 226 added − 119 removed, and 2,445 + 226 − 119 = 2,552 exactly. Disarmed discriminator 6b1c431f… — one line different (the spawn's env= removed).

Green pair, five consecutive invocations (run_green_q50.py, subject /root/crucible/q48/helm-collect.py, Q48_ROOT unset): rc 0 each, 175 passed / 0 failed, ALL GATES PASS, 13,929 B stdout, 13.82–15.11 s, digests b5391473 / dd0b0989 / d8905c97 / 21e04379 / aea1ebb3, live delta 0 on all five. 175 = 174 + 1; no pre-existing check moved. Regressions 11/11 (run_regressions_q50.py): n1–n5, noparse (Q46 REFUSAL), dep-unparseable (repair 3), undecodable (Q47 REFUSAL), broken_dep (Q35 REFUSAL) rc 2; latin1 and bom green 175/0; live delta 0 on all 11.

The full matrix, all five cells (run_matrix_q50.py, subject env-root-v1.py, each under the digest-verified guard q50_guard.py): base × named MOVED (above); armed × unset delta 0 (0 value + 1 default redirect); armed × named delta 0 (1 value redirect — the blank cell); disarmed × unset delta 0 (the probe copy's own Q45 literal relocation covers the default shape — the Q50 redirect is load-bearing only in the named cell); disarmed × named delta 0 with the detector firing (in-gate restore). The other probe files count in the Q39 OK line is the tell: 1 on armed rows (the redirected write lands inside the probe tree, counted by the containment census), 0 on dis-named (the write went live, and only the window census sees it).

Live state, delta 0 across all 27 invocations (5 green + 5 matrix + 11 regressions + guard reads): snapshot 14,039 B / aa842b0fd88037f8… / mtime_ns 1791479579475780303; held pin 120 B / 5b6d70716153c3f4… / mtime_ns 1791478687099553071. ctime_ns moved twice (the in-gate detector restores + the guard restore of the base row) — disclosed, not hidden. Deployed bin untouched (ee0b36a8… / 7ed1bca8… / 12570786… / 73869998…, grep -c HELM_COLLECTOR on the deployed gate = 0 — Q40's finding stands). Final tree: 0 sandboxes. Nothing of Q31–Q50 is in production.

Three defects of mine, logged first in the deliverable: the green runner's first attempt used the deployed collector (ee0b36a8…, the pre-Q33 collector — Q40's finding) and was refused by Q35; re-run with the Q33–Q48 subject. The matrix/regression extractors matched lines starting with Q50 while the foot prints PASS Q50 …; the Q50 lines were re-derived from the saved logs (figures_q50.py), no invocation re-run. The disarmed variant still prints the Q50 NOTE although the env it names is not the one the spawn receives — a scratch discriminator's known inaccuracy.

Blocked

Nothing in my lane. The named follow-on (record §7.2): hoist the run-wide held census (_q44_held_before, taken after the spawn) above the probe so the per-run instrument sees the window too. Same standing gates, all Alexander's: the §4 adoption cp — now collector 4e45021d… + gate a951dbe8… (superseding 085ddf4f…, which the pipe made conditional on this item) — Q9, Q13, Q19, Q42.

Next

  1. The pipe's verification of this run, when it lands. Everything re-runs from /root/crucible/q50/: patch_gate_q50.py, run_green_q50.py, run_matrix_q50.py, run_regressions_q50.py, figures_q50.py.
  2. The held-census hoist above (my named follow-on) and Merlin's Q45 §9 follow-on both stay open and unclaimed.
  3. Q7, measured: the Helm lane's executable set is empty again. No new item opened — the next Helm unit after the two follow-ons is a decision, not a task.

Ask

Alexander: nothing blocking. The standing items, consolidated: (a) rule on the §4 adoption cp — collector 4e45021d… + gate a951dbe8…, the pair that makes python3 helm-selftest.py green with no environment and puts Q31–Q50's protection into production; (b) the manifest_match pin decision (stale since 2026-10-08); (c) the Q13 publication call (item 13's decided note still controls over its proposed_action).

Run 16 landing evidence

Pushed as its own commit (git -c user.name=Merlin -c user.email=merlin@agents.invalid), read back over the anonymous raw path (https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>), no credential — each HTTP 200 and cmp byte-identical on three sides (served = disk = git cat-file -p <rev>:<path>). Table and digests land with the push; the check-in's own row cites the revision it was written against, per the lane's no-self-hash convention.

Read back over the anonymous raw path (https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>), no credential — each HTTP 200 and cmp byte-identical on three sides (served = disk = git cat-file -p 4c6cd50:<path>), read at 2026-10-13T11:26:50Z; method python3 /root/crucible/q50/readback_q50.py, exit 0, VERDICT: ALL READBACKS IDENTICAL, artifact out/Q50-READBACK.json:

file HTTP / bytes sha256 (served = disk = git)
recoveries/helm-probe-spawn-env.md 200 / 15,287 4b557db28dbaad1b5758cd3c136fded70f415cec725f282d877937014bcb4ff5
WORK-QUEUE.md 200 / 835,449 d6e8f7c8aa3baf0a634fbd5f4c37064ce856450a40b3ec352d3751ef404e5f8a
checkins/2026-10-13-merlin.md 200 / 44,489 (the committed revision 4c6cd50 — a file cannot hash itself, so this row cites the revision it was written against; this fill lands as its own commit) b432037fd1f7be6f67f50fef2656107c946a78a950ae8cbe64d38384dda21d48

Re-measured after the push, from this host: the live snapshot /root/.helm/data/snapshot.json is 14,039 B / sha256 aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d and the held pin /root/.helm/data/held/stackchain-home.html.sha256 is 120 B / 5b6d70716153c3f4… — delta 0 on both across the whole run; the deployed /root/.helm/bin/ is untouched (ee0b36a82f23fcf3… / 7ed1bca8f9da624f… / 12570786ba703787… / 7386999867789694…). Nothing was deployed, published, rebuilt or re-run beyond the measurements above; decisions/ and inbox/ were not touched; no another-party file was edited; no secret is printed in this check-in or in the files it lands — the long strings are gate check names, refusal messages, file paths and sha256 digests. This run's commits are authored Merlin <merlin@agents.invalid> (git -c), so the monitor sees them as counterparty content per Q36's v1.3 rule.

— Merlin

2026-10-13 — merlin (Run 17)

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 17 — Q51: the run-wide census hoist

Did

Claimed and finished Q51 — the run-wide census hoist (Helm lane; the top unclaimed executable item, opened by the pipe on 2026-10-13 and explicitly assigned to me: "Q51 (hoist the run-wide census above the probe) is Merlin's, and the gate is his file"). Deliverable: recoveries/helm-runwide-census-hoist.md (12,041 B / sha256 0ab0cc10829e14823b76267b6438392fcaca78884d0b404d2f764069f88904a8, this host). Queue block appended to WORK-QUEUE.md. Scratch tree /root/crucible/q51/; nothing deployed, no cp into /root/.helm/bin/, decisions/ and inbox/ untouched, no another-party file edited, no secret.

The defect, measured before anything changed. base-q49-named (Q49 gate 085ddf4f…, subject env-root-v1.py, Q48_ROOT=/root/.helm): the admission probe wrote the live held pin — the guard's delta record says MOVED and restored it byte-exact — and the run-wide Q44 check passed (165 passed / 9 failed). The baseline was read after the write, so before == after; the live write was caught only by the guard, outside the gate. Ordering cited to the line on the Q50 gate (a951dbe8…, 134,086 B / 2,552 lines): the probe spawn at :917, the run-wide _q44_held_before read at :1388 — 471 lines later.

The pair. Collector untouched — the change is in the gate only, as the item's note requires. Gate e4967da9bdc4537802993523c7044a762a9a6366576df4e4234444789310107e (134,427 B / 2,558 lines / 125 check( registrations, unchanged) on the Q50 gate a951dbe87d3394e030e16139781d447d86958818c186cc8ee296e4ed23ebaa10 (134,086 / 2,552 / 125). out/DIFF-vs-q50.txt (76 lines / sha256 c8b2ac1367fbe5f2…) = 2 hunks + 33 added − 27 removed, and 2,552 + 33 − 27 = 2,558 exactly. The diff is a pure move: the Q44 census machinery was cut from its old site (a dated note left behind) and re-inserted above the probe branch — before-read :890, branch :893, spawn :948, foot census :2477, asserted by the patch script's own ordering assert, not by inspection. Disarmed twin (the spawn's env= removed — the same one-line cut Q50's pair carried): b1d969767f347d179ce14df1803bef1fa409d880beeafc8b898e34cf57d63add (134,378 B / 2,557 lines / 125), 49 B and one line smaller than the armed gate.

The item's two cells, verbatim. Blank cell, shipped gate, Q48_ROOT=/root/.helm (q51-armed-named): 166/9, Q44 PASS and Q50 PASS, run-wide and window delta both {}. Disarmed discriminator (q51-dis-named): 164/11, Q50 window check FAIL (the detector prints the moved object and restores byte-exact) and the run-wide Q44 check also fails and names the same object — before={"/root/.helm/data/held/stackchain-home.html.sha256": [120, "5b6d70716153c3f4…", 1791478687099553071, 1791898508989942384]} after={… [120, "5b6d70716153c3f4…", 1791478687099553071, 1791898514021357042]}.

The finding beyond the item's criterion. Before and after are identical on size, sha256 and mtime — the window detector restored byte-exact — and the run-wide check fails on ctime alone. The run-wide instrument cannot be fooled by a restore, because ctime is the stamp a restore cannot undo (Q43's discriminator, now load-bearing in the run-wide instrument rather than only the window one). Two caveats, stated in the record: the run-wide failure is attributable to the restore trace, not to a persisted byte change (the Q50 window check is what names the write itself), and the property is inherited from the census's four-field shape, which the move did not alter.

Green pair, five consecutive invocations (run_green_q51.py, subject /root/crucible/q48/helm-collect.py 4e45021d…, Q48_ROOT unset; logs out/q51-green-{1..5}): rc 0 each, 175 passed / 0 failed — the Q50 count exactly, no check added — 13,929 B stdout, 12.41–13.04 s, live delta {} each. The green log carries both instruments green: PASS Q44 the live held directory is unchanged by every leg in the run and PASS Q50 the admission probe's spawn moved neither live object.

Regressions 11/11 (run_regressions_q51.py → out/Q51-REGRESSIONS.json): n1–n5, noparse, dep-unparseable, undecodable, broken_dep rc 2 (Q39 refusals / Q46 parse guard / repair 3 / Q47 read path); collector-latin1.py and collector-bom.py green at 13,929 B — the read-path fix's subjects unaffected by the hoist. Live delta {} on all 11. VERDICT: ALL REGRESSIONS HOLD.

Live state, delta 0 on bytes/sha256/mtime across all 32 invocations (5 green + 5 matrix + 11 regressions + 11 void runs, defect 1): snapshot /root/.helm/data/snapshot.json 14,039 B / aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d / mtime_ns 1791479579475780303; held pin /root/.helm/data/held/stackchain-home.html.sha256 120 B / 5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297 / mtime_ns 1791478687099553071 — identical to every prior run's record. ctime moved on both objects (1791898508989942384 / 1791898514021357042), the in-gate and guard restores; disclosed. Final tree 0 sandboxes (glob for helm-legs-* / helm-q39-* → []); disk 45 GiB free of 153. Deployed bin untouched (ee0b36a8… / 7ed1bca8… / 12570786… / 73869998…) — none of Q31–Q51 is in production.

Four defects of mine, logged first in the deliverable. (1) The first regression run was void: the q51 tree was built by copying the runners, not fixtures/, so all 11 ran against nonexistent paths and were refused by Q35's source precondition (0 B stdout) — no gate body executed, live delta 0 throughout, re-run after cp -r; the void logs are not on disk. (2) The matrix JSON's Q44/Q50 cells are empty — the extractors matched line prefixes while the foot prints PASS Q44 …, the same comparator defect class the Q50 record logged against its own figures script; §3 is re-derived from the saved logs by show_matrix.py, no invocation re-run, and the empty cells were not edited after the fact. (3) rm -rf is blocked in this shell, so the copied fixtures tree carries __pycache__ — harmless here, and the adoption cp must not copy it in (C32). (4) The green runner's assertion covers bytes+sha256 but not the ctime trace, which §6 discloses instead.

Blocked

Nothing in my lane. Same standing gates, all Alexander's: the §4 adoption cp — now collector 4e45021d… + gate e4967da9… (superseding a951dbe8…); Q40's finding stands (the deployed gate 7ed1bca8… reads HELM_COLLECTOR zero times), so none of Q31–Q51's protection is in production until it lands — Q9 (checksum handover), Q13 (wording fixes), Q19 (wizard onboarding), Q42 (zephyrus's).

Next

  1. The pipe's verification of this run, when it lands. Everything re-runs from /root/crucible/q51/: patch_gate_q51.py (count-asserted edits; aborts on a miscount), run_green_q51.py, run_matrix_q51.py, run_regressions_q51.py, show_matrix.py, final_state.py.
  2. Merlin's Q45 §9 follow-on stays open and unclaimed — the only named Helm unit left: resolve every path the subject declares at runtime, rather than rewriting the literals it declares statically. The hoist instruments the run; it does not relocate a runtime-composed root.
  3. Q7, measured: the Helm lane's executable set is empty again. The adoption, Q9, Q13/Q19 and Q42 are human- or counterparty-gated. No new item opened — the next Helm unit after the Q45 §9 follow-on is a decision, not a task.

Ask

Alexander: nothing blocking. The standing items, consolidated: (a) rule on the §4 adoption cp — collector 4e45021d… + gate e4967da9…, the pair that makes python3 helm-selftest.py green with no environment and puts Q31–Q51's protection into production (the deployed gate today has no subject-selection path at all); (b) the manifest_match pin decision (stale since 2026-10-08; a static render cannot say so); (c) the Q13 publication call (item 13's decided note — escalate, do not edit the live page — still controls over its proposed_action).

Run 17 landing evidence

Pushed as its own commit (git -c user.name=Merlin -c user.email=merlin@agents.invalid), read back over the anonymous raw path (https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>), no credential — each HTTP 200 and cmp byte-identical on three sides (served = disk = git cat-file -p <rev>:<path>). Table and digests land with the push; the check-in's own row cites the revision it was written against, per the lane's no-self-hash convention.

— Merlin


Run 17 landing evidence

Read back over the anonymous raw path with no credential (https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>) and byte-compared on three sides — the bytes the server served, the bytes on disk, and git cat-file -p 57d8e6b:<path> — by python3 /root/crucible/q51/readback_q51.py, exit 0, VERDICT: ALL READBACKS IDENTICAL, artifact out/Q51-READBACK.json, read at 2026-10-13T13:5xZ:

file HTTP / bytes sha256 (served = disk = git)
recoveries/helm-runwide-census-hoist.md 200 / 12,041 0ab0cc10829e14823b76267b6438392fcaca78884d0b404d2f764069f88904a8
WORK-QUEUE.md 200 / 871,015 3d47d296b1ba19b3…
checkins/2026-10-13-merlin.md 200 / 55,478 a79488adfb246931…

Push: da28ef0..57d8e6b on main, 3 files / +314 −1, authored Merlin <merlin@agents.invalid>. The queue's own byte count moved 871,016 → 871,015 with the digest correction in §Did's block — the placeholder digest was one character longer than the measured one; the readback's three-way compare is the authority.

Re-measured after the push, from this host: the live snapshot /root/.helm/data/snapshot.json is 14,039 B / sha256 aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d and the held pin /root/.helm/data/held/stackchain-home.html.sha256 is 120 B / 5b6d70716153c3f4… — delta 0 on bytes, sha256 and mtime_ns across the whole run; the deployed /root/.helm/bin/ is untouched (ee0b36a8… / 7ed1bca8… / 12570786… / 73869998…). Nothing was deployed, published, rebuilt or re-run beyond the measurements above; decisions/ and inbox/ were not touched; no another-party file was edited — the pipe's replies/2026-10-13-to-zephyrus-66.md and the Q53 career-lane block it landed in WORK-QUEUE.md (da28ef0) were read, not touched; no secret is printed in this check-in or in the files it lands — the long strings are gate check names, refusal messages, file paths and sha256 digests. This run's commit is authored Merlin <merlin@agents.invalid> (git -c), so the monitor sees it as counterparty content per Q36's v1.3 rule.

— Merlin


Run 18 — the Q45 §9 follow-on: the home-directory channel

Screen

Merlin, Helm lane, 2026-10-13, this host. Item: the named Q45 §9 follow-on — resolve every path the subject declares at runtime, rather than rewriting the literals it declares statically — the one Helm unit the queue's own open set carried as mine and unclaimed (the pipe's 15:37Z block lists it by name; Q52 is Mercury's and is not touched here). Deliverable: recoveries/helm-home-channel-guard.md (13,173 B / sha256 3f813ca23202590c675f7ac7587f0d5e7d8b0ff9ee9f4f0711996530a2d6d7db, this host). Queue block appended to WORK-QUEUE.md (897,771 B after the append). Scratch tree /root/crucible/q52/; nothing deployed, no cp into /root/.helm/bin/, decisions/ and inbox/ untouched, no another-party file edited, no secret.

Did

The class, and why every existing mechanism missed it. HELM_HOME = Path.home() / ".helm" composes the live root at runtime from the user database: CPython's posixpath.expanduser reads HOME itself, so Q45's literal scan sees only ".helm" (not absolute), Q48's env inventory finds no os.environ access in the subject's own AST, Q49's default redirect keys on that same inventory, and Q48's argv rule sees no root argument. The channel is live in the shipped subject: the real collector calls Path.home() twice (lines 297–298 of /root/crucible/q48/helm-collect.py, 4e45021d…, 720 / 29,954) for its himalaya config search.

The pair. Collector byte-identical (measured by sha256) — every change is in the gate. Gate 78b290ecf2d93e0c… (140,365 B / 2,677 lines / 126 registrations) on the Q51 gate e4967da9… (134,427 / 2,558 / 125); out/DIFF-vs-q51.txt = 169 lines = 6 hunks + 122 added − 3 removed, 2,558 + 122 − 3 = 2,677 exactly. Disarmed twin be7b306a… (140,390 / 2,677 / 126), one line different. Mechanism: an ast inventory of home-database reads (_q52_home_sites, :786) and, inside Q50's one rebuild function (two callers — probe :977, legs :1162), a redirect of HOME + USERPROFILE to <target>/q52-home; a conditional Q52 NOTE on stderr and one new check("Q52") (:1204). A --q52-witness extra flag (:1261) runs the copy with --deploy --pin --skip-tests --out <sandbox dest> — the pin shape the suite refuses (Q44's rule) — because the class's write path is structurally unreachable from the green run.

Fixtures, verified against the interpreter first (make_fixtures_q52.py): collector-home.py (d62888c4c9470d30…, 29,956 B) and collector-expanduser.py (99c49d395467709d…, 29,974 B), each py_compile-clean and each resolving HELM_HOME /tmp/<scratch>/.helm under a scratch HOME — the class measured, not asserted.

Green pair, five consecutive invocations (run_green_q52.py): rc 0 each, 176 passed / 0 failed (= 175 + 1), ALL GATES PASS, 14,044 B stdout / 1,216 B stderr, 12.34–12.73 s, live delta {}. The real collector's own .home() read makes the check non-vacuous: PASS Q52 the subject's home-directory reads resolve inside the sandbox when the subject reads the home database, Q52 NOTE: … HOME redirected to <sandbox>/q52-home (/root -> <sandbox>/q52-home) (out/q52-green-1.{out,err}). Q44 and Q50 stay green on the same runs.

The discriminator, five cells under the digest-verified guard (run_matrix_q52.py → out/Q52-MATRIX.json): armed × collector-home.py — the copy resolves HELM_HOME=<sandbox>/q52-home/.helm, the pin lands at q52-home/.helm/data/held/stackchain-home.html.sha256 inside the sandbox, live delta 0; armed × collector-expanduser.py — same, on the second channel; disarmed × home — HOME stays /root, the copy resolves HELM_HOME=/root/.helm and the live pin moves to sha256 caff1f504855264a… / mtime_ns 1791907100434371499, restored byte-exact by the guard; disarmed without the witness flag — the foot's own check fails (FAIL Q52 … home_reads=['.home()'] HOME='/root' expected='<sandbox>/q52-home', 174 passed / 2 failed); direct invocation, ambient env — the live pin moves, guard restores (the class's floor). Prevention and detection measured separately.

Regressions 11/11 (run_regressions_q52.py → out/Q52-REGRESSIONS.json): nine refusals rc 2 (n1–n5, noparse, dep-unparseable, undecodable, broken_dep); collector-latin1.py and collector-bom.py green at 14,044 B; live delta {} on all eleven. VERDICT: ALL REGRESSIONS HOLD.

Live state, delta 0 on bytes/sha256/mtime across all 21 invocations (5 green + 5 matrix + 11 regressions): snapshot 14,039 B / aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d / mtime_ns 1791479579475780303; held pin 120 B / 5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297 / mtime_ns 1791478687099553071. ctime moved on both objects (1791907371554631194) — the guard restores of the two deliberately-live rows; disclosed, not hidden. Final tree 0 sandboxes; deployed /root/.helm/bin/ untouched (7ed1bca8…, grep -c HELM_COLLECTOR = 0 — Q40 stands); disk 46 GiB free of 154.

Five defects of mine, logged first in the deliverable: the witness's missing local subprocess import; the witness anchored before the leg copy was written; the witness's live census reading the held directory (IsADirectoryError); the NOTE claiming a redirect that had not fired (the disarmed twin's own FAIL contradicted it — the NOTE is now derived from the actual environment); and the first matrix measuring nothing because the real collector pins only under --pin, which the suite refuses — the witness flag exists because of that.

Blocked

Nothing in my lane. Same standing gates, all Alexander's: the §4 adoption cp — now collector 4e45021d… + gate 78b290ec… (superseding e4967da9…); Q40's finding stands (the deployed gate 7ed1bca8… reads HELM_COLLECTOR zero times), so none of Q31–Q52's protection is in production until it lands — Q9 (checksum handover), Q13 (wording fixes), Q19 (wizard onboarding), Q42 (zephyrus's).

Next

  1. The pipe's verification of this run, when it lands. Everything re-runs from /root/crucible/q52/: make_fixtures_q52.py, patch_gate_q52.py, run_green_q52.py, run_matrix_q52.py, run_regressions_q52.py, final_state.py.
  2. The Helm lane's executable set is now empty. The Q45 §9 follow-on is closed; the adoption, Q9, Q13/Q19 and Q42 are human- or counterparty-gated. No new item opened — the next Helm unit is a decision, not a task. The two limits the record states as the item's own — the original-subject legs' ambient environment (Q48's residual) and pwd.getpwuid() bypassing HOME — are the only named candidates, and neither is a task until someone says the class matters.

Ask

Alexander: nothing blocking. The standing items, consolidated: (a) rule on the §4 adoption cp — collector 4e45021d… + gate 78b290ec…, the pair that makes python3 helm-selftest.py green with no environment and puts Q31–Q52's protection into production (the deployed gate today has no subject-selection path at all); (b) the manifest_match pin decision (stale since 2026-10-08); (c) the Q13 publication call (item 13's decided note — escalate, do not edit the live page — still controls over its proposed_action).


Run 18 landing evidence

Read back over the anonymous raw path with no credential (https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>) and byte-compared on three sides — the bytes the server served, the bytes on disk, and git cat-file -p c559d33:<path> — by python3 /root/crucible/q52/readback_q52.py, exit 0, VERDICT: ALL READBACKS IDENTICAL, artifact out/Q52-READBACK.json, read at 2026-10-13 ~16:1xZ after the push 0c190a4..c559d33:

file HTTP / bytes sha256 (served = disk = git)
recoveries/helm-home-channel-guard.md 200 / 13,173 3f813ca23202590c675f7ac7587f0d5e7d8b0ff9ee9f4f0711996530a2d6d7db
WORK-QUEUE.md 200 / 897,771 e8da72cff24460ec…
checkins/2026-10-13-merlin.md 200 / 65,145 d89b2189e69ba6ff…

The check-in's own row cites the committed revision c559d33, which is what the server served at readback time and what git cat-file -p c559d33:checkins/2026-10-13-merlin.md reproduces locally — a file cannot hash itself, so this row cites the revision it was written against; this fill lands as its own commit.

Re-measured after the push, from this host: the live snapshot /root/.helm/data/snapshot.json is 14,039 B / sha256 aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d / mtime_ns 1791479579475780303 and the held pin /root/.helm/data/held/stackchain-home.html.sha256 is 120 B / 5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297 / mtime_ns 1791478687099553071 — delta 0 on bytes, sha256 and mtime_ns across the whole run; the deployed /root/.helm/bin/ is untouched (ee0b36a8… / 7ed1bca8… / 12570786… / 73869998…). Nothing was deployed, published, rebuilt or re-run beyond the measurements above; decisions/ and inbox/ were not touched; no another-party file was edited; no secret is printed in this check-in or in the files it lands — the long strings are gate check names, refusal messages, file paths and sha256 digests. This run's commit is authored Merlin <merlin@agents.invalid> (git -c), so the monitor sees it as counterparty content per Q36's v1.3 rule.

— Merlin


Run 19 — Q45§9: corrections to the record

Screen

Merlin, Helm lane, 2026-10-13, ~18:2x–18:4xZ, this host. Item: record correctness on the Q45§9 home-directory deliverable — the corrections replies/2026-10-13-to-merlin-37.md §2 left open on this lane's own file, each verified against Run 18's retained artifacts rather than re-run. Deliverable: recoveries/helm-home-channel-guard.md (21,230 B / sha256 953ea1a14c5fa49b6d2d8e0d8324a8ac9d739ca4c39695646a5c05ae9cbf37fb after the append; 13,173 B / 3f813ca23202590c… before it, the value reply 37 verified). Queue block appended inside the item's own section (WORK-QUEUE.md 904,744 B / 72770fef8eaa4225… before the append, head dba77c2b, the pipe's 16:27Z commit). Scratch tree /root/crucible/q52/; nothing deployed, no cp, no gate invocation, no live write; decisions/ and inbox/ untouched; no another-party file edited; no secret printed.

Did

The label collision, closed by renaming in prose. The item is Q45§9, not Q52: WORK-QUEUE.md:7167 is Mercury's Q52, the queue's own section for this unit is Q45 §9 follow-on — the home-directory channel, and the c559d33 commit subject already reads the Q45 s9 follow-on. The gate's internal check("Q52", …) and its _q52_* helpers are deliberately not renamed — renaming changes helm-selftest-q52.py's digest and would invalidate the byte-level verification reply 37 performed against it. Internal check names are identifiers inside a verified artifact, not queue item ids.

The gate digest, in full, and the commit-subject defect measured. sha256sum /root/crucible/q52/helm-selftest-q52.py → 78b290ecf2d93e0cc3087e5ede8baef5c10ca52986706d5da69a13a619dbdd9f (64 hex, 140,365 B / 2,677 lines / 126 check( registrations). git -C /root/troupe-standup log -1 --format=%s c559d33 carries the same digest as a 63-character string, one c dropped at index 16 (…d93e0c|3… against the measured …d93e0c|c3…), lengths printed by len(). A commit message cannot be corrected by edit, so the correction lives in the record and the queue.

The unverified figure isolated. grep -rn 'caff1f504855264a' /root/crucible/q52/ → 3 hits, all this lane's prose (q52-commit-msg.txt:5, q52-queue-block.md:39, checkin-run18.md:50), 0 in out/; grep -rln '1791907100434371499' → the same three files. The retained out/Q52-MATRIX.json (12,308 B / 75bd624ef25c5667b81f7a77f8d0fed358305f4a41fbb7fc05a185eaf4cf6a8a, generated_at 2026-10-13T16:02:51+0000) records the disarmed row's move as 10d12a7d20c5f0ac… / mtime_ns 1791907358370548372 and the raw row's as 576a47723957844e… / 1791907371509627497, both guard_restored: true. Direction Corroborated, §5's cited figure unverified — most likely the overwritten first matrix.

The readback pairing, stated. out/Q52-READBACK.json (675 B / b0f74587967126e9…) carries read_at 2026-10-13T16:09:11Z, "revision": "6954cc6", and its check-in row is 67,347 B / 912985e3…; the record's landing table's 65,145 B / d89b2189… is the same file at c559d33. Rule: read a readback artifact's revision field before comparing a row against a table row.

Four line citations corrected, one row completed. Read by grep -n in helm-selftest-q52.py: _q52_home_sites :786 → :758, the legs' _q50_rebuild_env caller :1162 → :1160, check("Q52", …) :1204 → :1205, the --q52-witness flag test at :1270; and §5's q52-dis-check row names one failing check where out/q52-dis-check.out:186–187 carries two — the second (FAIL Q45 … HELM_HOME: /root/.helm) being the expected consequence of the redirect cut, not a surprise.

The delta phrasing. "Delta 0 across all 21 invocations" is a net end-state; the honest form is net zero, with two disclosed transient movements — exactly two of the five matrix rows carry a non-empty guard_live_delta with guard_restored: true, and final_live_delta is {}.

Live state, re-measured 2026-10-13T18:18:06Z, delta 0. Snapshot /root/.helm/data/snapshot.json 14,039 B / aa842b0fd88037f8… / mtime_ns 1791479579475780303; held pin 120 B / 5b6d70716153c3f4… / mtime_ns 1791478687099553071; ctime 1791907371554631194 on both, unmoved since Run 18 (the restore trace). Deployed /root/.helm/bin/ untouched (ee0b36a82f23… / 7ed1bca8f9da… / 5c67473d8928… / 12570786ba70… / 738699986778…), HELM_COLLECTOR count 0 — Q40 stands, so none of Q31 through Q45§9's mechanisms is in production. df -h / → 46 G free of 154, 71 % used; sandbox census both ways (glob and rglob) → [] / [].

Blocked

Nothing on this lane. The only blockers are human decisions, listed under Ask. The Q51 record's 45 GiB free of 153 disk figure is a dated reading against today's 46 of 154, not a defect, and no count in that record depends on it — carried, not corrected.

Next

The Helm lane's executable set is empty again after this run: Q42 is zephyrus's, Q52 is Mercury's, Q53 is held for Alexander, and the named Q45§9 limits (the original-subject legs' ambient environment; pwd.getpwuid().pw_dir bypassing HOME) stay named and unopened until someone says the class matters. No new item opened — the next Helm unit is a decision, not a task.

Ask

Alexander's, unchanged and now with the corrected digest: (a) the §4 adoption cp — collector 4e45021d… + gate 78b290ecf2d93e0cc3087e5ede8baef5c10ca52986706d5da69a13a619dbdd9f (superseding e4967da9… and a951dbe8…) — 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, where item 13's decided note (escalate, do not edit the live page) still controls over its proposed_action; (d) Q9's audio-checksum handover; (e) Q19's wizard onboarding. No ask of the pipe this run: reply 37's §2 asks are answered by this run's three appends, and replies/ is the pipe's channel, so nothing was written there.

— Merlin


Run 20 — the record-correction tick: four returned corrections discharged, two of my own found

Screen

Every claim below carries a path, a hash, a command with its output, or the word unverified. Read-only: no gate invocation, no fixture run, no live write, no cp into /root/.helm/bin/, no edit to another party's file, no decisions/ or inbox/ touch, no secret printed. Instrument /root/crucible/q53/measure.py and measure2.py; durable artifact out/Q53-MEASUREMENTS.json. The queue's executable set had no unclaimed item left — Q42 is zephyrus's, Q52 is Mercury's, Q53 and Q9/Q13/Q19 are Alexander's — so this unit is the Helm lane's own outstanding debt: the four corrections replies 38, 39 and 40 returned against recoveries/helm-home-channel-guard.md.

Did

Four corrections returned by the pipe, each discharged with its own measurement. Appends E10–E16 in recoveries/helm-home-channel-guard.md (21,230 B / 953ea1a14c5fa49b… → 31,219 B / 0f8b7f1617a67f5e…, +159/−0), and a Run-20 block in WORK-QUEUE.md (919,333 B / c5fa27ea61cf43de… → 925,786 B / 78feb8441d8f01183…, +16/−0). Nothing above the appends was edited.

  • E10 — E4's legs-caller row corrected: :1162, not :1160. grep -n '_q50_rebuild_env(' /root/crucible/q52/helm-selftest-q52.py → :815 (def), :977 (probe caller), :1162 (legs caller: _q48_env, _q48_redirects, _q48_default_redirects, _q52_home_redirect = _q50_rebuild_env(_q43_dir)). :1160 and :1161 are the two comment lines above it — a comment read as code, which is where the wrong number came from. §2's own cite was right; the erratum's cell was the defect. Reply 38's finding upheld.
  • E11 — E2's grep count restated, scoped and dated. The command as written, grep -rn 'caff1f504855264a' /root/crucible/q52/, returns 9 lines in 8 files at 20:5xZ (run19_append_record.py 2, the other seven 1 each); out/ returns 0 (rc 1); the repository tree at HEAD returns 15 lines in 6 files. The 3 the record printed is a Run-18-era reading — the three scratch prose files it names (q52-commit-msg.txt:5, q52-queue-block.md:39, checkin-run18.md:50, mtime 16:06–16:07Z) carry 1 each and were the only files under the tree holding the string until Run 19's own five scripts (created 18:13–18:35Z) quoted the string they were written to test. Finding unchanged: §5's caff1f50… / 1791907100434371499 figure stays unverified — no artifact carries either string. Direction Corroborated by out/Q52-MATRIX.json's two guard_restored: true rows (10d12a7d20c5f0ac… / 1791907358370548372 and 576a47723957844e… / 1791907371509627497) with final_live_delta {}.
  • E12 — the Run-19 landing block's readback clock is 18:30:31Z, not 18:31:0xZ. out/Q45S9-RUN19-READBACK.json (1,686 B / sha256 ccec083ce40f53242ab469f96529d9047eb525047891bedd4b492256fa45b39d) records "read_at": "2026-10-13T18:30:31.084749+00:00", "revision": "068ac5f"; epoch 1791916231.084749. A ±360 s band census over the tree reproduces the pipe's supporting measurement to the millisecond: the next write after the read is run19_append_landing.py at +160.699 s = 18:33:11.78Z, the script that wrote the block. The window is real; only the printed clock was wrong, and no figure depends on it (head was 068ac5f until 18:34:22Z).
  • E13 — out/Q45S9-RUN19-READBACK.json is host-local, not forge-verifiable. git -C /root/troupe-standup ls-tree -r --name-only HEAD → 244 paths, 0 under out/ (50 under recoveries/); no worktree out/; GET …/raw/branch/main/out/Q45S9-RUN19-READBACK.json → HTTP 404, 11 bytes. The artifact is real and its three rows each carry http: 200, served_eq_disk: true, served_eq_git: true, but it lives only on this host. Stated as a property of the lane, not fixed: publishing the artifacts is a visibility decision.

Two findings of my own, both from re-reading rather than from being told.

  • E14 — the sandbox census is tree-scoped; the whole-crucible census is 26. E7's both ways → [] / [] is true of the q52 tree (shallow glob and recursive rglob both empty) and E7 names the tree, so the sentence is not false. The recursive census over /root/crucible is 26: 19 helm-legs-* (q43 ×1, q43/variants ×2, q43z/variants ×1, q44 ×2, q45/variants ×13) and 7 helm-q39-* (q48). None is in a live path and none is reachable from a gate run, so nothing is broken — but the standing line should read 0 in the q52 tree; 26 across /root/crucible. This is the skill's own logged lesson applied to my own record.
  • A sixth line-citation defect. E4's --q52-witness row puts the section comment at :1261; grep -n '--q52-witness' returns :1262 (the comment) and :1270 (the flag test). The flag test was right; the comment is one line lower. Same family as E10.

E15 — the rest of the record re-derives, measured not accepted. Gate 78b290ecf2d93e0c… 140,365 B / 2,677 lines / 126 check(; disarmed twin be7b306a… 140,390 B; _q52_home_sites :758; _q50_rebuild_env :815; probe caller :977; check("Q52", …) :1205; out/Q52-MATRIX.json 12,308 B / 75bd624e… at generated_at 2026-10-13T16:02:51+0000; out/q52-dis-check.out 191 lines, 174 passed, 2 failed with the two FAILs at :186 (the Q52 home-redirect check) and :187 (the Q45 module-constant check, HELM_HOME: /root/.helm and HELD_DIR: /root/.helm/data/held escaping the cut redirect) — E3 re-derives exactly.

Live state, delta 0 across every measurement in this run. Snapshot /root/.helm/data/snapshot.json 14,039 B / aa842b0fd88037f8… / mtime_ns 1791479579475780303 / ctime_ns 1791907371554631194; held pin 120 B / 5b6d70716153c3f4… / mtime_ns 1791478687099553071 / ctime_ns 1791907371554631194 — bytes, sha256 and mtime_ns identical before and after, and ctime unmoved, so it is still Run 18's restore trace and not a new write. Deployed /root/.helm/bin/ untouched (ee0b36a82f23… 27,907 / 5c67473d8928… 21,766 / 7ed1bca8f9da… 33,647 / 12570786ba70… 3,556 / 738699986778… 1,463), HELM_COLLECTOR count 0 — Q40 stands, so none of Q31–Q45§9 is in production. df -h / → 46 G avail of 154, 71 % used.

Blocked

Nothing on this lane. The Helm lane's executable set is empty again after this run, and it has been since Run 19: every named follow-on is either a counterparty's (Q42 is zephyrus's, Q52 is Mercury's) or Alexander's (the §4 cp, the manifest_match pin, Q13, Q9, Q19, Q53). The two named Q45§9 limits — the original-subject legs' ambient environment, and a subject reading pwd.getpwuid(...).pw_dir directly so HOME cannot see it — stay named and unopened until someone says the class matters; both are recorded in the record's §Limits.

Next

Nothing outstanding from the pipe: all four corrections returned by replies 38, 39 and 40 are discharged with their own measurements, and the two I found are recorded beside them at E14 and in E15. No new item opened — the queue's open set is Q42 (zephyrus's), Q52 (Mercury's), Q53 and Q9/Q13/Q19 (Alexander's), so the next Helm unit is a decision, not a task. The next time a Helm unit exists it will be one of: the §4 cp landing a gate whose HELM_COLLECTOR support then needs re-measuring in production (Q40's finding is about the deployed file, not about the adoption), or one of the two named §Limits being opened.

Ask

Alexander's, unchanged: (a) the §4 adoption cp — collector 4e45021d… + gate 78b290ecf2d93e0cc3087e5ede8baef5c10ca52986706d5da69a13a619dbdd9f — 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, where item 13's decided note (escalate, do not edit the live page) still controls over its proposed_action; (d) Q9's audio-checksum handover; (e) Q19's wizard onboarding.

No ask of the pipe this run. replies/ is the pipe's channel and nothing here is a counterparty defect — the four corrections it returned are mine and are now discharged — so no reply file was written. The two corrections that belong in the queue rather than in the record (E12's clock and E13's local-artifact label) are appended beside the Run-19 landing block in WORK-QUEUE.md as its own Run-20 block, not edited into the pipe's text.

— Merlin (Run 20)

Run 20 landing evidence

Read back over the anonymous raw path (https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/<path>, no credential) at 2026-10-13 ~21:0xZ, instrument /root/crucible/q53/readback.py. All three rows HTTP 200, served = disk = git cat-file -p 7673477:<path>:

file bytes sha256
recoveries/helm-home-channel-guard.md 31,219 0f8b7f1617a67f5e8308e85b837e3256d74949080750dbabacc0f09f106464fa
WORK-QUEUE.md 925,786 78feb8441d8f01183c5f57c7248366400d7f5d5720bf3b8a10d12c37b73a2c11
checkins/2026-10-13-merlin.md 82,262 9db0834471415e3a6a4d1844910a8f21d3a558305b9a69ea08785b8ec0bcda94

The third row is this file at 7673477, the revision before this append — a file cannot cite its own post-append digest, so the readback row is dated rather than chased. out/Q53-MEASUREMENTS.json and out/Q53-READBACK.txt live only on this host and are local, not forge-verifiable: git ls-tree -r --name-only 7673477 returns 0 paths under out/ and the raw path serves 404 (E13's own rule, applied to this run's artifacts rather than only to Run 19's). Commit 7673477 (Merlin <merlin@agents.invalid>), pushed aa3a806..7673477. Live state unchanged at readback time: snapshot 14,039 B / aa842b0fd88037f8… / mtime_ns 1791479579475780303, held pin 120 B / 5b6d70716153c3f4… / mtime_ns 1791478687099553071, ctime_ns 1791907371554631194 on both; deployed /root/.helm/bin/ untouched, HELM_COLLECTOR count 0.

— Merlin (Run 20, landing)

Run 20 closing note — the final revision is cf07003. Three commits carry this unit: 7673477 (the corrections, +307/−0), dc3c2f7 (the landing evidence and E17, +76/−2) and cf07003 (E18, +22/−1 on the record alone). Read back over the anonymous raw path at 2026-10-13 ~21:2xZ, instrument /root/crucible/q53/readback_final.py, all three rows HTTP 200 and served = disk = git cat-file -p cf07003:<path>, each newline-terminated:

file bytes sha256
recoveries/helm-home-channel-guard.md 34,311 4ba00ce427b85079adedf34524c8334a92e949b205efcc682c8cdd47a99a1cd7
WORK-QUEUE.md 927,009 7754184c5368…
checkins/2026-10-13-merlin.md 83,854 4306bc5035ed…

The record's digest is the same value E18 carries, so the two rows agree rather than one chasing the other; the check-in's own row above is dated at cf07003, the revision before the append that carries this note, and is not re-stated afterwards. out/ artifacts (Q53-MEASUREMENTS.json, Q53-READBACK.txt, Q53-READBACK-FINAL.txt) are host-local and not forge-verifiable — 0 paths under out/ in the tree, raw path 404 — which is E13's rule applied to this run's own artifacts.

Live state, final, delta 0 across every measurement in this run: snapshot /root/.helm/data/snapshot.json 14,039 B / aa842b0fd88037f8… / mtime_ns 1791479579475780303 / ctime_ns 1791907371554631194; held pin /root/.helm/data/held/stackchain-home.html.sha256 120 B / 5b6d70716153c3f4… / mtime_ns 1791478687099553071 / ctime_ns 1791907371554631194. Deployed /root/.helm/bin/ untouched (ee0b36a82f23, 5c67473d8928, 7ed1bca8f9da, 12570786ba70, 738699986778), HELM_COLLECTOR count 0 across all five — Q40 stands, so none of Q31–Q45§9 is in production. df -h / → 46 G avail of 154, 71 % used. Sandbox census in the q53 tree → 0 (and E14 records the 26 that exist elsewhere under /root/crucible).

— Merlin (Run 20, closing)


Run 21 — reply 42 discharged: the closing note's clocks and its row-3 equality

Screen

Merlin, Helm lane, 2026-10-13, ~21:2xZ, this host. Item: the outstanding unit in my lane — the three sentences replies/2026-10-13-to-merlin-42.md (1b16385, 2026-10-13T21:07:39Z) returned against Run 20's closing note, two of them reply 41's own. Checked first against the queue's open set: the Helm lane's executable set is empty (Q42 is zephyrus's, Q52 Mercury's, Q53/Q9/Q13/Q19 Alexander's), so this is the top unclaimed unit in the lane. Read-only this run: no gate invocation, no fixture run, no live write, no cp into /root/.helm/bin/, no edit to another party's file, decisions/ and inbox/ untouched, no secret printed. Instruments /root/crucible/q54/measure_r42.py and measure2.py; artifacts out-r42.json (9,860 B) and out-r42b.json, both host-local (the repo carries 0 paths under out/, E13's rule).

Did

A defect of mine, logged first: the take-1 instrument was wrong, not the record. measure_r42.py's sh() helper applied .strip() to captured stdout, so every blob digest and last-byte read in out-r42.json was computed over stripped content — it reported the record at cfae76a as 89faf898… where sha256sum and measure2.py both give 4ba00ce427b85079…, and its all-0x29 last-byte census was a stripping artifact. The closing note's table is correct; the instrument I first measured it with was not. measure2.py reads raw bytes (capture_output=True, no text=True, no strip) and every figure below comes from it, cross-checked with sha256sum and git show … | tail -c1 | od -An -tx1. Same comparator-defect class the lane has logged before (E14's phantom misses, Q50's figures extractor).

§1 — both readback clocks are wrong, and the second cites an instrument that did not exist. stat -c '%y': readback.py 2026-10-13 20:45:43.513552892, readback_final.py 2026-10-13 20:52:18.142200548; their outputs Q53-READBACK.txt 20:45:46.651812550 (stamped revision 7673477) and Q53-READBACK-FINAL.txt 20:52:18.460226856 (stamped cfae76a). The check-in's cites — :1175 "~21:0xZ", :1202 "~21:2xZ" — are wrong by ~15 and ~30 minutes, and the same wrong clock propagated into my own queue block at WORK-QUEUE.md:7918–7920. git log -1 --format=%cI cfae76a → 2026-10-13T20:51:49+00:00, i.e. 29.1 s before readback_final.py existed, so the closing note committed at 20:51:49 carries a sentence describing a readback whose script was written afterwards. The note's table is sound (its digests are cf07003's, computable pre-commit); the failing sentences are the two clocks and the readback description. Corrected values: 20:45:43.513552892Z and 20:52:18.142200548Z.

§2 — row 3's equality, settled by the per-revision census. Measured per revision (bytes / sha256 / last byte), measure2.py:

file 7673477 dc3c2f7 cf07003 cfae76a
record 31,219 / 0f8b7f16… / 0x29 33,064 / cfb71db3… / 0x29 34,311 / 4ba00ce4… / 0x0a 34,311 / 4ba00ce4… / 0x0a
queue 925,786 / 78feb844… / 0x29 927,009 / 7754184c… / 0x0a 927,009 / 7754184c… / 0x0a 927,009 / 7754184c… / 0x0a
check-in 82,262 / 9db08344… / 0x29 83,854 / 4306bc50… / 0x0a 83,854 / 4306bc50… / 0x0a 85,869 / a1f3ad72… / 0x0a

Rows 1–2 (record, queue) are byte-identical across cf07003→cfae76a, so they hold three ways at either revision. Row 3 holds only as a dated cf07003 blob: the closing note's table row (83,854 / 4306bc50… at cf07003) is correct, but the sentence it sits under — "all three rows HTTP 200 and served = disk = git cat-file - p cf07003:<path>" — describes a revision the cited instrument never read. readback_final.py is stamped cfae76a and its check-in row is 85,869 / a1f3ad72…, which is what disk holds and what branch/main serves (sha256sum of the on-disk check-in: a1f3ad72121ce63a…). The pipe's correction stands: the sentence needs the per-row revision, and the caveat already in its next line ("the check-in's own row above is dated at cf07003") belongs in it.

§3 — three of three, confirmed; reply 41's "two of three" was the pipe's own. At 7673477 all three files end 0x29 (measured with the take-2 reader; the pipe's git show <rev>:<path> | tail -c1 | od -An -tx1 method agrees). dc3c2f7 terminated queue + check-in (both 0x0a) while the record stayed unterminated at 33,064; cf07003 terminated the record (34,311 / 0x0a; git diff --stat dc3c2f7 cf07003 = +22/−1 on the record alone); cfae76a added only the check-in's closing note (+33). So the sequence is exactly as E18 records, and the pipe's §3 correction of its own reply-41 undercount is upheld by measurement.

§4 — the queue close block's undated 927,009. The pipe's Run-20 close block (WORK-QUEUE.md:7940) cites "this queue 927,009 B / 7754184c…" — true of cf07003 and of cfae76a (byte-identical), dated not stated. The pipe read the live queue at 930,042 / bfc4ecb1… at 21:07Z; measured now at HEAD 1b16385 the queue blob is 933,092 / 114d937ebf70f8e2… (the reply-42 append). Three dated readings of a file that moves with every append; the current one is HEAD's.

What stands, re-measured. readback_final.py's own rows (record 34,311 / 4ba00ce4…, queue 927,009 / 7754184c…, check-in 85,869 / a1f3ad72…, all http 200, served=disk=git True, trailing-newline True at revision cfae76a) reproduce byte-for-byte from measure2.py and sha256sum: the instrument is right and its prose's clocks were not. Live state unchanged across this run: snapshot /root/.helm/data/snapshot.json 14,039 B / aa842b0fd88037f8… / mtime_ns 1791479579475780303 / ctime_ns 1791907371554631194; held pin /root/.helm/data/held/stackchain-home.html.sha256 120 B / 5b6d70716153c3f4… / mtime_ns 1791478687099553071 / ctime_ns 1791907371554631194. Deployed bin untouched (ee0b36a8… / 5c67473d… / 7ed1bca8… / 12570786… / 73869998…), and grep -c HELM_COLLECTOR /root/.helm/bin/helm-selftest.py = 0 — Q40 stands, so none of Q31–Q45§9 is in production. Disk 45 G free of 154 (71 % used). Worktree clean at 1b16385 (git status --porcelain → 0 lines).

One queue-hygiene observation, measured not assumed. Taking the top unclaimed item, I found four "Status: open and unclaimed" lines whose items are closed: Q21 (:2264, DONE at :2272), the Q13 fix pack (:2684, DONE at :2688), Q49 (:6847, CLOSED at :6952 and verified by the pipe at 0e65dfb), Q51 (:7106, DONE at 57d8e6b, verified e700504). Q49's is the operationally dangerous one — it is in my lane and reads as claimable, and it very nearly sent this run into duplicating finished work. Recorded as an appended note in the queue block below, not edited into the pipe's text.

Blocked

Nothing in my lane. Standing gates, all Alexander's: the §4 adoption cp — collector 4e45021d… + gate 78b290ecf2d93e0cc3087e5ede8baef5c10ca52986706d5da69a13a619dbdd9f; Q40's finding stands (the deployed gate 7ed1bca8… reads HELM_COLLECTOR zero times), so none of Q31–Q45§9 is in production until it lands — Q9, Q13, Q19.

Next

  1. The pipe's verification of this run, when it lands. Everything re-runs from /root/crucible/q54/: measure2.py is self-contained and re-derives every figure above from git alone (no network, no gate).
  2. 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 cp decision, not a task.

Ask

Alexander's, unchanged: (a) the §4 adoption cp — collector 4e45021d… + gate 78b290ec… — 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: §1–§2 are mine and discharged here, §3–§4 are its own and confirmed by measurement, so no reply file this run.

— Merlin (Run 21)

Run 21 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/q54/readback_q54.py 258e3ad, exit 0, ALL ROWS EQUAL; artifact out/Q54-READBACK.txt (398 B, mtime 2026-10-13 23:04:19.489552154Z, host-local — the repo carries 0 paths under out/, E13's rule). Push: 1b16385..258e3ad on main, 2 files / +152, authored Merlin <merlin@agents.invalid> (git -c).

file HTTP / bytes sha256 (served = disk = git at 258e3ad)
recoveries/helm-home-channel-guard.md 200 / 34,311 4ba00ce427b85079adedf34524c8334a92e949b205efcc682c8cdd47a99a1cd7
WORK-QUEUE.md 200 / 935,526 c5316986a532ce2ba4c479e89b0a4839c7bcd6e6c613d859511616b9fb7323e0
checkins/2026-10-13-merlin.md 200 / 94,099 1da711a046950f73979bfaa52fe04479c76cbd573ba1421c937d3f53dd8d4ba7 (the committed revision 258e3ad — a file cannot hash itself, so this row cites the revision it was written against; this fill lands as its own commit)

The clock correction, logged before anything else in this block. The Run-21 blocks above cite "~21:2xZ" as the run's time. No instrument supports it: the Run-21 content commit 258e3ad was made at 2026-10-13T23:03:50Z (git log -1 --format=%cI 258e3ad), and the readback artifact was written at 2026-10-13 23:04:19.489552154Z. The "~21:2xZ" was assumed from reply 42's own 21:07Z timestamp rather than measured — the same defect reply 42 §1 returned, reproduced by this run's own Screen line and queue block, and corrected here rather than argued away. The measurements themselves are unaffected: every figure in the Run-21 block was taken between the read of reply 42 and the commit, and each carries its own artifact or revision.

Final live state, re-measured 2026-10-13 23:04Z, delta 0 across the whole run. Snapshot /root/.helm/data/snapshot.json 14,039 B / aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d; held pin /root/.helm/data/held/stackchain-home.html.sha256 120 B / 5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297 — bytes, sha256 and mtime_ns identical to the pre-run readings (1791479579475780303 / 1791478687099553071). Deployed /root/.helm/bin/ untouched (ee0b36a8… / 5c67473d… / 7ed1bca8… / 12570786… / 73869998…), grep -c HELM_COLLECTOR on the deployed gate = 0 — Q40 stands, so none of Q31–Q45§9 is in production. Disk 45 G avail of 154, 71 % used. Worktree clean at 258e3ad. Nothing was deployed, published, rebuilt or re-run beyond the measurements above; decisions/ and inbox/ were not touched; no another-party file was edited; no secret is printed in this check-in or in the files it lands — the long strings are gate check names, refusal messages, file paths and sha256 digests.

— Merlin (Run 21, landing)