Commit Graph
124 Commits
Author SHA1 Message Date
zephyrus-sparkborn fc06ebffb6 check-in 2026-10-13 2026-10-13 13:25:30 +00:00
mercury fd5a5fe061 checkin 2026-10-13-mercury.md 2026-10-13 12:02:48 +00:00
Merlin 36f8e9fb4a Q50 landing evidence: three files read back HTTP 200 over the anonymous raw path, byte-identical on three sides (served = disk = git cat-file -p 4c6cd50); live objects delta 0, deployed bin untouched 2026-10-13 11:27:38 +00:00
Merlin 4c6cd50baf Q50 closed: the admission probe's environment -- one rule, one function, two callers
Taken on the pipe's own offer (reply 34, asks 1). The Q48 value-redirect and Q49
default-redirect are factored into _q50_rebuild_env(_target) and called twice: at the
rule's original site for the legs (target the legs' sandbox) and above the admission
probe's spawn for the probe (target the probe's own tree, which exists before the
spawn -- the legs' sandbox does not). The spawn now carries env=, and a per-window
census of both live objects around the spawn is the class's detector: a move is
restored byte-exact in-gate, recorded, printed as a dated Q50 DETECTOR note, and
fails the named check "Q50 the admission probe's spawn moved neither live object".

Measured, all five matrix cells under a digest-verified guard (subject env-root-v1.py):
  base-q49 x named  MOVED  held pin 120 B / 5b6d7071... -> 14 B / 784b9bde..., guard-restored
  q50-armed x unset  delta 0  0 value + 1 default redirect
  q50-armed x named  delta 0  1 value redirect  -- the blank cell, filled
  q50-dis   x unset  delta 0  the probe copy's own Q45 literal relocation covers the
                              default shape; the redirect is load-bearing only in the named cell
  q50-dis   x named  delta 0  the DETECTOR fires: pin moves inside the gate, restored
                              byte-exact, foot prints FAIL Q50 (165/10 vs armed 166/9)
Green 5 x rc 0 / 175 passed / 0 failed (174 + 1) / 13,929 B / live delta 0.
Regressions 11/11 hold (n1-n5, noparse, dep-unparseable, undecodable, broken_dep rc 2;
latin1 and bom green 175/0). Live objects byte-identical to session start on
(bytes, sha256, mtime_ns); deployed bin untouched (ee0b36a8... / 7ed1bca8...,
HELM_COLLECTOR count 0 -- Q40's finding stands). Named follow-on, not fixed here:
hoist the run-wide held census above the probe. Three harness defects of mine logged
first in the record. Nothing deployed; no another-party file edited; no secret.
2026-10-13 11:26:36 +00:00
Merlin 26d4020ce2 Q49 landing evidence: the three post-push digests, read back from main
The record's deferred table and the check-in's deferred line are filled from the
anonymous raw read at main, taken after the push (a pre-push readback returns 404
for a new file), so the figures are stable for any outsider. All three HTTP 200
and byte-identical to disk.
2026-10-13 09:07:12 +00:00
Merlin de74527209 Q49 closed: the Q48 live-held invocation named and reproduced; the class closed
- (a) ATTRIBUTION, measured not withdrawn. env-root-v1.py = q48/env-root.py with its
  two default literals returned to /root/.helm (asserted count 2). Under a
  digest-verified guard: the fixture run --dry-run / bare / --deploy --out <scratch>
  with Q48_ROOT UNSET each moved the live held pin, and
  HELM_COLLECTOR=<that fixture> Q48_ROOT unset python3 q48/helm-selftest.py moved it
  too. All three Q48_ROOT=<scratch> controls: no move. Written bytes measured by a
  5 ms watcher: 14 B / sha 784b9bded20e9e22... / 'q48-env-pin\n'. Q48's 6.2
  attribution is upheld as a measurement; the pipe's negative reproduces exactly.
  The writing leg is named verbatim by the per-leg census: the G8 --dry-run
  original-subject leg, whose own source comment asserts "it writes nothing".

- (b) THE CLASS IS CLOSED, green 5/5. helm-selftest-q49.py (128,948 B / 2,445 lines /
  085ddf4f42ae80ea...): the DEFAULT redirect (every os.environ.get("X","<default>")
  pair inventoried by ast; a default literal resolving inside the live data root is
  redirected to the per-invocation sandbox), a per-leg census of BOTH live objects as
  detection, and a guard on the in-process --deploy leg. Checks 120 -> 123
  (+3 check("Q49"), nothing else moved). Five green runs: rc 0, 174 passed /
  0 failed, 13,863 B stdout, digests 13cf5cf7 / d4666b9f / 0abd28cd / 5ed81c37 /
  bbbd1901, live delta 0 on both objects.

- TWO FINDINGS BEYOND THE ITEM. (i) G8's --deploy branch calls hcg.main() IN-PROCESS
  with only SNAPSHOT_PATH patched, so a subject that resolved its root at import time
  wrote the LIVE SNAPSHOT (14,039 B -> 137 B) -- reproduced, restored, and now
  guarded. (ii) In the fully disarmed configuration the live pin still moves and no
  spawn the traced instrument can attribute it: one fixture main() per run, banner
  naming the sandbox, both censuses silent, watcher still seeing 120 B -> 14 B at
  t+280 ms. The write is real, the mechanism is UNATTRIBUTED, and it is named as the
  Helm lane's next unit rather than guessed at.

- Six live writes under guard, every one restored from a digest-verified backup that
  refuses to restore unless the backup digest matches. Both live objects byte-identical
  at session end: snapshot aa842b0fd88037f8... / 14,039 B and held pin
  5b6d70716153c3f4... / 120 B. Nothing deployed: /root/.helm/bin/helm-selftest.py is
  still 7ed1bca8... and reads HELM_COLLECTOR 0 times, so none of Q31-Q49 is in
  production and the cp of collector 4e45021d... + gate 085ddf4f... stays Alexander's.

Deliverable: recoveries/helm-resolved-root-live-path.md (15,220 B).
Scratch tree /root/crucible/q49/. Record, check-in Run 15 and queue block.
2026-10-13 09:06:35 +00:00
Merlin abe1f0b8c8 Run 14 landing evidence: all three files HTTP 200 over the anonymous raw path and three-way identical (served = disk = git cat-file -p 20623b6) at the revision the push created; the check-in row cites its pre-append revision per the no-self-hash convention 2026-10-13 06:45:12 +00:00
Merlin 20623b66fd Q48 queue block + check-in Run 14: the pair (collector 4e45021d + gate a590170f, diff 186 = 2 file + 3 hunk + 143 added + 0 removed + 18 context, 2124+143-0=2287); green 171/0 x5; witness armed-live redirected /root/.helm -> sandbox with the pin in the sandbox, disarmed-live wrote live and the guard restored byte-exact; three live-held writes disclosed with final live_delta 0 2026-10-13 06:44:25 +00:00
Merlin 1b3d7a44da check-in: Run 13 landing evidence — the post-push readback measured rather than promised: all three files HTTP 200 over the anonymous raw path and byte-identical on three sides (served, disk, git cat-file -p 8cb941f) at the revision the push created 2026-10-13 03:54:27 +00:00
Merlin 8cb941fc26 Q47 CLOSED (Merlin): the read path — a subject the interpreter can run neither crashes the gate nor is falsely refused
The subject's source is now read the way CPython reads it: bytes through
tokenize.detect_encoding (BOM stripped, PEP 263 cookie honoured), with a
dated exit-2 refusal for a file that cannot be read that way, at Q46's
guard point — after Q35's precondition, before the admission probe,
before any leg, before any sandbox. All four subject-source reads route
through the one reader; one stderr NOTE when the encoding is not plain
utf-8; the Q46 parse guard, the Q45 redirect, every check() and the 169
count untouched.

Deliverable recoveries/helm-read-path-guard.md (12,821 B), scratch tree
/root/crucible/q47/, evidence out/Q47-NEGATIVES.json (21 rows),
out/Q47-VERDICT.json, out/Q47-GREEN.json, out/DIFF-vs-q46.txt.

Measured, not asserted: latin-1 cookie subject rc 0 / 169 passed / ALL
GATES PASS under the shipped gate (Q39-Q45 crash with UnicodeDecodeError);
BOM'd collector rc 0 / 169 passed (Q43/Q45 SyntaxError at the sandbox
copy, Q44 AttributeError, sandboxes left); genuinely undecodable subject
rc 2 with the dated Q47 REFUSAL and no sandbox. Q39 runs the BOM subject
green with 164 passed — the read-path class is the text-compiling gates
(Q43-Q46), not subject handling generally. Green pair 5x rc 0, 169/0,
13,312 B stdout / 425 B stderr, live and held delta 0 on all 26
invocations. Adoption pair moves to collector 4e45021d + gate 76f2292b.

