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.
This commit is contained in:
1 parent
e585b8809a
commit
0776480b51
3 files changed
+322
No files matched your search
@@ -5012,3 +5012,57 @@ actually is, since his own-identity commits are seen directly and need no rule.
|
||||
commands; the harness output if a signal is found. **Not** in scope: changing the attribution of history — no commit
|
||||
can be restated (see Q20 and Q36), and the five commits' content is already recorded as Merlin's on the author's own
|
||||
statement and on the files' first-person text.
|
||||
|
||||
---
|
||||
|
||||
## Q38 — The behavioural destination guard *(Helm lane; opened 2026-10-12 by Merlin — Q36's candidate 2, on Alexander's direction to continue the Helm lane)*
|
||||
|
||||
Q35 made the destination-rule guard a **precondition**, but the precondition reads a **source marker** — the strings
|
||||
`--deploy` and `SNAPSHOT_PATH.resolve()` present in the subject collector's source — and a subject that **documents**
|
||||
the rule in a comment without implementing it is admitted. The pipe measured exactly that on 2026-10-12T02:4xZ: a
|
||||
fake collector whose body is `import sys; sys.exit(0)` plus a comment carrying both strings ran the whole Q35 suite
|
||||
to completion with live delta 0. This item makes the guard **behavioural**.
|
||||
|
||||
**Do this:** in a scratch tree, add to the gate a precondition that executes the subject against a **sentinel**
|
||||
destination — a copy of the subject's source with its `SNAPSHOT_PATH =` assignment rewritten to a scratch path, run
|
||||
as a subprocess bare (`--skip-tests`, no `--out`, no `--deploy`) — and refuses the subject unless the run exits
|
||||
non-zero **and** writes nothing **and** the live snapshot is delta 0 around the probe. Then run the pair green for
|
||||
**N ≥ 5 consecutive invocations** with each log's digest, and demonstrate the discriminator on a subject that passes
|
||||
the source check but fails behaviourally.
|
||||
|
||||
**Done means:** `recoveries/helm-behavioural-guard.md` — the guard's code path with line numbers, the diff, the
|
||||
green-pair logs with digests, the refusal transcripts, and the live snapshot delta 0.
|
||||
|
||||
**Status: DONE — `recoveries/helm-behavioural-guard.md` (10,232 B), Merlin, 2026-10-12T06:5x–07:1xZ, this host.**
|
||||
Scratch tree `/root/crucible/q38/`; nothing deployed, nothing published; the shared tree, `/root/.helm/bin/`,
|
||||
`decisions/` and `inbox/` untouched.
|
||||
|
||||
- **The guard** sits at `helm-selftest.py:117–211`, after the Q35 source-marker check (`:96–114`, kept as the fast
|
||||
filter and measured to fire first) and before the subject import (`:784`) and G8's bare-refusal leg
|
||||
(`:1079–1081` — the Q34 incident's leg). Gate 1,044 → **1,141 lines, +97/−0** (`DIFF.txt` 108 lines / sha256
|
||||
`ac8e52bb38090c66…`), sha256 `643e5387…` → **`74aba34860b34ac6aebd8661e3e46c01ed8c15dcec1cd958ec766114abfa1ef0`**;
|
||||
collector byte-identical to the Q34/Q35 pair (`4e45021d…`, 720 lines).
|
||||
- **Green pair, 7 consecutive invocations**, exit 0 each, `helm-selftest: 164 passed, 0 failed` / `VERDICT: ALL GATES
|
||||
PASS` in every log, the `Q38 OK` line (probe rc=2, sentinel not written, live delta 0) present in all seven; live
|
||||
snapshot sha256+mtime read around every invocation, delta 0 on all seven. Log digests: `f606bf3877cd6a96…` /
|
||||
`4cd6456713f2e1ff…` / `02ecbf989f2d162c…` / `94781f8dfa0f4ac8…` / `a2380b7ab4c61435…` / `fbd5e11713a6c048…` /
|
||||
`d0cae43b79b4f5f1…`.
|
||||
- **The discriminator, both sides.** `fake-documented-no-rule.py` (both markers in its docstring, so the Q35
|
||||
predicate over its source is true): **exit 2**, stdout 0 bytes, the Q38 refusal naming the probe rc=0 and the
|
||||
sentinel written (74 B / sha256 `817e38302aff7065…`), live delta 0. `fake-marker-only.py` (the pipe's measured
|
||||
shape): **exit 2** at the assignment step, stdout 0 bytes. The deployed collector: **exit 2** at the Q35 source
|
||||
check with zero Q38 lines — the ordering. The admission control: `fake-marker-only.py` under the **Q35** gate ran
|
||||
G7 and died at the subject import (`AttributeError … has no attribute 'SNAPSHOT_PATH'`, `helm-selftest.py:688`) —
|
||||
the admission, measured end to end — while the Q38 gate refuses the same subject before any leg.
|
||||
- **Live state, delta 0 across every leg:** `/root/.helm/data/snapshot.json` 14,039 B / sha256
|
||||
`aa842b0fd88037f8…` / mtime_ns `1791479579475780303`, identical before and after the 7 green runs, the 3 refusals
|
||||
and the admission control. Deployed bin untouched (`ee0b36a8…` / `7ed1bca8…` / `5c67473d…`).
|
||||
- **§4 consequence:** the adoption pair is now collector `4e45021d…` + gate **`74aba348…`** (superseding
|
||||
`643e5387…`); the `cp` into `/root/.helm/bin/` remains Alexander's.
|
||||
- **Limits stated in the deliverable:** the probe substitutes the module's `SNAPSHOT_PATH =` assignment, so a
|
||||
subject resolving its destination by another route is not covered by the substitution (the live-delta-0 assertion
|
||||
catches an actual write only after the fact); the refusal criterion is rc ≠ 0 **and** nothing written (a
|
||||
no-write rc=0 subject is admitted — it cannot clobber); the timeout branch is coded and not exercised; and the
|
||||
guard protects the gate's legs, not a direct CLI run of a pre-gate collector (the Q35 limit, unchanged).
|
||||
- **Q7, measured:** the unclaimed executable set is unchanged and not empty — **Q37** (pipe tooling) is open. Nothing
|
||||
opened this tick beyond this item, which discharges Q36's candidate 2 on Alexander's direction.
|
||||
@@ -343,3 +343,114 @@ Alexander: nothing further is asked of you here. This is disclosed so the roster
|
||||
reconciled by whoever owns them, and so the next tick does not repeat it.
|
||||
|
||||
— Merlin
|
||||
|
||||
---
|
||||
|
||||
## Run 4 — Q38: the destination guard is now behavioural, not documented
|
||||
|
||||
Claimed and finished **Q38 — the behavioural destination guard** (Helm lane; Q36's candidate 2, on
|
||||
Alexander's direction to continue the lane). Deliverable: `recoveries/helm-behavioural-guard.md`
|
||||
(**10,232 B / sha256 `69e72474c103c727c11408aca34a666309b740db66f0cd476bc13e1772d56db9`**, this
|
||||
host). Queue block appended to `WORK-QUEUE.md` (was 565,470 B / sha256
|
||||
`b4b8b2d5561725c8205b5da18fa190aa9a143b0dc56bf2707f7fb4d71d4d5673` before this run's append).
|
||||
Scratch tree `/root/crucible/q38/`; nothing deployed, nothing published.
|
||||
|
||||
**What was gated.** Q35's precondition reads a *source marker* — `--deploy` and
|
||||
`SNAPSHOT_PATH.resolve()` present in the subject's source — so a subject that **documents** the
|
||||
rule in a comment without implementing it is admitted, which the pipe measured at 02:4xZ today
|
||||
(a fake collector carrying both strings in a comment ran the whole Q35 suite to completion with
|
||||
live delta 0). Q38 adds, at `helm-selftest.py:117–211` — after the Q35 check (`:96–114`, kept as
|
||||
the fast filter and measured to fire first) and before the subject import (`:784`) and G8's
|
||||
bare-refusal leg (`:1079–1081`, the leg that executed an ungated subject and wrote the live
|
||||
snapshot in Q34's incident): a copy of the subject's source with its `SNAPSHOT_PATH =`
|
||||
assignment rewritten to a **sentinel** path, run as a **subprocess** bare (`--skip-tests`, no
|
||||
`--out`, no `--deploy`), and the subject is refused (**exit 2, no leg runs**) unless that run
|
||||
exits non-zero **and** writes nothing **and** the live snapshot is delta 0 around the probe. The
|
||||
probe never imports the subject into the gate's process — the subject's module-level code runs
|
||||
only in the probe subprocess.
|
||||
|
||||
**Green pair, 7 consecutive invocations**, exit 0 each, `helm-selftest: 164 passed, 0 failed` and
|
||||
`VERDICT: ALL GATES PASS` in every log, the `Q38 OK: … (probe rc=2, sentinel written=False, live
|
||||
delta 0)` line present in all seven, live snapshot sha256+mtime read around every invocation
|
||||
(`run-green.sh`), delta 0 on all seven. Log digests: `f606bf3877cd6a96…` / `4cd6456713f2e1ff…` /
|
||||
`02ecbf989f2d162c…` / `94781f8dfa0f4ac8…` / `a2380b7ab4c61435…` / `fbd5e11713a6c048…` /
|
||||
`d0cae43b79b4f5f1…`.
|
||||
|
||||
**The discriminator, both sides.** `fixtures/fake-documented-no-rule.py` — both markers in its
|
||||
docstring, so the Q35 predicate over its source is **true** (measured: `deploy` ×2,
|
||||
`SNAPSHOT_PATH.resolve()` ×1 by line count): **exit 2**, stdout 0 bytes (`e3b0c442…`), the refusal
|
||||
naming the probe rc=0 and the sentinel **written** (74 B / sha256
|
||||
`817e38302aff70659ac8f49bd1607a7843748a917eec97dc01582d95c932f437`), live delta 0.
|
||||
`fixtures/fake-marker-only.py` — the pipe's measured shape: **exit 2** at the assignment step (no
|
||||
`SNAPSHOT_PATH =` at all), stdout 0 bytes. The deployed collector
|
||||
(`HELM_COLLECTOR=/root/.helm/bin/helm-collect.py`): **exit 2** at the Q35 source check with **zero
|
||||
Q38 lines** in the output — the ordering. The admission control: `fake-marker-only.py` under the
|
||||
**Q35** gate ran G7 to completion and died at the subject import (`AttributeError: module
|
||||
'helm_collect_gate' has no attribute 'SNAPSHOT_PATH'`, traceback naming
|
||||
`/root/crucible/q35/helm-selftest.py:688`) — the admission measured end to end — while the Q38
|
||||
gate refuses the same subject before any leg runs.
|
||||
|
||||
**What moved.** Gate 1,044 → **1,141 lines, +97/−0** (`DIFF.txt`, 108 lines / sha256
|
||||
`ac8e52bb38090c66c8592a4aee9b39667d0cbbf6fefb8567043bf1e3ed0d588d`), sha256
|
||||
`643e53874e42f7ae…` → **`74aba34860b34ac6aebd8661e3e46c01ed8c15dcec1cd958ec766114abfa1ef0`**.
|
||||
The collector is byte-identical to the Q34/Q35 pair (`4e45021d…`, 720 lines, 29,954 B) — the gate
|
||||
moved, the subject did not. **§4 consequence:** the adoption pair is now collector `4e45021d…` +
|
||||
gate **`74aba348…`** (superseding `643e5387…`); the `cp` into `/root/.helm/bin/` is Alexander's.
|
||||
|
||||
**Live state, delta 0 across every leg.** `/root/.helm/data/snapshot.json`: 14,039 B / sha256
|
||||
`aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d` / mtime
|
||||
`2026-10-08 17:12:59.475780303 +0000` (mtime_ns `1791479579475780303`), identical before and after
|
||||
the 7 green runs, the 3 refusals and the admission control; the sentinel temp directories are
|
||||
removed at exit (0 left). Deployed bin untouched: `ee0b36a82f23fcf3…` / `7ed1bca8f9da624f…` /
|
||||
`5c67473d89283c3d…`. `decisions/` and `inbox/` untouched; no another-party file edited; no secret
|
||||
printed here or in the files this lands — the long strings are check names, paths and digests.
|
||||
|
||||
**Limits, stated in the deliverable:** the probe substitutes the module's `SNAPSHOT_PATH =`
|
||||
assignment, so a subject that resolves its destination by another route is not covered by the
|
||||
substitution (the delta-0 assertion catches an actual write only after the fact); the criterion is
|
||||
rc ≠ 0 **and** nothing written — a no-write rc=0 subject is admitted, correctly, since it cannot
|
||||
clobber the live snapshot bare; the timeout branch is coded and not exercised by a fixture; and
|
||||
the guard protects the gate's legs, not a direct CLI run of a pre-gate collector (the Q35 limit,
|
||||
unchanged). fake-B was deliberately **not** run under the Q35 gate: its G8 legs include a bare run
|
||||
and an explicit-live-`--out` run, either of which writes the live snapshot with an ungated subject
|
||||
— the accident class itself — so its admission was measured by the predicate directly, with fake-C
|
||||
supplying the end-to-end admission.
|
||||
|
||||
**Attribution note, mine:** this run's commits are authored `Merlin <merlin@agents.invalid>` via
|
||||
`git -c`, per the Q36 monitor fix — the Run 3 attribution fault is not repeated.
|
||||
|
||||
## Blocked
|
||||
|
||||
Nothing in my lane. Q9 waits on the checksum handover, Q13 and Q19 on Alexander, and **Q37 is the
|
||||
pipe's own tooling** — the monitor script lives in the default profile's tree and Q37's own
|
||||
analysis already names where the fault is (the counterparty's push identity), so neither the
|
||||
harness edit nor the record is mine to make.
|
||||
|
||||
## Next
|
||||
|
||||
The §4 adoption (collector `4e45021d…` + gate `74aba348…`, the two-file `cp` that makes
|
||||
`python3 helm-selftest.py` green with no environment) and the `manifest_match` pin, both
|
||||
Alexander's. Nothing else in my lane is executable; with Q38 closed the Helm candidates from Q36
|
||||
are both discharged (candidate 1 was measured in Q35's post-`cp` staging; candidate 2 is this
|
||||
run). If the adoption lands, the natural follow-on is a verification run of the *deployed* pair —
|
||||
same discriminator, one host change.
|
||||
|
||||
## Ask
|
||||
|
||||
Alexander: nothing blocking. The §4 adoption is the only thing between this scratch pair and a
|
||||
shipped gate whose default subject is green rather than self-refusing — say the word and the `cp`
|
||||
is one command, with the deployed-pair verification as the next unit.
|
||||
|
||||
— Merlin
|
||||
|
||||
---
|
||||
|
||||
Landing evidence, Run 4, 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-behavioural-guard.md` | 200 / 10,232 | `69e72474c103c727c11408aca34a666309b740db66f0cd476bc13e1772d56db9` |
|
||||
| `WORK-QUEUE.md` | 200 / <measured post-append> | <measured post-append> |
|
||||
| `checkins/2026-10-12-merlin.md` | 200 / <pre-append revision, as pushed> | <measured pre-append> |
|
||||
@@ -0,0 +1,157 @@
|
||||
# The behavioural destination guard — Q38 (Helm lane, 2026-10-12)
|
||||
|
||||
Q35 made the destination-rule guard a **precondition**, but the precondition reads a **source
|
||||
marker**: the strings `--deploy` and `SNAPSHOT_PATH.resolve()` present in the subject collector's
|
||||
source. A subject that **documents** the rule in a comment without implementing it passes that
|
||||
check and is admitted. The pipe measured exactly that on 2026-10-12T02:4xZ: a fake collector
|
||||
whose body is `import sys; sys.exit(0)` plus a comment carrying both strings ran the whole Q35
|
||||
suite to completion with live delta 0. Q38 makes the guard **behavioural**: the subject is
|
||||
executed against a sentinel destination and must **refuse**.
|
||||
|
||||
Nothing is published, nothing is deployed. The shared build tree, `/root/.helm/bin/`, the live
|
||||
snapshot, `decisions/` and `inbox/` are untouched; every figure below came from a command run in
|
||||
this pass. Scratch tree `/root/crucible/q38/`.
|
||||
|
||||
## The guard
|
||||
|
||||
At `helm-selftest.py:117–211` — after the Q35 source-marker check (`:96–114`) and **before** the
|
||||
subject is imported (`:784`) and before G8's bare-refusal leg (`:1079–1081`, the leg that executed
|
||||
an ungated subject and wrote the live snapshot in Q34's incident):
|
||||
|
||||
1. A copy of the subject's source is written to the gate's own scratch tree, with its
|
||||
`SNAPSHOT_PATH =` assignment rewritten to a **sentinel** path
|
||||
(`<gate dir>/helm-q38-*/snapshot.json`, created per invocation, removed at exit).
|
||||
2. The copy is run as a **subprocess**, bare: `python3 <probe> --skip-tests` — no `--out`, no
|
||||
`--deploy`, 180 s timeout. The subject's module-level code never executes inside the gate's
|
||||
process (the Q35 mechanism probe imported and rebound in-process; this one does not).
|
||||
3. The subject **passes** iff the run exits non-zero **and** writes nothing to the sentinel
|
||||
**and** the live snapshot is byte- and mtime-identical before and after. Otherwise the gate
|
||||
exits **2** with a stderr message naming the subject, the probe path, the probe rc, the
|
||||
sentinel's byte count and sha256, and the live snapshot's before/after readings — and **no
|
||||
leg runs**. A subject that exits 0 and writes nothing is admitted: it cannot clobber the live
|
||||
snapshot bare, which is the property under test.
|
||||
4. A subject carrying no `SNAPSHOT_PATH =` assignment at all is refused at step 1 — the
|
||||
destination the rule keys on does not exist, and such a subject crashes the gate at the
|
||||
import (`:784`) anyway.
|
||||
|
||||
The Q35 source check is **kept** as the fast first filter and fires first (measured below); the
|
||||
behavioural check is the authority. The precondition registers no `check()`, so the green pair
|
||||
still reports exactly 164 passed / 0 failed; the positive side prints one `Q38 OK` line on stderr
|
||||
in every gate log so it is visible rather than implicit.
|
||||
|
||||
Gate: 1,044 → **1,141 lines, +97/−0** (`git diff --no-index --numstat`; `DIFF.txt` 108 lines /
|
||||
sha256 `ac8e52bb38090c66c8592a4aee9b39667d0cbbf6fefb8567043bf1e3ed0d588d`), sha256
|
||||
`643e53874e42f7ae…` → **`74aba34860b34ac6aebd8661e3e46c01ed8c15dcec1cd958ec766114abfa1ef0`**.
|
||||
The collector is byte-identical to the Q34/Q35 pair: `4e45021d80395d3f…`, 720 lines, 29,954 B.
|
||||
Both fixtures and the runner (`run-green.sh`) live in the same tree.
|
||||
|
||||
## The subjects and the matrix
|
||||
|
||||
| subject | Q35 source check | Q38 behavioural | outcome |
|
||||
|---|---|---|---|
|
||||
| pair `4e45021d…` (`/root/crucible/q38/helm-collect.py`) | pass | pass (probe rc=2, sentinel not written, live delta 0) | admitted — 7× green |
|
||||
| `fixtures/fake-documented-no-rule.py` | **pass** (both markers in its docstring) | **fail** (rc=0, sentinel written) | exit 2, no leg |
|
||||
| `fixtures/fake-marker-only.py` (the pipe's measured shape) | **pass** | **fail** (no `SNAPSHOT_PATH =` assignment) | exit 2, no leg |
|
||||
| deployed `/root/.helm/bin/helm-collect.py` (`ee0b36a8…`) | **fail** (no markers) | not reached | exit 2 at Q35 — the ordering |
|
||||
|
||||
### Green pair — 7 consecutive invocations
|
||||
|
||||
`HELM_COLLECTOR=/root/crucible/q38/helm-collect.py python3 helm-selftest.py`, exit 0 each,
|
||||
`helm-selftest: 164 passed, 0 failed` and `VERDICT: ALL GATES PASS` in every log, and the
|
||||
`Q38 OK: the subject refused its sentinel destination (probe rc=2, sentinel written=False, live
|
||||
delta 0)` line present in all seven (`run-green.sh` reads the live snapshot's sha256 and mtime
|
||||
around every invocation; delta 0 on all seven). Log digests:
|
||||
|
||||
`f606bf3877cd6a96…` / `4cd6456713f2e1ff…` / `02ecbf989f2d162c…` / `94781f8dfa0f4ac8…` /
|
||||
`a2380b7ab4c61435…` / `fbd5e11713a6c048…` / `d0cae43b79b4f5f1…`
|
||||
|
||||
The logs differ run to run in the temp paths only (the Q35 tick's C15 class); the verdict line is
|
||||
identical in all seven and is what the digests are quoted for.
|
||||
|
||||
### fake-B — documents the rule, writes its default anyway
|
||||
|
||||
`HELM_COLLECTOR=/root/crucible/q38/fixtures/fake-documented-no-rule.py python3 helm-selftest.py`
|
||||
→ **exit 2**, stdout **0 bytes** (`e3b0c442…`, the empty-file digest — no `helm-selftest:` summary
|
||||
and no PASS line exists, which is how "no leg executed" is measured), stderr
|
||||
(`q38-refuse-fakeB.err`, sha256 `38dcd0e40b05f9ba…`):
|
||||
|
||||
> Q38 REFUSAL: the subject collector … carries no WORKING destination rule — a bare run against
|
||||
> the sentinel exited rc=0 (stderr: ); sentinel written=True (74 B /
|
||||
> `817e38302aff70659ac8f49bd1607a7843748a917eec97dc01582d95c932f437`); live delta 0 — so no leg
|
||||
> is executed.
|
||||
|
||||
Its docstring carries both marker strings, so the Q35 predicate over its source is **true**
|
||||
(measured: `deploy` ×2, `SNAPSHOT_PATH.resolve()` ×1 by line count on the fixture) — it is
|
||||
admitted by the source check and refused by behaviour. Its unrewritten default destination is
|
||||
deliberately **not** the live snapshot: the unrewritten file is never executed by this gate, but a
|
||||
non-live default means even a false admission during measurement could not clobber live state.
|
||||
The real-world subject this models — the deployed collector — has the live snapshot as its
|
||||
default, and that is the shape Q34's incident ran.
|
||||
|
||||
**fake-B was not run under the Q35 gate.** Its G8 legs include a bare run (`:982` in the Q35
|
||||
file) and an explicit-live-`--out` run (`:994`), either of which writes the live snapshot with an
|
||||
ungated subject — the accident class itself. The admission was measured by the predicate
|
||||
directly, and the end-to-end admission is shown by fake-C below.
|
||||
|
||||
### fake-C — the pipe's measured shape, admitted by Q35, refused by Q38
|
||||
|
||||
`HELM_COLLECTOR=/root/crucible/q38/fixtures/fake-marker-only.py python3 helm-selftest.py`
|
||||
→ **exit 2**, stdout 0 bytes, stderr (`q38-refuse-fakeC.err`, sha256
|
||||
`b3ab82a71d170998…`): *"carries no WORKING destination rule — the subject carries no
|
||||
`SNAPSHOT_PATH =` assignment, so its default destination is not the module constant the rule
|
||||
keys on — so no leg is executed."*
|
||||
|
||||
The same subject under the **Q35** gate
|
||||
(`HELM_COLLECTOR=… python3 /root/crucible/q35/helm-selftest.py`, `q35-admit-fakeC.log`, 841 B /
|
||||
sha256 `691155d4b99dee0b…`) ran G7 to completion and then died at the subject import —
|
||||
`AttributeError: module 'helm_collect_gate' has no attribute 'SNAPSHOT_PATH'` at
|
||||
`helm-selftest.py:688` — which is the admission, measured: the Q35 precondition passed the
|
||||
subject and the gate proceeded past it. Under Q38 the same subject never reaches the import.
|
||||
|
||||
### Ordering — the deployed collector is still refused at Q35
|
||||
|
||||
`HELM_COLLECTOR=/root/.helm/bin/helm-collect.py python3 helm-selftest.py` → **exit 2**, stdout 0
|
||||
bytes, stderr (`q38-refuse-deployed.err`, sha256 `2aaa36c1f8277e90…`, byte-identical to the Q35
|
||||
tick's own `q35-refuse-deployed.err`) carrying the **Q35 REFUSAL** line and zero Q38 lines: the
|
||||
source-marker check fires first, the behavioural check is not reached, live delta 0.
|
||||
|
||||
## Live state, measured before and after every leg
|
||||
|
||||
`/root/.helm/data/snapshot.json`: **14,039 B / sha256
|
||||
`aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d` / mtime
|
||||
`2026-10-08 17:12:59.475780303 +0000` (mtime_ns `1791479579475780303`)** — identical before and
|
||||
after each of the 7 green runs, each of the 3 refusals, and the Q35 admission control. The
|
||||
sentinel temp directories are removed at exit (0 left behind).
|
||||
|
||||
Deployed bin untouched: `helm-collect.py` `ee0b36a82f23fcf3…` (687 lines / 27,907 B),
|
||||
`helm-selftest.py` `7ed1bca8f9da624f…` (609 / 33,647), `helm-render.py`
|
||||
`5c67473d89283c3d…` (496 / 21,766). Nothing deployed, nothing rebuilt, nothing published;
|
||||
`decisions/` and `inbox/` untouched; no another-party file edited; no secret printed here or in
|
||||
the files this lands.
|
||||
|
||||
## Limits, stated
|
||||
|
||||
- The probe substitutes the module's `SNAPSHOT_PATH =` assignment. A subject that resolves its
|
||||
destination by another route — a hardcoded path, an environment variable — is not covered by
|
||||
the substitution; the live-delta-0 assertion would catch an actual write only **after** the
|
||||
fact. The pair keys on the module's own `SNAPSHOT_PATH` (Q31/Q35 measured that rebinding does
|
||||
not disable the rule), so the substitution is sound for this artifact family; it is not a
|
||||
general sandbox.
|
||||
- The refusal criterion is rc ≠ 0 **and** nothing written **and** delta 0. A subject that
|
||||
refuses with rc = 0 while writing nothing is admitted — correct, since it cannot clobber the
|
||||
live snapshot bare — but "refuses" is defined by the non-zero exit, not by a message.
|
||||
- The timeout branch (rc `None`) is coded and not exercised by a fixture.
|
||||
- The guard protects the **gate's legs**, not a direct CLI run of a pre-gate collector — the
|
||||
Q35 limit, unchanged.
|
||||
- The bare-run leg now admits only behaviourally gated subjects, but the shipped gate is still
|
||||
the pre-Q38 one: the §4 `cp` is Alexander's, and with this run the adoption pair becomes
|
||||
collector `4e45021d…` + gate **`74aba348…`** (superseding `643e5387…`).
|
||||
|
||||
## Artifacts
|
||||
|
||||
`/root/crucible/q38/`: `helm-selftest.py` (the patched gate), `helm-collect.py` (the pair,
|
||||
unchanged), `fixtures/fake-documented-no-rule.py`, `fixtures/fake-marker-only.py`,
|
||||
`DIFF.txt`, `run-green.sh`, `q38-gate-run-1..7.log`, `q38-refuse-fakeB.{log,err}`,
|
||||
`q38-refuse-fakeC.{log,err}`, `q38-refuse-deployed.{log,err}`, `q35-admit-fakeC.log`.
|
||||
|
||||
— Merlin, 2026-10-12
|
||||
Reference in new issue
Block a user