From a16d9e45be053831ec63c2fdac1dbf108caca666 Mon Sep 17 00:00:00 2001 From: Merlin Date: Mon, 12 Oct 2026 00:28:38 +0000 Subject: [PATCH] =?UTF-8?q?Q34=20DONE:=20the=20pointer's=20null=20case=20i?= =?UTF-8?q?s=20gated=20(recoveries/helm-null-gate.md,=20scratch=20/root/cr?= =?UTF-8?q?ucible/q34/).=20Four=20checks=20planted=20in=20the=20gate's=20o?= =?UTF-8?q?wn=20scratch=20tree=20between=20two=20collects=20on=20a=20profi?= =?UTF-8?q?le=20with=20sessions/=20and=20logs/=20and=20no=20files:=20lates?= =?UTF-8?q?t=5Factive=5Fpath=20null,=20source=5Fpath=20still=20the=20profi?= =?UTF-8?q?le=20directory,=20the=20key=20present=20with=20value=20null=20r?= =?UTF-8?q?ather=20than=20absent,=20and=20a=20follow-up=20collect=20where?= =?UTF-8?q?=20a=20planted=20file=20sets=20the=20pointer=20while=20the=20ci?= =?UTF-8?q?tation=20holds;=20the=20member=20analogue=20stated=20unreachabl?= =?UTF-8?q?e=20by=20construction.=20Seven=20consecutive=20green=20gate=20i?= =?UTF-8?q?nvocations=20(exit=200,=20164=20passed=200=20failed=20each,=20t?= =?UTF-8?q?he=20Q33=20160=20plus=20these=20four),=20log=20digests=20in=20t?= =?UTF-8?q?he=20deliverable.=20Red=20on=20both=20comparators:=20Q33-before?= =?UTF-8?q?=20collector=20under=20the=20full=20gate=20exit=201=20/=20153?= =?UTF-8?q?=20passed=2011=20failed=20(the=20Q33=20nine=20plus=20Q34=20chec?= =?UTF-8?q?ks=203=20and=204);=20pre-Q33=20collector=202=20passed=202=20fai?= =?UTF-8?q?led=20on=20the=20four=20checks=20by=20module=20import=20with=20?= =?UTF-8?q?no=20subprocess=20leg;=20checks=201-2=20pass=20vacuously=20on?= =?UTF-8?q?=20both=20comparators=20and=20are=20reported=20as=20vacuous.=20?= =?UTF-8?q?The=20collector=20did=20not=20move=20(byte-identical=20to=20the?= =?UTF-8?q?=20Q33=20pair,=204e45021d,=20720=20lines);=20the=20gate=20moved?= =?UTF-8?q?=20+56/-0=20(929=20->=20985=20lines,=2045e53187),=20so=20the=20?= =?UTF-8?q?=C2=A74=20adoption=20ask=20is=20now=20a=20three-file=20ask.=20O?= =?UTF-8?q?ne=20incident=20logged=20first:=20the=20first=20red=20leg=20ran?= =?UTF-8?q?=20the=20full=20gate=20against=20the=20pre-Q33=20collector,=20w?= =?UTF-8?q?hich=20has=20no=20destination=20gate,=20so=20the=20bare=20--ski?= =?UTF-8?q?p-tests=20leg=20wrote=20the=20live=20snapshot=20(aa842b0f=20->?= =?UTF-8?q?=20e4d1ad5,=2014039=20->=2018524=20B,=20mtime=5Fns=201791479579?= =?UTF-8?q?475780303=20->=201791764761933369921=20at=2000:26:01Z);=20resto?= =?UTF-8?q?red=20byte-exact=20from=20/root/crucible/q31/snap-before.json?= =?UTF-8?q?=20with=20the=20mtime=20re-stamped=20and=20the=20comparator=20r?= =?UTF-8?q?e-run=20by=20import=20only;=20live=20snapshot=20delta=200=20acr?= =?UTF-8?q?oss=20every=20leg=20after=20the=20restore.=20Deployed=20bin=20u?= =?UTF-8?q?ntouched.=20Limits:=20a=20live=20empty=20profile=20is=20unobser?= =?UTF-8?q?ved;=20checks=201-2=20vacuous=20on=20the=20comparators;=20the?= =?UTF-8?q?=20null=20value=20is=20not=20schema-constrained.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WORK-QUEUE.md | 24 +++++- checkins/2026-10-12-merlin.md | 102 +++++++++++++++++++++++ recoveries/helm-null-gate.md | 150 ++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+), 2 deletions(-) create mode 100644 checkins/2026-10-12-merlin.md create mode 100644 recoveries/helm-null-gate.md diff --git a/WORK-QUEUE.md b/WORK-QUEUE.md index 7bc209c..b2f5ee2 100644 --- a/WORK-QUEUE.md +++ b/WORK-QUEUE.md @@ -4496,8 +4496,28 @@ the profile directory and (c) the key is present rather than absent (a reader mu are **red on the pre-Q33 collector, green on the patched pair**, and reported as **N consecutive green invocations, N ≥ 5**, each with its log digest. **Evidence:** the new check names with their pass/fail on both collectors, the gate logs with digests, the before/after `evidence` blocks for the empty profile, and the live snapshot delta 0. -**Status: OPEN — named to the Helm lane.** Deliberately separate from Q33's record: Q33's deliverable is a finished -artifact and the adoption pair under §4 must not move under a second edit while Alexander is deciding on it. +**Status: DONE 2026-10-12 — `recoveries/helm-null-gate.md` (Merlin), scratch tree `/root/crucible/q34/`.** +Four checks planted in the gate's own scratch tree (profile `empty` with `sessions/` and `logs/` and no +files, between two collects): (a) `evidence.latest_active_path` is `null`, (b) `evidence.source_path` stays the +profile directory, (c) the key is **present** with value `null` rather than absent, (d) after a file lands the +pointer is set and the citation is unchanged. The member analogue is stated unreachable by construction, not +asserted (a member row exists only for an existing check-in file). **Seven consecutive green gate invocations** +(exit 0, `164 passed, 0 failed` each — the Q33 suite's 160 plus these four), log digests in the deliverable. +Red on both comparators: the Q33-before collector under the full gate **exit 1 / 153 passed, 11 failed** (the +Q33 nine plus Q34 checks 3 and 4), and the pre-Q33 collector **2 passed / 2 failed** on the four Q34 checks +(module-import run, no subprocess leg) — checks 1 and 2 pass vacuously on both comparators and are reported as +such, so the discriminating checks are 3 and 4. The collector **did not move** (byte-identical to the Q33 pair, +`4e45021d…`, 720 lines); the gate moved **+56/−0** (929 → 985 lines, `45e53187…`). Live snapshot delta 0 across +every leg after the restore below; deployed bin untouched. **One incident, logged first in the deliverable:** +the first red leg ran the full gate with `HELM_COLLECTOR` pointed at the pre-Q33 collector, which has no +destination gate, so the gate's own bare `--skip-tests` leg wrote the live snapshot (`aa842b0f…` → `e4d1ad5…`, +14,039 → 18,524 B, mtime_ns `1791479579475780303` → `1791764761933369921`, 2026-10-12T00:26:01Z); restored +byte-exact from `/root/crucible/q31/snap-before.json` with the mtime re-stamped (`VERDICT: RESTORED +BYTE-EXACT`), and the comparator re-run by import only. **§4 consequence:** the adoption ask now covers three +scratch files — collector `4e45021d…` unchanged, selftest `4a442f62…` superseded by `45e53187…`. Limits: a live +empty profile is still unobserved (the branch is exercised by the fixture, not by production data); checks 1–2 +are vacuous on the comparators; the null value is not schema-constrained. Scratch artifacts +`/root/crucible/q34/`: gate, both comparators, the seven logs, `Q34-NULL-EVIDENCE.txt`, `q34-restore.py`. **Q33 citation repair — the pre-Q32 control figure does not match the log it cites. 2026-10-11 22:43Z (control plane).** One block, one subject, appended after reading the tail and grepping for the existing record: the diff --git a/checkins/2026-10-12-merlin.md b/checkins/2026-10-12-merlin.md new file mode 100644 index 0000000..eea226d --- /dev/null +++ b/checkins/2026-10-12-merlin.md @@ -0,0 +1,102 @@ +# 2026-10-12 — 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. + +--- + +## Did + +Claimed and finished **Q34 — gate the pointer's null case**, the last open item and the one named to +my lane (Q20 is zephyrus-sparkborn's, Q9 blocked on the audio handover, Q13/Q19 gated on Alexander). +Deliverable: `recoveries/helm-null-gate.md` (**9,924 B / sha256 +`84b1e714bfad1c0be948845f0f0a9f92a739ce5b64b68a197523bbb7c0808a58`**, this host). Queue block +appended to `WORK-QUEUE.md` (was 519,292 B / sha256 +`592523616f8b9a8ca45f4dabc631508baeb173c68de1f01cc125c0b0682a4f3e` before this run's append). +Scratch tree `/root/crucible/q34/`; nothing deployed. + +**What was gated.** Q33's one `unverified` limit: `evidence.latest_active_path: null` for a profile +with a `sessions/` directory and no files, with the Q32 pointer carve-out deleted, needed an +exercised branch. The gate now plants, in its own scratch tree between two collects, a profile +`empty` carrying `sessions/` and `logs/` and no files, and asserts four things — pointer `null`, +citation 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 is stated unreachable by construction, not asserted (a member row exists only for an +existing check-in file); the rule is a comment in the gate, not a test. + +**Seven consecutive green invocations**, exit 0 each, `helm-selftest: 164 passed, 0 failed` (the +Q33 suite's 160 plus these four), log digests in the deliverable: +`7f01728d…` / `997b1308…` / `96678a66…` / `f13e5cd6…` / `532ab633…` / `00bea997…` / `d4e39936…`. + +**Both comparators red where it matters.** The Q33-before collector under the full gate: +`exit 1, 153 passed, 11 failed` (`q34-gate-q33before.log`, sha256 +`7e53bb46adcdfda5f66c93dd780732fdc89207e5d5073bf56bd5921f3a94f1d5`) — the Q33 nine plus Q34 checks +3 and 4. The pre-Q33 collector on the four Q34 checks by module import, no subprocess leg: +**2 passed / 2 failed** (`q34-red-pregate.log`, sha256 +`093f60e587186827a77e7f31247735b2048a8e86540a47485acf6324f95f1571`). Checks 1 and 2 pass +*vacuously* on both comparators (an absent key satisfies `.get() is None`, and a pointer-less +citation falls back to the directory) and are reported as vacuous, so the discriminating checks are +3 and 4 — both red on both comparators. + +**Before/after evidence for the empty profile** (from the gate's own dump, run 7, +`Q34-NULL-EVIDENCE.txt`, sha256 `c625bc07068c5040d91117d604208152b33f34f0416e96dfc51d326546c3473c`): +before — `"latest_active_path": null`, `"source_path": "/tmp/tmp5r57iyp4/q34-null/profiles/empty"`; +after planting `sessions/landed.jsonl` at mtime +60 s — the pointer is that file and +`source_path` is unchanged. The key is present in the before block; the citation does not move. + +**What moved.** The collector did not: `/root/crucible/q34/helm-collect.py` is byte-identical to +the Q33 pair's (`4e45021d80395d3f…`, 720 lines). The gate moved **+56/−0** +(`git diff --no-index --numstat` → `56 0`), 929 → 985 lines, sha256 +`45e53187c01398df7a0edcbf24a08b7d91255eda0cfe93b9cb01e8398f0d7091`. Deployed bin untouched: +`helm-collect.py` `ee0b36a82f23fcf3…`, `helm-selftest.py` `7ed1bca8f9da624f…`, +`helm-render.py` `5c67473d89283c3d…`. + +**One incident, logged first and corrected.** The first red leg ran the full gate with +`HELM_COLLECTOR` pointed at the **pre-Q33** collector — which has no destination gate, Q31's own +finding — so the gate's bare `--skip-tests` refusal leg executed it and it **wrote the live +snapshot**: `aa842b0fd88037f8…` → `e4d1ad5293fa58cb…`, 14,039 → 18,524 B, mtime_ns +`1791479579475780303` → `1791764761933369921` (2026-10-12T00:26:01.933369921Z). Restored byte-exact +from `/root/crucible/q31/snap-before.json` with the mtime re-stamped (`q34-restore.py`, +`VERDICT: RESTORED BYTE-EXACT`); post-restore **14,039 B / sha256 +`aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d` / mtime_ns +`1791479579475780303`**, and the comparator re-run by import only. Live snapshot **delta 0 across +every leg after the restore** — seven green runs, the Q33-before comparator and the import-only +comparator. This is the harness rule the skill already carries (*a negative control must never run +ungated code against a live default*) walked into anyway; the standing rule is now mechanical in +this tree: no `HELM_COLLECTOR` naming a pre-gate collector is ever passed to the full gate. + +## Blocked + +Nothing in my lane. Q13/Q19 wait on Alexander, Q9 on the audio handover, Q20 is zephyrus's — none +of them is mine to move. One thing my own run made Alexander's, below. + +## Next + +Two things, both stated in the deliverable and neither mine to execute: + +1. **§4 adoption, now a three-file ask.** Collector `4e45021d…` unchanged from Q33; selftest + `4a442f62…` (Q33) superseded by `45e53187…` (this run). The pair production has never run + under the gate that ships with it, so the `cp` into `/root/.helm/bin/` approves + collector + Q34-gated selftest together. Alexander's call. +2. **A live empty profile is still unobserved** — every profile under `/root/.hermes/profiles/` + has files today, so the null branch is exercised by the gate's fixture, not by production data. + The branch is proven; the data class is not. Nothing to do unless a profile is emptied. + +Also worth naming for the queue: the Q34 gate writes its `Q34-NULL-EVIDENCE.txt` dump into the +gate's own directory on every invocation, so that file is a dated reading, not a stable artifact — +digest run 7 is quoted above, and the deliverable says so. + +## Ask + +Alexander: nothing blocking. If you want the Helm render's `manifest_match` pin re-taken, say so — +it has been stale since 2026-10-08 (`f27326e8…` pinned against a live body now +`e7df6364…` / 215,836 B) and a static render cannot say so, which is a separate decision about +whether that pin should exist at all. + +--- + +Landing evidence, appended after commit and read back over the anonymous raw path +(`https://forge.alexanderwhitestone.com/git/stackchain/troupe-standup/raw/branch/main/`), no +credential — each **HTTP 200** and `cmp` **byte-identical** to disk. Table filled at push time. + +— Merlin diff --git a/recoveries/helm-null-gate.md b/recoveries/helm-null-gate.md new file mode 100644 index 0000000..17f1d2e --- /dev/null +++ b/recoveries/helm-null-gate.md @@ -0,0 +1,150 @@ +# The pointer's null case, gated + +**Q34 — collector-side gate. Author: Merlin (`merlin@agents.invalid`). Clock: 2026-10-12T00:24–00:28Z, this host.** +**Scratch tree: `/root/crucible/q34/`. Nothing deployed; the §4 adoption pair is untouched by this run.** + +Q33's one `unverified` limit, now exercised. The patched collector emits +`evidence.latest_active_path: null` for a profile with no files under `sessions/` / +`cron/output/` / `logs/`; every planted tree in the Q33 checks has files and the live collect is +20/20 non-None, so the null branch was exercised by nothing in the suite — and on the pre-Q33 +collector the two pointer non-vacuity checks pass `0/0` vacuously, since that collector emits +neither pointer key at all. Q34 plants the empty profile inside the gate's own scratch tree, +between two collects, and asserts the three properties the item names plus a fourth that makes +the null a *measured* null rather than a missing field. + +## The four checks (gate section `# ---- Q34: the pointer's null case ----`, `helm-selftest.py:866-925`) + +The fixture: profile `empty` with `sessions/` and `logs/` present and **no files** anywhere, +planted in a `TemporaryDirectory` under the gate's own `td`, `PROFILES_DIR` rebound exactly as +the Q33 checks do it (`:875-889`), restored in a `finally`. Two collects: before, and after +`sessions/landed.jsonl` is planted at mtime +60 s. + +| # | check name (verbatim, as printed) | patched pair | Q33-before collector | pre-Q33 (pregate) collector | +|---|---|---|---|---| +| 1 | `Q34: evidence.latest_active_path is null for a profile with a sessions/ directory and no files` | PASS | PASS (vacuous — `.get()` returns `None` for an absent key) | PASS (vacuous, same reason) | +| 2 | `Q34: the null pointer's evidence.source_path is still the profile directory (the citation survives an empty profile)` | PASS | PASS | PASS | +| 3 | `Q34: the key is present with value null, not absent (a reader can tell 'no files' from 'field missing')` | PASS | **FAIL** `present=False value=None` | **FAIL** `present=False value=None` | +| 4 | `Q34: after a file lands the pointer is set and the citation is unchanged (the null was a real reading, not a missing field)` | PASS | **FAIL** `null -> None; source_path …/empty -> …/empty/sessions/landed.jsonl` | **FAIL** same shape | + +Check 3 is the discriminator; checks 1 and 2 are structural on both comparators and pass there +for the stated reason — reported as vacuous passes, not as failures of the comparator. The +member analogue (`evidence.newest_checkin_file: null`) is **unreachable by construction and is +stated, not asserted**: a member row is emitted only for a file that exists under the check-ins +directory, so `collect_troupe()` cannot produce a member with no newest file. The rule is in the +gate as a comment at `:870-875`. + +## Consecutive green invocations — 7, not 5 + +`HELM_COLLECTOR=/root/crucible/q34/helm-collect.py python3 helm-selftest.py`, exit 0 every time, +`helm-selftest: 164 passed, 0 failed` (the Q33 suite's 160 plus these four): + +| run | log | sha256 of log | +|---|---|---| +| 1 | `q34-gate-run-1.log` | `7f01728d08227755fddb5baa445b75fff9c4bd8e0fb6bf5596fca2fd938ba5bf` | +| 2 | `q34-gate-run-2.log` | `997b1308242f7fe63ae331f82afbdbde8a822288d61ca54afb9906dfdd0c2205` | +| 3 | `q34-gate-run-3.log` | `96678a66bb5c8e07d8ebc17ef13ef22c83a75390c8514926ae2b84639a6e6912` | +| 4 | `q34-gate-run-4.log` | `f13e5cd600579fbc7e6bd06f781f489b59dff96f377433c8156b31d4ffe52317` | +| 5 | `q34-gate-run-5.log` | `532ab633fb36c5864ff756084e568b8052d348b004e9f57658af86086446bd7f` | +| 6 | `q34-gate-run-6.log` | `00bea9975b861c39ec9d96fcb5f09faf93aad9aa1e8c8f9266848fa069455c8c` | +| 7 | `q34-gate-run-7.log` | `d4e39936e52491ef55317915a28ee20a501faf32f3dddd1d75729399f6aea69e` | + +Log digests differ run to run only by clocks and durations; the verdict line is identical in all +seven (`VERDICT: ALL GATES PASS`). + +## The empty profile's `evidence` block, before and after + +From `Q34-NULL-EVIDENCE.txt` (written by the gate on every run; the digest below is run 7's, +**sha256 `c625bc07068c5040d91117d604208152b33f34f0416e96dfc51d326546c3473c`** — the file is +regenerated each invocation, so it is a dated reading, not a stable artifact): + +``` +profile dir : /tmp/tmp5r57iyp4/q34-null/profiles/empty (sessions/ and logs/ present, no files) +collector : /root/crucible/q34/helm-collect.py + +--- before (no files anywhere under the profile) --- +{ + "latest_active_path": null, + "observed_at": "2026-10-12T00:27:09.204Z", + "source_path": "/tmp/tmp5r57iyp4/q34-null/profiles/empty" +} + +--- after (sessions/landed.jsonl planted, mtime +60s) --- +{ + "latest_active_path": "/tmp/tmp5r57iyp4/q34-null/profiles/empty/sessions/landed.jsonl", + "observed_at": "2026-10-12T00:27:09.206Z", + "source_path": "/tmp/tmp5r57iyp4/q34-null/profiles/empty" +} +``` + +The key is **present** in the before block with value `null`; the citation does not move. + +## The comparators + +- **Q33-before collector** (`helm-collect-q33-before.py`, **8a477376f72c578b…**, the Q33-before + collector with the destination gate intact): full gate, **exit 1, `153 passed, 11 failed`** + (`q34-gate-q33before.log`, sha256 `7e53bb46adcdfda5f66c93dd780732fdc89207e5d5073bf56bd5921f3a94f1d5`). + The eleven are the Q33 suite's nine (eight pointer checks + the declared-key source check, + which lists `latest_active_path, newest_checkin_file` as not emitted) plus Q34 checks 3 and 4. +- **Pre-Q33 collector** (`helm-collect-pregate.py`, **ee0b36a82f23fcf3…**, the deployed + collector): Q34 checks only, by module import with `PROFILES_DIR` rebound, **no subprocess leg** + (`q34-red-pregate.py`, output `q34-red-pregate.log`, sha256 + `093f60e587186827a77e7f31247735b2048a8e86540a47485acf6324f95f1571`): **2 passed / 2 failed**, + the two failures being checks 3 and 4 as tabulated above. + +## Incident, logged first — a bare run of the pre-Q33 collector wrote the live snapshot + +The first red leg ran the full gate with `HELM_COLLECTOR` pointed at the **pre-Q33** collector. +That collector has **no destination gate** (Q31's finding), so the gate's own bare +`subprocess.run([sys.executable, COLLECTOR, "--skip-tests"])` leg — the one that asserts a refusal +— executed the collector, which wrote the live snapshot. Measured: +`/root/.helm/data/snapshot.json` went `aa842b0fd88037f8…` → `e4d1ad5293fa58cb…`, 14,039 → 18,524 B, +mtime_ns `1791479579475780303` → `1791764761933369921` (2026-10-12T00:26:01.933369921Z). The run +also aborted at the argparse `--deploy` error, so it produced no usable comparator. + +Restored byte-exact from `/root/crucible/q31/snap-before.json` (the Q31 pre-run copy, itself +verified `aa842b0f…` / 14,039 B before the restore): `q34-restore.py` copied the bytes and re-stamped +`mtime_ns` to `1791479579475780303`. Post-restore: **14,039 B / sha256 +`aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d` / mtime_ns +`1791479579475780303`**, `VERDICT: RESTORED BYTE-EXACT`. The pre-Q33 comparator was then re-run by +module import only. This is the harness incident the skill already warns about — *a negative control +must never run ungated code against a live default* — and it happened anyway; the standing rule is +now mechanical in this tree: no `HELM_COLLECTOR` value naming a pre-gate collector is ever passed +to the full gate. + +**Live snapshot delta 0 across every other leg**, including all seven green invocations, the +Q33-before comparator and the import-only pre-Q33 comparator: `/root/.helm/data/snapshot.json` reads +`aa842b0fd88037f8…` / 14,039 B / mtime_ns `1791479579475780303` at every checkpoint after the +restore. + +## What moved, and what did not + +- **The collector did not move.** `/root/crucible/q34/helm-collect.py` is byte-identical to the Q33 + pair's collector: sha256 `4e45021d80395d3f03fc58d7e99610e3c1c0d2fcf9c85f1db50b16cfd2043c6c`, + 720 lines / 29,954 B. Q34 is a gate-only change, as the item requires — Q33's adoption pair is + not re-edited under a second item. +- **The gate moved +56 / −0** against the Q33 selftest: `/root/crucible/q31/helm-selftest.py` + (929 lines) → `/root/crucible/q34/helm-selftest.py` (**985 lines**, sha256 + `45e53187c01398df7a0edcbf24a08b7d91255eda0cfe93b9cb01e8398f0d7091`). + `git diff --no-index --numstat` → `56 0`. 160 → 164 checks. +- **Deployed bin untouched:** `/root/.helm/bin/helm-collect.py` `ee0b36a82f23fcf3…`, + `helm-selftest.py` `7ed1bca8f9da624f…`, `helm-render.py` `5c67473d89283c3d…`, unchanged. +- **Consequence for §4, stated:** the adoption ask now approves **three** scratch files, not two — + collector `4e45021d…` (unchanged from Q33), selftest `4a442f62…` (Q33) **superseded by** + `45e53187…` (this item). Alexander's decision should be read as covering the pair-plus-gate. + +## Limits + +1. **A live empty profile is still unobserved.** Every profile under + `/root/.hermes/profiles/` currently has files; the null branch is exercised by the gate's + fixture, not by production data. Measured non-destructively (Q33's import-based probe, this + host, 2026-10-11) and now by the gate itself. +2. **Checks 1 and 2 pass vacuously on both comparators** — they hold for an absent key and for a + pointer-less citation fallback. The discriminating checks are 3 and 4, and both are red on both + comparators. Stated so the `2/2` and `2/4` red figures are not read as a weaker gate than they + are. +3. **The `latest_active_path: null` value is not schema-constrained.** Q33 measured that the + schema's `$defs.evidence` has no `additionalProperties: false`; nothing asserts the field's + type, only its presence and its null-ness in this fixture. Out of Q34's scope. +4. **Testimony only, not verified this run:** the Q33 suite's own checks above the Q34 section + (160 of the 164) were not re-derived here; this run measures that the Q34 section is green, + discriminating, and non-destructive.