Nothing deployed, no cp into /root/.helm/bin/, decisions/ and inbox/
untouched, no another-party file edited, no secret. Run 13 in the
check-in; queue block appended.
2026-10-13 03:53:48 +00:00
Merlin 29cea300a1 Q46 landing evidence: the readback table filled from the measured read (three files HTTP 200 and byte-identical on three sides at a6b1ae3; the check-in row cites the committed revision, per the no-self-hash convention) 2026-10-13 01:38:51 +00:00
Merlin a6b1ae3434 Q46 closed: the parse guard
An unparseable subject is refused with exit 2 and a dated message naming the
parse failure, not admitted-then-crashed. Discriminator on all five gates,
digest-identical to the revision history: Q39 rc 1 SyntaxError at the legs
import of the original subject, Q43 rc 1 SyntaxError at the sandbox-copy
import, Q44 rc 1 AttributeError at the unguarded _q39_tree.body, Q45 rc 1
SyntaxError at the sandbox-copy import, Q46 rc 2 dated refusal with stdout 0
B and no sandbox created. dep-unparseable refused by Q39 repair 3 on all five
gates. C2 reproduced: the ROOT glob sees no leftover while the recursive
census sees legacy/q4X/helm-legs-*. Green pair 5x rc 0, 169 passed, 13,312 B,
live delta 0; atexit sandbox cleanup closes the n5 leak measured before and
after. Live snapshot aa842b0f 14,039 B and held pin 5b6d7071 delta 0 across
27 invocations. Adoption pair is now collector 4e45021d + gate ae69d5dd.
2026-10-13 01:38:23 +00:00
Merlin d5a14d4386 Run 11 landing evidence, final fill: the post-push readback measured rather than promised -- the fill landed as 00df4e6, the same anonymous raw path re-read the check-in at HTTP 200 / 103,128 B, cmp byte-identical to disk, sha256 4a17e8ee17a65dce20898ae16e562a8aea22490ef31c40c3e8d8467c2bb6479e reproducing from git cat-file -p 00df4e6, so served/disk/committed agree on three sides at the revision that now exists and the pre-append row stands at 57895b2 (100,376 B / 87c275a1) 2026-10-12 23:22:47 +00:00
Merlin 00df4e6e5b Run 11 landing evidence: the three files read back 200 and byte-identical on three sides (served, disk, git cat-file 57895b2) over the anonymous raw path; live snapshot and held pin re-measured delta 0, the held pin's ctime named as this run's restore trace 2026-10-12 23:22:07 +00:00
Merlin 57895b2e7c Q45 CLOSED: the redirect keys on the resolved value, not on a name (Helm lane, Merlin)
One rule replaces Q44's two: every absolute path literal in the subject that
resolves inside the live data root is relocated to the same relative path inside
the per-invocation sandbox, on the parsed node's own span, wherever in the module
it sits and whatever the constant holding it is called. Q44's HELM_HOME =
assignment rewrite is subsumed, not removed; the SNAPSHOT_PATH rewrite (Q39/Q43's
mechanism) is kept. Q39's literal refusal is retired for this class and its reason
printed where the refusal stood -- the refusal's own text said the rewrite "cannot
redirect a path that is not the module constant the rule keys on", which is the
statement Q45 makes false.

Gate 2bbca218871bc5613e1fe3c4d3a84fe2e6da05ffc526e51b2865a8c8ad00ee5e (105,477 B /
1,942 lines) against Q44's 18580c102ddb1c3f (94,819 / 1,731); diff = 426 lines =
2 file headers + 7 hunk headers + 284 added + 73 removed + 60 context, sums exactly;
1,731 + 284 - 73 = 1,942. Collector byte-identical to Q44's 4e45021d80395d3f
(measured by sha256 comparison, not asserted).

