I read this as a read-only release-gate audit - I’ll trace the sealed candidate, bootstrap-to-launcher path, authority/registry/recovery contracts, and rehearsal identity, then return an evidence-backed PASS or FAIL without executing any live path.


I read this as a final release-gate decision - I audited the sealed bytes and control flow without invoking the live path and am returning the evidence-backed verdict.

# FAIL

Candidate `a88071d999155e52433c00891b2886f8867fe80ae749936fa1b6688eec123cf8` is internally immutable and correctly bound, but V14 r10 is not release-safe because its executable preseal closure is mutable, one sealed recovery input is not verified, and pre-snapshot interruption recovery is incomplete.

## Gate results

| Gate | Result | Exact evidence |
|---|---|---|
| Candidate immutability | PASS | Candidate has exactly 324 expected files. All 322 inventory rows matched SHA-256, had no write bits, and had link count 1. Recomputed derivation equals the claimed candidate digest. Manifest SHA-256 is `e6605df2510f46af8267a1fae250aa7762b12b9e4d198a19299610cb7d621832`. |
| Launcher reachability | PASS structurally, FAIL integrity | Launcher hash `dfffb7b8...` matches worktree and preseal. It enters r10 bootstrap, which execs the worker, which imports `execute_authorized`. However, mutable unmanifested bytecode can be imported after verification. |
| One-use authority | FAIL end-to-end | `GlobalLedger.reserve()` correctly uses `O_EXCL`, and the live ledger/execution/successor paths are currently absent. But process death before snapshot creation leaves states the recovery algorithm cannot close. |
| Registry binding | PASS | Current registry SHA-256 is exactly `bd61ed95f80737ba8013db262fd0242a600e540f43f6627f5b9708a599660b29`; shape is two customers with only `pilot_20260820_01` enabled. Package shape digest recomputes to bound value `bb911adc...`. |
| Recovery boundaries | FAIL | `PREPARING` and no-phase interruption windows are unrecoverable; rehearsal rollback evidence is left in `PREPARING`, not `ROLLED_BACK`. |
| Controller/launcher target agreement | PASS | Launcher, bootstrap, worker, controller `SEALED_TARGET`, transaction plan, target binding, candidate, package, and successor runtime all resolve to r10/a88071d9. Controller derivation recomputes to `c4e0d802...`. |
| Rehearsal identity | FAIL as release evidence | Candidate/package/wheels match, but rehearsal calls `execute_disposable` with `DisposableService`, not launcher -> bootstrap -> `execute_authorized`; all 12 rollback cases report PASS while their durable phases are `PREPARING`. |

## Release blockers

### 1. The verified controller closure contains mutable, unmanifested executable bytecode

Preseal inventory verification found all 326 declared rows correct, but the directory contains 343 regular files versus 327 expected including the self-excluded manifest: **16 undeclared `.pyc` files**.

Examples:

- `controller-source/scripts/__pycache__/nutricoach_v150_sealed_controller.cpython-312.pyc`
- `controller-source/scripts/__pycache__/nutricoach_v150_detached_bootstrap.cpython-312.pyc`
- `controller-source/scripts/__pycache__/nutricoach_v150_sealed_authority.cpython-312.pyc`

They are mode `0644`; their parent directories are mode `0775`. None appear in either package or controller-source manifests.

The sealed-controller bytecode header is timestamp-based:

- flags: `00000000`
- embedded source timestamp: `0x6a919e0a` = source mtime `1787928074`
- embedded source size: `0x2516` = `9494`

Those values exactly match `nutricoach_v150_sealed_controller.py`, making this bytecode import-eligible. Bootstrap verifies listed source files at `nutricoach_v150_detached_bootstrap.py:145-147`, then the worker imports the controller at `nutricoach_v150_controller_worker.py:11`. The mutable bytecode itself is never hashed.

### 2. The protected inventory is writable and its sealed digest is unused

`preflight-v14-live-representative-r10/snapshot-before.json` is mode `0600`, owner `cube`, and resides under the migration tree mounted writable by launcher lines 42-44.

Its current digest does match the declared value:

`d2c084be0865f8e9844452a7b683f97800e31af9bc7e1a113241109a283aada5`

But `protected_inventory_sha256` has **zero source-code references**. The live host loads only its path (`nutricoach_v150_concrete_host.py:156-166`), and `protected_paths()` dynamically trusts its `profiles.stable` rows (`nutricoach_v150_host_operations.py:42-65`). The preseal verifier checks the permission-package hash but never hashes this inventory (`verify_nutricoach_v150_preseal_v14.py:198-217`).

Consequently, the catalog of 86,756 protected `dualcoachtest` stable paths can change without bootstrap or preseal denial.

### 3. Recovery does not cover the pre-snapshot interruption window

Controller ordering is:

1. Write recovery manifest: `sealed_controller.py:169`
2. Write phase `PREPARING`: line 171
3. Reserve authority: line 174
4. Create snapshot: line 182

Recovery loads a snapshot for every pending phase except `STOPPING` and `RESERVED` (`sealed_controller.py:209-220`).

Therefore:

- Death after recovery-manifest creation but before phase creation leaves an execution root with no recoverable phase; subsequent preseal verification rejects `authority_touched`.
- Death in `PREPARING`, including during reservation, calls `load_snapshot()` even though no snapshot exists yet.

The rehearsal artifacts expose the same state inconsistency:

- All 12 rollback cases are reported `PASS`.
- Every durable rollback phase is `PREPARING`.
- Every ledger is `CONSUMED:FAILED`.
- `rollback-stop` has no snapshot at all.
- `PhaseJournal.recovery_required()` explicitly treats `PREPARING` as pending.

Report SHA-256: `c698d2a19904d776e9bfbe11a835cd4f68bf42a16f7e1207d5b022aa4eff8404`.

## Architecture decision

Two viable corrections:

1. **Harden the existing design**
   - Reject unmanifested files, remove bytecode, run with `-B`/`PYTHONDONTWRITEBYTECODE`, and make preseal directories read-only.
   - Verify every external sealed digest before use.
   - Add explicit pre-snapshot recovery states and terminal-state rehearsal assertions.
   - Lowest migration cost and preserves current test seams.

2. **Package the controller as one content-addressed executable artifact**
   - Launcher verifies and runs a single read-only zipapp/wheel-like closure.
   - Smaller import attack surface, but higher packaging migration cost and tighter build/debug coupling.

**Recommendation: option 1.** It is the smallest architecture that closes the actual failures; a new packaging framework is not justified.

No authorization, live execution, network, Telegram, provider, customer, service, commit, or push action was run. No audited file was modified.