04 Recovery
This is a COPY for the operator's reading room. The original (above) is the authority — if they ever disagree, the original wins and this file is regenerated. Generated 2026-10-12 18:27 by mira.
The restore proof is built, it ran, and it found something
The stage's own rule: "9.4 is the whole stage. A backup nobody has restored is a belief." So this is not a description of a restore — it is one that was executed.
Script: ~/.hermes/profiles/mira/scripts/restore-proof.sh
0b. ✅ UPDATE 05:51 UTC — the proof PASSES, and it has now done its job twice
Host restarted, Sol committed (8699d93), and the proof went green:
[restore-proof] cloned: 8699d93 — 🔴 I left the retention blocklist INERT — half
[restore-proof] PROBES PASS against the restored root:
440 passed, 2 skipped, 2 xfailed, 1 warning in 9.31s
[restore-proof] registry restored: 11 agents, and it loads from the RESTORED root
[restore-proof] registry identical between live and restored — no drift
[restore-proof] scratch cleaned
[restore-proof] RESULT: ✅ RESTORED INTO AN EMPTY ROOT AND THE PROBES PASSED
440 passed, 0 failed, against a fresh clone of the real remote. The registry restores, parses, holds all 11 agents, and is byte-identical to live.
And the proof's real value: it caught the defect that made the blocklist inert
Min's commit message says it outright — "🔴 I left the retention blocklist INERT — half-wired, caught by the restore proof."
Commit 4419407 (Stage 6.4b) added RETENTION_BLOCKLIST and its tests but not the
wiring in router.py, so route() had no blocklist parameter. A blocklist no
caller can pass is the same defect as the router with zero callers (C1) — the
capability with no caller, in the module built to close that defect. It looked
complete and did nothing.
That is the stage's own thesis, proven on itself. Min's lesson: "a commit that names two of three files is a partial commit, and the missing file is the one that makes the feature real."
Now verified as genuinely wired, not as compiling
route()acceptsblocklist:— checked via its signature, not by readingconfidential + muse-spark→REFUSED: muse-spark-1.3-contributor-free is on the rete[ntion blocklist]— the refusal is produced, not described- Falsifier run: neutering the
if chosen in blocklist:check → 7 red; restoring it → 17 green. A control that cannot be broken is decoration.
And it is scheduled, then forced to run
restore-proof-daily, 03:30, --no-agent — so a rehearsal costs zero model
calls and cannot be silently skipped. Proved by triggering it rather than waiting
eight hours: "Ran now: succeeded", and the delivery is on disk at
~/.hermes/profiles/mira/cron/output/34335e5dcd4e/2026-10-11_16-56-52.md.
So Stage 9.4 is now complete on measurement. It stays scheduled permanently — not because the result is green, but because a proof that is only run once is a snapshot, and this one has already caught two defects in three runs.
0. UPDATE 05:15 UTC — the second run, after Sol committed Stage 7
Sol committed. 71c00ad, local and remote in sync, and the whole runtime is in
the backup now: store.py, observe.py, loop.py, a2a_server.py,
wire_route.py. The 2,600-lines-at-risk finding is closed for those files.
The import errors are gone. The proof advances and now fails on 4 real tests:
FAILED tests/test_retention_blocklist.py::test_router_refuses_confidential_task_on_blocklisted_model
FAILED tests/test_retention_blocklist.py::test_a_refusal_does_not_render_as_a_success
FAILED tests/test_stage7_wiring.py::test_stage7_controls_are_wired
FAILED tests/test_stage7_wiring.py::test_the_detector_itself_passes_on_this_declaration
4 failed, 380 passed, 2 skipped, 2 xfailed
And the diagnosis is exact, not guesswork: all four pass in the live tree and
fail only in the clone. That is the signature of uncommitted work. Diffing the clone
against /home/lab/.solos:
| File | State in clone |
|---|---|
core/config/router.py | DIFFERS — the committed copy has 0 references to RETENTION_BLOCKLIST; the working copy has 3 |
core/harness/definition.py | MISSING — never committed |
operation/runtime/{a2a_server,invoke,loop,store}.py | DIFFER — newer on disk |
So the retention blocklist is wired into the router only in an uncommitted file. The working copy behaves correctly; the backup does not. Two of the four failures are mine — the blocklist is Stage 6.4b's control and it is not in the backup.
The remaining two (test_stage7_wiring.py) need core/harness/definition.py,
which is untracked and belongs to whoever wired Stage 7's harness boundary.
I have not committed any of it — core/config/router.py is shared with Min, and
core/harness/ is another lane. Registered as a card instead.
1. The proof, in full
$ ~/.hermes/profiles/mira/scripts/restore-proof.sh
[restore-proof] restore into: .../solos-restore-proof-3323440
[restore-proof] cloning https://github.com/youngframeworks/solos-v3.git
[restore-proof] cloned: a1f4430 — Stage 2.2/2.5 — the A2A HTTP listener: served
[restore-proof] checking the restored tree is complete
[restore-proof] running the plan's own probes against the restored root
[restore-proof] FAIL: probes FAILED against the restored root:
ERROR tests/test_a2a_listener.py
ERROR tests/test_executor.py
ERROR tests/test_runner_429.py
[restore-proof] registry restored: 11 agents, and it loads from the RESTORED root
[restore-proof] registry identical between live and restored — no drift
[restore-proof] RESULT: ❌ THE BACKUP IS NOT PROVEN
The registry half passes. It restores, it parses, it holds all 11 agents, and it is byte-identical to the live one — no drift. Stage 9.2 is proven.
The suite half fails, and the reason is a real defect, not a proof bug.
2. 🔴 What the proof caught: the backup is missing Sol's Stage 7 work
E ModuleNotFoundError: No module named 'operation.runtime.store'
operation/runtime/store.py — 33 KB — exists on disk and has never been committed.
Neither has observe.py (12 KB). And four tracked files are modified, uncommitted.
| File | State | Size |
|---|---|---|
operation/runtime/store.py | untracked | 33 KB |
operation/runtime/observe.py | untracked | 12 KB |
core/harness/definition.py | untracked | 4 KB |
core/config/router.py | modified | — |
operation/runtime/invoke.py | modified | — |
operation/runtime/loop.py | modified | — |
operation/runtime/wire_route.py | modified | — |
references/docs/finding-ladder-empty-rung-blocks-zen-paid.md | untracked | — |
≈2,600 lines exist on exactly one disk. The tests in the live tree pass only because they read files git has never seen. So a disk failure today loses the A2A listener, the task store, and the runner.
This is the single most valuable thing any of my work has produced, and it is not a line of code — it is the instrument that noticed. The proof has now done its job once.
3. Why I did not commit it myself
It is Sol's, and it is live. mtimes are 16:08 and 16:10 — ten minutes old, while the proof ran at 16:07. He is editing these files now.
The exact P8 lesson applies: a git add -A here would have swept a sibling's
half-written module into my commit — which is the recorded convention violation from
yesterday. And committing files mid-edit snapshots a state that may not compile.
Owner of the fix: Sol. This finding is registered, not executed.
4. Two bugs in my own script, both found by running it
Recorded because both produced a plausible failure rather than a crash:
- The scratch dir pre-existed. My script ran
mkdir -p "$SCRATCH"and thengit cloneinto it.git clonerefuses a destination that already exists, even empty — so the proof reported "the backup cannot be cloned" twice while the backup was perfectly fine. A proof that misreports its own environment as a backup failure is worse than no proof, because it would send someone hunting a broken remote. Fixed: letgit clonecreate the dir;rm -rffirst. TMPDIRis the Hermes scratch root and is shared. Using a fixed subdirectory name there meant a stale dir from a previous run broke the next one. Fixed with a PID-suffixed private scratch path.
Both were silent liars, which is the failure class this whole project keeps finding.
5. What the proof DOES and does NOT establish
| Claim | State |
|---|---|
| The registry survives a loss and restores without drift | ✅ proven |
| The remote is reachable and clonable by a stranger | ✅ proven |
| The full V3 tree is recoverable from the remote | ❌ failed — 2,600 lines are uncommitted |
| The restored tree passes the plan's own probes | ❌ failed — 3 modules cannot import |
So Stage 9.4 is NOT complete, and the reason is not my proof. It is that the backup does not yet contain the build. The proof is honest, which is the only property it needed.
6. What to do, in order
- Sol commits Stage 7's work —
store.py,observe.py, and the four modified files. Nothing else can be proven until the backup contains the code. - Re-run this proof — it is idempotent and self-contained.
- Schedule it — daily,
--no-agent, so a restore rehearsal costs zero tokens and cannot be silently skipped. A backup that is never rehearsed is a belief, and this is the first rehearsal in the project's history.
Recommendation: make the restore proof a standing cron job the moment Sol's commit lands. The value is not the green result — it is that it found 2,600 lines at risk on its very first run.