Green pair 5 consecutive: rc 0, 13,312 B stdout each, 169 passed / 0 failed,
VERDICT: ALL GATES PASS. 169 = 166 + 3, unchanged from Q44 -- two new Q45 checks
plus Q44's held-directory check carried verbatim and still labelled Q44.

The five Q39 negatives still refused under both gates (all ten rc 2, live delta 0).
n5 is the class change: Q44 refuses it (stdout 0 B), Q45 admits it and lets its legs
run (stdout 575 B), still rc 2 with live delta 0.

Discriminator on a scratch protected root, rule (3) disarmed, two subjects (a
differently-named root constant; the held directory built at call time from a
literal, with HELD_DIR left in place as a decoy) x three variants (redirect armed /
disarmed / the Q44 gate blind):
  armed    rc 0, 169/0, the only held write in the run's own sandbox, protected delta 0
  disarmed rc 1, 165/4, the held write in the protected root, protected NONZERO
  q44blind rc 0, 169/0, VERDICT: ALL GATES PASS, and the held write in the protected root
Prevention separated from detection by measurement, on both shapes.

INCIDENT, disclosed in full: the first discriminator run wrote the LIVE held
directory. The subject's root literal was /root/.helm while the variant's own live
root was the scratch protected root, so the literal sat outside the gate's live
root, was never in the redirect's inventory, and the copy the legs ran still named
live. Restored byte-exact from /root/crucible/q43z/backup/held.bak by
restore_held.py, verified against the recorded digest 5b6d70716153c3f4 (120 B,
mtime_ns 1791478687099553071). ctime_ns moved to 1791846636217687791 -- the trace
of the restore, which a restore cannot undo. Three mechanical fixes followed in
this tree: make_subjects.py retargets the root literal with an asserted count;
run_negatives.py's guard() refuses any discriminator subject whose code names the
live data root (it fired during this build); abort_if_live_moved() stops the whole
run the moment a live object moves.

Four instrument defects of mine, each caught by its own measurement: the span list
visited each AST node once per ancestor (ast.walk nested inside _q39_iter_nodes),
which produced Path('<sandbox>'le/<sandbox>'le/<sandbox>'le/<sandbox>') on the
HELM_HOME line; the subject header swap stripped the original docstring's opening
triple quote; make_subjects.py's truthiness and its HELM_HOME expectation; and the
q44blind variant's PIN block reading the wrong environment variable.

Two defects in others' code, found here and not fixed here: the Q44 gate accesses
_q39_tree.body with no None guard (unexercised, so reported rather than repaired);
and Q39's _q39_live_literals list appends once per ancestor yielded, so one literal
site printed 12 times (deduped for display where Q45 reads it; Q39's list unchanged).

Live state delta 0 on all 21 rows: snapshot 14,039 B / aa842b0fd88037f8 /
mtime_ns 1791479579475780303 / ctime_ns 1791789490146606356; held pin 120 B /
5b6d70716153c3f4 / mtime_ns 1791478687099553071 / ctime_ns 1791846636217687791
(that ctime is the restore trace). Deployed /root/.helm/bin/ untouched
(ee0b36a82f23fcf3 / 7ed1bca8f9da624f / 5c67473d89283c3d). Nothing deployed, no cp,
decisions/ and inbox/ untouched, no another-party file edited, no secret.
2026-10-12 23:21:35 +00:00
Merlin 9e6fe7ca93 Q44 landing evidence fill: the Run 10 table's measured digests, read back after 534be9e
python3 /root/crucible/q44/readback.py, exit 0, VERDICT: ALL READBACKS IDENTICAL,
run after the push of 534be9e. Anonymous raw path, no credential, all three HTTP 200:

  recoveries/helm-root-redirect.md  200 / 12,811   e68be4cdd5a535e22eae87f5ffbf9cb6841ea3d8a044ae34c13e74f86460568b
  WORK-QUEUE.md                     200 / 709,179  f2d6c923212c633618aa1a9624b33b0459bb1190a148489222f57e45a6803bff
  checkins/2026-10-12-merlin.md     200 / 84,760   06573214c798bd8e878b84b4157e01b67c20ea3e43a294d59bc716f622f485b2

Each byte-identical on three sides: the bytes the server served, the bytes on disk,
and git cat-file -p 534be9e:<path>. The check-in row cites 534be9e, which is the
revision the readback verified; this fill's own revision is this commit and is
verified over the same path by the same script, its digest recorded here rather
than inside the file.

Nothing else changed: /root/.helm/bin/ untouched (ee0b36a82f23fcf3... /
7ed1bca8f9da624f... / 5c67473d89283c3d...), live snapshot 14,039 B /
aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d / mtime
2026-10-08 17:12:59.475780303 +0000, held pin 120 B /
5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297 / mtime
2026-10-08 16:58:07.099553071 +0000 -- delta 0 across the run. decisions/ and
inbox/ untouched, no another-party file edited, no secret.
2026-10-12 20:53:38 +00:00
Merlin 534be9e32c Q44 CLOSED: the pin class is closed by construction, not by argv rule (Helm lane, Merlin)
Deliverable recoveries/helm-root-redirect.md (12,811 B / sha256
e68be4cdd5a535e22eae87f5ffbf9cb6841ea3d8a044ae34c13e74f86460568b). Scratch tree
/root/crucible/q44/; harness run_negatives.py -> out/Q44-NEGATIVES.json
(66,881 B / 611ab1e06e172be535ae5f19e21b4e1a6667a0f1b7542d130fc9d72298c5b895,
generated_at 2026-10-12T20:49:04Z), 17 invocations. Nothing deployed, no cp into
/root/.helm/bin/, decisions/ and inbox/ untouched, no another-party file edited,
no secret.

The pair: subject collector 4e45021d80395d3f... (29,954 B / 720 lines) byte-identical
to Q43's -- every change is in the gate. Gate 18580c102ddb1c3f...
(94,716 B / 1,731 lines) against Q43's c22601ecea4192d9... (88,468 / 1,612);
diff -u = 195 lines = 3 header + 133 added + 14 removed + 45 context, and
1,612 + 133 - 14 = 1,731 exactly.

What changed: the copy builder rewrites the HELM_HOME = assignment ITSELF to the
per-invocation sandbox, so every constant composed from it follows by construction;
the composed set is found by ast on the subject's own source (module-level Assign
nodes whose value references HELM_HOME) and is [SNAPSHOT_PATH, HELD_DIR]. The
SNAPSHOT_PATH rewrite is kept as defence in depth. Rule (3)'s --pin refusal is kept
but reclassified as defence in depth. Q39's admission, its behavioural probe and its
per-leg watch are untouched; no check's meaning changed. Three new checks, so the
green count is Q43's 166 + 3 = 169 passed / 0 failed: (1) the root constant is
redirected; (2) every constant composed from the root resolves inside the sandbox,
measured by a subprocess that imports the copy and prints the live values (not a
source marker); (3) the live held directory is unchanged by every leg, censused on
bytes, sha256, mtime_ns and ctime_ns before any leg and again at the foot.

Green pair, 5 consecutive invocations: rc 0 each, 12,966 B stdout, "helm-selftest:
169 passed, 0 failed" / VERDICT: ALL GATES PASS, 12.00-12.14 s; log digests
5c519157eaec4a40... / 97916ab27b8521c0... / 6f5553364b7a0d09... / ad57bad15689dfc5...
/ 00a1ae6dc2519efc... . Q43's counters unchanged (4 legs redirected, 3 --dry-run legs
original, 0 refusals, sandbox holds 3 paths with no data/snapshot.json).

The five Q39 negatives, still refused -- each run under the Q44 gate and, as the
pre-Q44 comparator, under the Q43 gate: all ten rc 2, stdout 0 B
(e3b0c44298fc1c149...), no report block, live delta 0, live held delta 0, 0.14-0.21 s.

The discriminator, on a scratch protected root (never live), rule (3) disarmed and a
--pin --deploy leg appended at the foot so it runs through the same leg wrapper.
pinleg (redirect armed): rc 0 / 169 passed, the pin lands in the sandbox
("pinned e40308e573d046d7d503acecbfbde82b8ccd10758a345b0440d55b796e2d821e ->
<sandbox>/data/held/stackchain-home.html.sha256"), protected held file delta 0
(114 B / b58d2d0eb9f45862b... / mtime_ns 1791478687000000000 / ctime_ns
1791838054542473495 before and after). pinleg-noredirect (redirect disarmed, live root
stood in for the scratch root): rc 1 / 166 passed / 3 failed, the same shape lands in
the protected root's held file (120 B / f98215b460bf89764924096c6fc657e62173e4c26f99bc4a2e5c489f3ed0f416 /
mtime_ns 1791838143983952745 / ctime_ns 1791838143991953414 -- NONZERO). Prevention
separated from detection by measurement. The live-path write was NOT re-measured: it
would clobber /root/.helm/data/held, Q43 already measured it (pinned 5e5cd6d26a70...)
and this run's pinleg reproduces the same body digest e40308e5... from the same code
path, so the class is the same one.

Live state, delta 0 across all 17 invocations: snapshot 14,039 B /
aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d / mtime_ns
1791479579475780303 / ctime_ns 1791789490146606356; held pin 120 B /
5b6d70716153c3f4bd82045d5d71edf88f793a240ce1275c3dfca5759d0ee297 / mtime_ns
1791478687099553071 / ctime_ns 1791478687102553111. Deployed bin untouched
(ee0b36a82f23fcf3... / 7ed1bca8f9da624f... / 5c67473d89283c3d...).

Limits and this run's own defects, logged first in the deliverable: the redirect keys
on the HELM_HOME = assignment, so a differently-named root or a call-time path is not
covered by the substitution (Q39's literal scan and the per-leg watch remain the
backstop); the shipped gate never exercises the redirect on a --pin leg, so that
shape's evidence is the variant; my first green run read 168 passed / 1 failed because
my own comparator excluded the sandbox root itself (startswith(dir + "/") is false for
HELM_HOME, whose value IS the root) -- fixed in patch_gate2.py and the only reason the
count is 169; the Q43 resolution-leg check false-fails under the variants and was fixed
in the variant only (patch_variants.py), the shipped gate untouched by that edit; and
one unexplained observation -- in pinleg-noredirect the sandbox census holds 5 paths
including data/snapshot.json, i.e. a leg wrote a snapshot inside the sandbox, which is
the sandbox doing its job and rides on nothing, recorded rather than explained.

Q7, measured: after this item the Helm lane's executable set is empty again (Q9 blocked
on the audio handover, Q13/Q19 gated on Alexander, Q42 open and zephyrus's). No new item
opened. The section 4 adoption is now a three-file ask: collector 4e45021d... + gate
18580c1..., with Q40's finding unchanged -- the deployed gate 7ed1bca8... has no
subject-selection path at all.
2026-10-12 20:52:12 +00:00
Merlin 2ddbe68f9f checkins: Run 9 landing evidence -- the three landed files read back over the
anonymous raw path (200 / cmp byte-identical, readback.py exit 0, VERDICT: ALL
READBACKS IDENTICAL) and the table filled with the measured digests

The table cites the committed revision 0fb8b20 for this check-in's own row
(200 / 75,361 B / fc4e750b392d2099c11703b8ea0f4e26036ea3a86b0123a8e2a5c1a6a53393ff,
reproduced locally by `git cat-file -p 0fb8b20:checkins/2026-10-12-merlin.md |
sha256sum`), not a transient local revision -- Run 8's row cited one and the pipe
returned that as D1. The check-in's own digest after this fill is deliberately
not printed: a file cannot cite its own final digest, and chasing that regress is
what moved Run 8's row through six revisions.

The other two rows are stable and carry their read-back digests:
recoveries/helm-leg-sandbox.md 200 / 13,561 B /
7c5111aa064e85247007a8ce1ca7a20e0d82d64db45eae0edcef62b9e78eec28 and
WORK-QUEUE.md 200 / 691,024 B /
90399c0f1586952a20e9a229db277aabdf2d062da2eddd30f79159d9033644e4, each cmp
byte-identical to disk.

Read-back at 2026-10-12T18:34:33Z, no credential. Nothing deployed, no another
party's file edited, no secret printed.
2026-10-12 18:35:43 +00:00
Merlin 0fb8b2096c Q43: the legs run the rewritten subject -- prevention, not detect-and-restore
Q39's repair 5 is a net, not a fence: live bytes and mtime are read around every
subprocess and around the subject's in-process import, a change restores the
bytes and refuses the run, so the write has already happened when the watch
fires. Q39's own record names the residual and the Q39 closure asks for "the
stronger form (the legs against a rewritten copy)". This is that form, and it is
the Helm lane's next unit rather than a new invention.

Three rules in the one choke point the gate already has -- the leg wrapper
installed on subprocess.run, so every future leg inherits them:

  1. a subject leg carrying --dry-run runs AS THE ORIGINAL, watched: it writes
     nothing by the collector's own rule (helm-collect.py:698), and running the
     original is what lets the resolution leg read the subject's own destination
     out of its banner;
  2. every other subject leg, and the in-process import, runs the REWRITTEN COPY
     -- every SNAPSHOT_PATH = assignment pointing at a per-invocation sandbox
     built after admission and removed at the end of the run -- so module-level
     code can write at most into the sandbox;
  3. a subject leg is REFUSED (exit 2, the leg never runs) if its argv names the
     live snapshot or passes --pin.

Rule 3 is load-bearing, not decoration: the collector refuses only when --out
resolves to its OWN SNAPSHOT_PATH (helm-collect.py:702), so a copy whose
destination is the sandbox would write the live path if a leg named it. The
gate's own "explicit live --out is refused" leg therefore now names the copy's
own destination -- the Q30 discipline applied to the collector. The rule under
test is unchanged; it is measured on a path that is not live, and the semantic
change is stated in the gate and the record rather than left implicit.

Measured, 20 gate invocations, live delta 0 on every one (snapshot 14,039 B /
aa842b0f... / mtime_ns 1791479579475780303; held pin 120 B / 5b6d7071... /
mtime_ns 1791478687099553071):

  - green pair, 5 consecutive runs: rc 0, 166 passed / 0 failed, ALL GATES PASS,
    12,248 B stdout; 4 subject legs redirected, 3 --dry-run legs run as the
    original, 0 refusals; the sandbox holds 3 paths (the copy and its bytecode
    cache, no data/snapshot.json); 18 legs watched, delta 0 on each;
  - the five Q39 negatives refuse under BOTH gates (rc 2, stdout 0 B, no report
    block, live delta 0) -- but they are refused at Q39's admission, before the
    Q43 sandbox exists, so they are a regression control and nothing in the
    five-fixture suite exercises the redirect. Stated, not hidden;
  - the discriminator, on a scratch protected path: argvlive (the gate's own
    pre-Q43 leg shape, rule 3 armed) -> rc 2, the refusal naming the leg's argv,
    the copy's destination and the rule at :702, and the protected file's sha,
    mtime AND ctime unchanged -- the leg never ran. argvlive-norule3 (rule 3
    disarmed) -> rc 2 via Q39's watch, protected ctime MOVED while sha and mtime
    were restored -- the leg ran, the copy wrote a real snapshot over the
    protected file, and only the restore put it back. ctime_ns is the
    discriminator: the stamp a restore cannot undo;
  - the --pin residual: pin_stackchain() writes HELD_DIR, composed from HELM_HOME
    and untouched by the rewrite, so a --pin leg is refused (rc 2, naming --pin
    and /root/.helm/data/held); a copy with HELD_DIR also redirected to scratch,
    run --pin --deploy, writes the scratch held file, so the path is real; bare
    --pin is refused by the destination gate before `if args.pin`, so it is one
    flag combination away, not on the default path;
  - the rewrite is behaviour-preserving: original vs copy, both --dry-run, both
    20,570 B, scrubbed over the gate's full clock set -> diff_keys [].

Three defects of mine, logged first in the record: the redirect keyed on argv[0],
which is the interpreter (the subject is an argv element, and the first run
measured 0 redirects while its legs ran the original -- the Q40 shape); the
behaviour-preservation scrub omitted generated_at and duration_seconds; and the
first --pin measurement ran bare, so the held path was never reached.

Limits stated in the record: prevention is total for the SNAPSHOT_PATH class, not
for every class; the legs still execute the subject's code, and damage to
anything other than the snapshot is out of this gate's scope; the five-fixture
suite no longer reaches Q43's machinery, so the two variants and the pin residual
are the coverage.

Nothing deployed: no cp into /root/.helm/bin/, the deployed bin is unmoved
(ee0b36a8... / 7ed1bca8... / 5c67473d...), decisions/ and inbox/ untouched, no
another-party file edited, no secret printed. Adoption stays Alexander's, and Q40
measured that the deployed gate has no subject-selection path at all, so the cp
is the only thing that puts any of Q31-Q43's protection into production.
2026-10-12 18:33:44 +00:00
Merlin fbb2562c35 checkins: Run 8 landing evidence appended -- the Q41 erratum's three landed files read back over the anonymous raw path (200 / cmp byte-identical); the check-in's own row cites its pre-append revision, as Run 4 and Run 7 do, because a file cannot hash itself. 2026-10-12 16:10:38 +00:00
Merlin ff32a440e2 recoveries: Q41 erratum applied -- literal rows' offsets re-measured in the space their row names (s3e.py:81 returned an S0 offset under an S1 label; fraction was a mixed-space ratio). 6 of 42 measured rows move at 4dp, class mean 0.229448 -> 0.229590 (0.2294 -> 0.2296); the magazine contrast (0.4735) and the fifths split (21/10/9/1/1) are unchanged. Second defect of mine found while applying: s3e.py:105 counted the raw excerpt against the S1 body, so 16 occurrence counts were under-counts and the multi-occurrence aggregate moves 8 -> 9. Also applied: the anchor-census label fix (46 anchored + 4 no-anchor = 50), the 25 -> 35 anchor revision logged (Q41 35 = 25 unique + 10 shared with the magazine 91; union 116 = Q21's census figure), and the fifths bucketing rule printed (min(int(f*5),4)). Verified from the patched markdown itself: 50 rows / 0 malformed, class counts 30/5/7/4/4 summing to 50, Q21 join 42 bound / 4 mis-bound / 4 unanchored, 50/50 rows agreeing with the S1-measured set. Scratch /root/crucible/q41/; no page re-fetched; decisions/ and inbox/ untouched; nothing deployed. 2026-10-12 16:08:56 +00:00
Merlin e9cd99f280 checkins: Run 7 landing evidence -- anonymous readback of all three files 200 / cmp-identical (readback.py exit 0, VERDICT ALL READBACKS IDENTICAL) 2026-10-12 13:58:09 +00:00
Merlin 6abf898bd1 queue: Q41 excerpt fidelity class and placement, the 30 non-magazine entries DONE (Merlin) -- deliverable recoveries/excerpt-placement-nonmagazine.md (33645 B / sha256 d16761a827dfe5de9868dc0e1e513153d6acaa802983000959172d873de98c84); population 30 entries / 50 excerpts / 35 distinct anchors all HTTP 200 (index 200 / 34488 B / 4f764ef4, 2026-10-12T13:46:28Z); tally 30 literal / 5 normalised-literal / 7 elided / 4 paraphrase / 4 unreadable; placement n=42 over 26 of 30 entries, mean 0.2294 vs the magazine class 0.4735, fifths 21/10/9/1/1; Q21 join exact 42 bound / 4 mis-bound / 4 unanchored = 42/4/4; two of my own defects logged first (source-type unreadable rule on 23 non-article rows; three URL-tokenisation failures fixed, witness event-2022-08-21-...-1414 seq 1); scratch /root/crucible/q41/; no new item opened, Q37 pipe's, Q9/Q13/Q19 and Helm adoption gated 2026-10-12 13:57:38 +00:00
zephyrus-sparkborn 23837a4cf7 check-in 2026-10-12 (zephyrus): lane restored (1f96c8a pushed), Q20 aggregates independently recomputed, Q40 digest corroborated 2026-10-12 13:12:30 +00:00
zephyrus-sparkborn 1f96c8adcc check-in 2026-10-11 (zephyrus): Q20 sample audit done (26/26 literal), lane correction - Cassian took Q21 (e3b2f4b), I took Q20 per 18:13Z reconciliation; push owed
Supersession note (2026-10-12): Merlin's full-population Q20 audit (9a1de9a, 269/269 literal, pipe-verified reply 20) closed Q20 while my two commits were egress-blocked; my sample verdict agreed. Audit file landed as recoveries/excerpt-placement-audit-zephyrus-sample.md (renamed on rebase so Merlin's deliverable at recoveries/excerpt-placement-audit.md is untouched).
2026-10-12 13:10:15 +00:00
mercury e9efb23e4b checkin 2026-10-12-mercury.md 2026-10-12 12:00:38 +00:00
Merlin 5d71c855fb Q40: the deployed gate admits all five negatives, and has no admission path at all
Reproduces the Q39 closure's C26 from this host and states the mechanism:
`grep -c HELM_COLLECTOR /root/.helm/bin/helm-selftest.py` -> 0; the deployed gate
imports its subject at module scope from a hard-coded path (`:39`), so the five
fixtures are never loaded -- the shipped gate has no subject-selection path at
all, which is why Q34-Q39's admission machinery has nothing in production to
guard. Measured: deployed gate x5 fixtures -> rc 0 / 7,488 B stdout /
`119 passed, 0 failed` / `VERDICT: ALL GATES PASS`, stderr 0 B, live snapshot
`aa842b0f...` delta 0 across all 15 invocations plus the green control; Q38
admits n1 and n2 (its C22/C23 holes); Q39 `9b09f328...` refuses all five
(rc 2 / stdout 0 B / no fixture file touched / live delta 0) and runs the pair
green (164 passed / 0 failed, `Q39 OK`, 17 legs watched, delta 0 on each).
Nothing deployed, no `cp`, `/root/.helm/bin/`, `decisions/` and `inbox/`
untouched. Deliverable `recoveries/helm-deployed-gate-admission.md` (5,633 B /
sha256 5bdd2e7503cced8eee5b31a0256500aaa8eda9f8e3adbb80d3702eeb5e8df61a).
2026-10-12 11:43:08 +00:00
Merlin 9af42d2115 Q40: the deployed gate admits all five negatives, and has no admission path at all
Reproduces the Q39 closure's C26 from this host and states the mechanism:
`grep -c HELM_COLLECTOR /root/.helm/bin/helm-selftest.py` -> 0; the deployed gate
imports its subject at module scope from a hard-coded path (`:39`), so the five
fixtures are never loaded -- the shipped gate has no subject-selection path at
all, which is why Q34-Q39's admission machinery has nothing in production to
guard. Measured: deployed gate x5 fixtures -> rc 0 / 7,488 B stdout /
`119 passed, 0 failed` / `VERDICT: ALL GATES PASS`, stderr 0 B, live snapshot
`aa842b0f...` delta 0 across all 15 invocations plus the green control; Q38
admits n1 and n2 (its C22/C23 holes); Q39 `9b09f328...` refuses all five
(rc 2 / stdout 0 B / no fixture file touched / live delta 0) and runs the pair
green (164 passed / 0 failed, `Q39 OK`, 17 legs watched, delta 0 on each).
Nothing deployed, no `cp`, `/root/.helm/bin/`, `decisions/` and `inbox/`
untouched. Deliverable `recoveries/helm-deployed-gate-admission.md` (5,633 B /
sha256 5bdd2e7503cced8eee5b31a0256500aaa8eda9f8e3adbb80d3702eeb5e8df61a).
2026-10-12 11:42:47 +00:00
Merlin e56f959246 Q40: the deployed gate admits all five negatives, and has no admission path at all
Reproduces the Q39 closure's C26 from this host and states the mechanism:
`grep -c HELM_COLLECTOR /root/.helm/bin/helm-selftest.py` -> 0; the deployed gate
imports its subject at module scope from a hard-coded path (`:39`), so the five
fixtures are never loaded -- the shipped gate has no subject-selection path at
all, which is why Q34-Q39's admission machinery has nothing in production to
guard. Measured: deployed gate x5 fixtures -> rc 0 / 7,488 B stdout /
`119 passed, 0 failed` / `VERDICT: ALL GATES PASS`, stderr 0 B, live snapshot
`aa842b0f...` delta 0 across all 15 invocations plus the green control; Q38
admits n1 and n2 (its C22/C23 holes); Q39 `9b09f328...` refuses all five
(rc 2 / stdout 0 B / no fixture file touched / live delta 0) and runs the pair
green (164 passed / 0 failed, `Q39 OK`, 17 legs watched, delta 0 on each).
Nothing deployed, no `cp`, `/root/.helm/bin/`, `decisions/` and `inbox/`
untouched. Deliverable `recoveries/helm-deployed-gate-admission.md` (5,633 B /
sha256 5bdd2e7503cced8eee5b31a0256500aaa8eda9f8e3adbb80d3702eeb5e8df61a).
2026-10-12 11:42:14 +00:00
Merlin 4e87c8fee5 Q39 landing evidence: the three files read back 200 and cmp byte-identical over the anonymous raw path (record 12,253 / 56e25f16, queue 587,985 / 3884ebf8, check-in pre-append 38,651 / d16b8ef2); live snapshot aa842b0f delta 0 and deployed bin untouched after the push 2026-10-12 09:32:59 +00:00
Merlin fad802c0f5 Q39: the destination guard's admission is keyed on the subject's own destination, and every leg is watched (Helm lane)
Five repairs to the Q38 gate (74aba348 -> 9b09f328, +309/-38): the probe injects
from pathlib import Path so the rewritten line cannot NameError; EVERY SNAPSHOT_PATH
assignment is rewritten; a probe that dies with a traceback is refused; an ast scan
refuses an absolute path literal resolving inside /root/.helm/data/; and live bytes
and mtime are read around every subprocess and around the subject's in-process
import, a change dying the run and restoring the bytes it read.

Negative controls (q39-negatives.py, Q39-NEGATIVES.json): five fixtures, each run
under BOTH gates. n1 (the incident's shape) and n2 (a probe that dies with a
traceback) are ADMITTED by the Q38 gate - n1's in-process import writes the
fixture's destination inside the gate's own run - and refused by the Q39 gate.
Green pair: 5 consecutive invocations, rc 0, 164 passed / 0 failed, 17 legs
watched, live delta 0 on every run. Live snapshot aa842b0f delta 0 throughout;
nothing deployed, decisions/ and inbox/ untouched.
2026-10-12 09:32:18 +00:00
Merlin 4ed1da96ae Q38 landing evidence: the three files read back 200 and cmp byte-identical over the anonymous raw path (guard 10,232 / 69e72474, queue 570,365 / c18ffd4c, check-in pre-append 30,506 / 35a7ad50); live snapshot aa842b0f delta 0 and deployed bin untouched after the push 2026-10-12 07:07:13 +00:00
Merlin 0776480b51 Q38: the destination guard is behavioural, not documented (Helm lane, Q36 candidate 2)
Q35's precondition reads a source marker (--deploy and SNAPSHOT_PATH.resolve() in the subject's
source), so a subject that documents the rule in a comment without implementing it is admitted —
the pipe measured exactly that at 02:4xZ today. The gate now, at helm-selftest.py:117-211, after
the Q35 check and before the subject import (:784) and G8's bare-refusal leg (:1079-1081, the Q34
incident's leg), runs a copy of the subject's source with its SNAPSHOT_PATH = assignment rewritten
to a sentinel path as a subprocess bare, and refuses the subject (exit 2, no leg runs) unless that
run exits non-zero, writes nothing, and leaves the live snapshot delta 0. The probe never imports
the subject into the gate's process.

Measured this run (scratch tree /root/crucible/q38/, nothing deployed):
- 7 consecutive green invocations, exit 0 each, 164 passed / 0 failed and ALL GATES PASS in every
  log, the Q38 OK line present in all seven, live snapshot sha256+mtime read around every
  invocation with delta 0 throughout.
- Discriminator on both sides: fake-documented-no-rule.py (both markers in its docstring, so the
  Q35 predicate over its source is true) exits 2 with the refusal naming probe rc=0 and the
  sentinel written (74 B / 817e3830...); fake-marker-only.py (the pipe's measured shape) exits 2 at
  the assignment step; the deployed collector exits 2 at the Q35 source check with zero Q38 lines —
  the ordering. The admission control: fake-marker-only.py under the Q35 gate runs G7 and dies at
  the subject import (AttributeError, helm-selftest.py:688) — the admission measured end to end.
- Gate 1,044 -> 1,141 lines (+97/-0; DIFF.txt 108 lines / ac8e52bb...), sha256 643e5387... ->
  74aba348...; collector byte-identical to the Q34/Q35 pair (4e45021d..., 720 lines).
- Live snapshot /root/.helm/data/snapshot.json 14,039 B / aa842b0f... / mtime_ns
  1791479579475780303, delta 0 across every leg; deployed bin untouched (ee0b36a8 / 7ed1bca8 /
  5c67473d); decisions/ and inbox/ untouched; no another-party file edited.

Section 4 consequence: the adoption pair is now collector 4e45021d... + gate 74aba348...
(superseding 643e5387...); the cp into /root/.helm/bin/ remains Alexander's.
2026-10-12 07:06:41 +00:00
timmy d2a9cae675 merlin check-in: process fault disclosed after the fact -- WIZARDS-TABLE.md:13 names Q20 as zephyrus-sparkborn's lane unit and my own skill carries that exact pitfall; the deliverable stands on its own evidence, the roster is Timmy's file and untouched 2026-10-12 04:52:10 +00:00
timmy 5fe58aafbe Q20: the landing-evidence self-citation regress is broken by indirection, not by chasing it -- the record's own row and the check-in's own row defer to each other, the three revisions of the record are named with their bytes, and the stable artifacts (rows file, queue) keep their digests 2026-10-12 04:51:42 +00:00
timmy 48bf86b93e Q20: the record cites both of its own revisions (pre-fill 9dced5eb / 12,914 and post-fill e72062a3 / 13,062), the self-reference loop closed on the record rather than left circular, and the check-in landing table carries the same pair 2026-10-12 04:50:59 +00:00
timmy 95dfbf37de Q20: landing evidence filled in on the record (readback table at 9a1de9a, post-push reads) and the Run 3 check-in appended (Did / Blocked / Next / Ask) 2026-10-12 04:50:32 +00:00
Merlin f19243d3e6 Q35: Run 2 landing evidence appended to the check-in (readback table: helm-precondition-gate.md 200/8261 sha a5d3ad6a, WORK-QUEUE.md 200/537076 sha 28c7250b, check-in 200/12471 sha 814cda6e pre-append, all cmp byte-identical over the anonymous raw path; live snapshot aa842b0f/14039/mtime_ns 1791479579475780303 delta 0 across the whole Run 2; deployed bin untouched ee0b36a8/7ed1bca8/5c67473d; nothing deployed) 2026-10-12 02:37:49 +00:00
Merlin dd0bc69061 Q35 DONE: the destination-rule guard is a precondition, not a report (recoveries/helm-precondition-gate.md, scratch /root/crucible/q35/).
The subject collector named by HELM_COLLECTOR is checked for the rule (--deploy and SNAPSHOT_PATH.resolve() in its source) at helm-selftest.py:96-114 BEFORE the subject is imported (:679) and before G1, and refused with exit 2, a stderr message naming the subject and the missing rule, and the live snapshot read before/after the refusal. Gate +61/-2 (985 -> 1044 lines, 45e53187 -> 643e5387); collector byte-identical to the Q34 pair (4e45021d); the precondition registers no check() so the suite count is unchanged at 164 and the old foot-of-suite source check is kept at :1032.

Seven consecutive green invocations (164 passed / 0 failed each, log digests in the deliverable), live snapshot delta 0 across every leg (aa842b0f / 14039 B / mtime_ns 1791479579475780303). Discriminator both sides in one run pair: deployed pre-gate collector as subject -> exit 2, stdout 0 bytes (e3b0c442, no summary and no PASS line, which is how "no leg executed" is measured), live delta 0; missing subject refused the same way, not crashed. Mechanism probe from this tree (q35-mechanism.py, mech-probe.log): default destination rebound to scratch, bare main() -- deployed ee0b36a8 rc=0 no refusal, 18523 B written (9331b218, schema helm.snapshot/1); pair 4e45021d rc=2, refusal naming the path and --deploy, nothing written.

Limits stated: the gate run bare now refuses itself (default subject is the pre-gate deployed collector; the section-4 cp is what makes the shipped gate green, Alexander's); the precondition reads a source marker, not behavioral proof; the rule protects the gate's legs, not a direct CLI run. Nothing deployed; decisions/ and inbox/ untouched.
2026-10-12 02:37:25 +00:00
Merlin ac98bfb53c Q34: landing evidence appended to the check-in (readback table: helm-null-gate.md 200/9924 sha 84b1e714, WORK-QUEUE.md 200/521480 sha 602746a5, check-in 200/6442 sha 08afa919, all cmp byte-identical over the anonymous raw path; live snapshot aa842b0f/14039/mtime_ns 1791479579475780303 delta 0; deployed bin untouched ee0b36a8/7ed1bca8/5c67473d; nothing deployed, the §4 cp is a three-file ask now) 2026-10-12 00:29:31 +00:00
Merlin a16d9e45be Q34 DONE: the pointer's null case is gated (recoveries/helm-null-gate.md, scratch /root/crucible/q34/). Four checks planted in the gate's own scratch tree between two collects on a profile with sessions/ and logs/ and no files: latest_active_path null, source_path still the profile directory, the key present with value null rather than absent, and a follow-up collect where a planted file sets the pointer while the citation holds; the member analogue stated unreachable by construction. Seven consecutive green gate invocations (exit 0, 164 passed 0 failed each, the Q33 160 plus these four), log digests in the deliverable. Red on both comparators: Q33-before collector under the full gate exit 1 / 153 passed 11 failed (the Q33 nine plus Q34 checks 3 and 4); pre-Q33 collector 2 passed 2 failed on the four checks by module import with no subprocess leg; checks 1-2 pass vacuously on both comparators and are reported as vacuous. The collector did not move (byte-identical to the Q33 pair, 4e45021d, 720 lines); the gate moved +56/-0 (929 -> 985 lines, 45e53187), so the §4 adoption ask is now a three-file ask. One incident logged first: the first red leg ran the full gate against the pre-Q33 collector, which has no destination gate, so the bare --skip-tests leg wrote the live snapshot (aa842b0f -> e4d1ad5, 14039 -> 18524 B, mtime_ns 1791479579475780303 -> 1791764761933369921 at 00:26:01Z); restored byte-exact from /root/crucible/q31/snap-before.json with the mtime re-stamped and the comparator re-run by import only; live snapshot delta 0 across every leg after the restore. Deployed bin untouched. Limits: a live empty profile is unobserved; checks 1-2 vacuous on the comparators; the null value is not schema-constrained. 2026-10-12 00:28:38 +00:00
Merlin dded721159 Q33: landing evidence appended (readback table, untouched-file re-verification) 2026-10-11 22:21:13 +00:00
Merlin 8bb88da1d3 Q33 DONE: the newest-file pointer is its own named field (evidence.latest_active_path / newest_checkin_file), source_path is a stable citation everywhere, the Q32 pointer carve-out is deleted from the gate; 6 consecutive green gate invocations (160/160 each), 8 paired runs with zero differing leaf paths without the carve-out, the gate red on the pre-Q33 collector (8 behavioural checks), consumer walk done; C5 appended to helm-g8-scrub.md Limits; collector 4e45021d + selftest 4a442f62 scratch-local, adoption is Alexander's 2026-10-11 22:20:43 +00:00
Merlin 83e92530d6 Q32: landing evidence appended (readback table, untouched-file re-verification) 2026-10-11 20:00:06 +00:00
Merlin 7e12c82506 Q32 DONE: the G8 two-run agreement check is deterministic — declared scrub set covers every clock-derived field (age_seconds, last_active_at, last_checkin_at, the newest-file pointer), 6 consecutive green gate invocations, 8 paired runs with zero differing leaf paths; collector 8a477376 unchanged, adoption identity is now collector 8a477376 + selftest 9ce6a4e9 2026-10-11 19:59:42 +00:00
timmy 229fe96332 Q31 Run 7: landing evidence filled from the anonymous raw readback (Merlin) 2026-10-11 15:40:16 +00:00
timmy 1c0d660c2a Q31 Run 7: dead digest corrected to the artifact that exists (8a477376), restore-mtime root-caused and fixed, gate re-run 137/137 (Merlin) 2026-10-11 15:39:52 +00:00
Merlin ebf5226451 Q31: append final landing-evidence figures (Merlin) 2026-10-11 13:32:41 +00:00
Merlin bf5028732e Q31: landing evidence block for run 6 (Merlin) 2026-10-11 13:32:13 +00:00
Merlin 300228b44c Q31: collector's entry point executed, destination gated, G8 gate (Merlin run 6) 2026-10-11 13:31:39 +00:00