# Owner-Isolated Diagnostic Mode — Revision 26

## Status
Planning only. Supersedes Stage 25 in full.

## Decision summary
Implement an owner-authenticated, 60-minute maximum, current-boot diagnostic session that hot-attaches one marked isolated registry to the already-running ordinary gateway. Ordinary same-user/distinct-full-triple identity records remain legal and unchanged; only diagnostic authority, synthetic replay, isolated enabled-customer visibility and production exclusion require the session.

## Principles and options
Principles: no diagnostic inference; no production reach; bounded/read-only evidence; synthetic replay only; deployable changes exclude runtime state. Drivers: solo-owner usability, security isolation, deterministic incident handling. Chosen option is a Topic-59-authenticated hot-attached diagnostic runtime. Permanent master authority is rejected as unsafe; mandatory three accounts remains optional but is not required.

## 1. Non-ambient bootstrap and gateway admission

### Bootstrap authority
The existing running ordinary gateway and `AdaptiveOperatorService` remain the only ingress. Add explicit typed actions `diagnostic_prepare`, `diagnostic_activate`, `diagnostic_revalidate`, `diagnostic_close`; no natural-language parser and no config-only enablement.

A request enters only through the configured Topic-59 review triple and existing persisted callback/session mechanism. `AdaptiveOperatorService` refreshes the canonical owner and all live pins, then issues a one-use `DiagnosticBootstrapCapability` containing: schema/version, action, opaque capability ID/nonce digest, authenticated review triple/version digest, canonical owner triple/version digest, isolated profile digest, requested disposable-customer digest, test-bot digest, three role-destination digests, issue/expiry KST, gateway boot epoch, config/registry/consent/activation/artifact digests, predecessor and row digest. Maximum capability lifetime is 10 minutes. Raw triples/local CLI/config cannot mint it.

### Loader selection
`TelegramAdapter` starts only the ordinary coordinator. After authenticated `diagnostic_activate`, `AdaptiveOperatorService` passes the consumed bootstrap capability directly in memory to `NutritionCoachingCoordinator.attach_diagnostic_runtime(capability)`. That method calls `load_diagnostic_runtime_customer_registry`; no startup discovery/config/profile scanning can choose it. The hot-attached coordinator is keyed by diagnostic session digest and exact role destinations. Close/expiry/restart detaches it before disabling state. `nutrition_coaching_config.py` may define closed schema defaults but never contains an enable switch or authority.

### Private DM
Diagnostic mode disables legacy trainer private-DM inference. Only an exact pinned trainer `(chat_id, topic_id)` and active diagnostic role capability is accepted. Wrong DM text/callback/active binding terminates with zero downstream/provider work.

## 2. Distinct marked registry and ordinary-loader rejection

Add closed fields to the registry document schema: `registry_mode: ordinary_v1|diagnostic_isolated_v1` and optional `diagnostic_session_digest`. Existing documents default/migrate in memory to `ordinary_v1` without byte rewrite. Ordinary `load_runtime_customer_registry` and `load_committed_customer_registry` reject `diagnostic_isolated_v1`. Only `load_diagnostic_runtime_customer_registry(root, capability)` accepts it after current session/boot/spec validation.

The isolated profile has a physically separate private root and registry. During active diagnostics its one disposable customer is enabled so existing enabled-only workflow code can run. Production profile/registry is never modified. Production gateway cannot consume the marked registry even if misconfigured to its path.

Targets include `customer_coaching.py`, `customer_admin.py`, gateway constructor/service paths and exact registry domain tests.

## 3. Crash-recoverable activation/cleanup protocol

Create `checkin_cli/diagnostic_isolation.py` with append-only `data/diagnostic-isolation.jsonl` and `data/diagnostic-transitions.jsonl`. States: `prepared`, `activating`, `active`, `restart_unvalidated`, and terminal `expired|revoked|closed|recovery_required`. TTL max 60 minutes, exclusive expiry. Every transition validates schema/predecessor/digest under `profile_authority_lock`.

Atomic protocol under the authority lock:
1. append/fsync `transition_prepared` with intent, before-registry digest/bytes digest, disabled customer digest, target marked-registry digest, session/spec/boot digest;
2. atomically replace+fsync the isolated registry with marked diagnostic registry and enabled disposable customer;
3. append/fsync active session row;
4. append/fsync `transition_committed`.

Terminal cleanup reverses order safely: prepare cleanup intent with active registry digest and disabled target digest; detach gateway runtime; atomically replace+fsync registry to marked-but-disabled state; append terminal session; commit transition. It never touches production registry.

Recovery runs at gateway startup before any diagnostic attachment and on a 30-second host tick:
- prepared + registry-before => append abandoned, keep disabled;
- prepared + registry-target + missing active/commit => replace disabled registry, append `recovery_required`, provider zero;
- active from prior boot => detach, mark `restart_unvalidated`, disable registry; explicit Topic-59 `diagnostic_revalidate` creates a fresh current-boot activation transaction;
- expired active => detach, disable, append expired;
- cleanup partial => complete disable idempotently, terminalize; ambiguous digest => `recovery_required`, no attach/provider.

Every request and pre-provider boundary independently checks current time/session/boot/marked registry, so expiry is safe even if the tick is delayed.

## 4. Exact session APIs and state outcomes

Profile APIs: `prepare_diagnostic_isolation`, `activate_diagnostic_isolation`, `revalidate_diagnostic_isolation_after_restart`, `revoke_diagnostic_isolation`, `close_diagnostic_isolation`, `recover_diagnostic_isolation`, `load_active_diagnostic_isolation`.

Outcome matrix:
- no session/prepared: no diagnostic routes, zero lifecycle/provider rows;
- active current boot: exact three routes, operations allowed by capability;
- expired/revoked/closed/recovery_required: no routes, zero new lifecycle/provider rows;
- restart_unvalidated: no routes until fresh revalidation;
- stale/wrong action/owner/profile/customer/bot/destination/pin: reject before append, zero provider;
- mismatch after delivery reservation: preserve existing linked terminal unknown/provider-zero semantics;
- duplicate mutation: original typed duplicate result, no row/provider delta.

## 5. Preflight closed schema

Preserve ordinary `GateDPreflightReceipt` v1 exactly. Add `DiagnosticPreflightOptions` and `DiagnosticPreflightReceipt` schema `diagnostic_preflight_v1`.

Exact receipt fields: `schema_version`, `ready`, `reason_codes`, `checked_at_kst`, `epoch`, `checks`, `counts`, `digests`.

Exact checks: `owner_authenticated`, `same_owner_user`, `full_triples_distinct`, `destinations_distinct`, `review_space_disjoint`, `profile_isolated`, `data_root_private`, `disposable_customer_only`, `test_bot_separate`, `production_routes_absent`, `registry_marked`, `session_state_valid`, `boot_epoch_current`, `ttl_valid`, `customer_state_valid`, `feature_flags_safe`, `plan_window_current`, `schedule_fence_ready`, `artifacts_current`, `consent_current`, `activation_current`, `source_reconciled`, `reservation_baseline_clean`.

Exact counts: `customers`, `role_destinations`, `production_routes`, `reservations`, `schedule_rows`, `schedule_tombstones`, `artifact_kinds`, `session_rows`, `transition_rows`.

Exact digest keys: `owner`, `review_config`, `profile`, `registry`, `session`, `spec`, `test_bot`, `operator_destination`, `customer_destination`, `trainer_destination`, `registration`, `policy`, `catalog`, `constraints`, `source`, `consent`, `activation`, `feature_epoch`, `schedule_fence`.

Bounded reasons: `owner_invalid`, `identity_invalid`, `destination_collision`, `review_collision`, `profile_not_isolated`, `permissions_invalid`, `customer_invalid`, `test_bot_invalid`, `production_route_visible`, `registry_invalid`, `session_missing`, `session_stale`, `restart_revalidation_required`, `ttl_invalid`, `feature_flags_unsafe`, `plan_window_stale`, `schedule_invalid`, `artifact_invalid`, `consent_invalid`, `activation_invalid`, `source_invalid`, `reservation_not_clean`, `corrupt_state`.

The API is byte-for-byte read-only and exposes no raw identifier/path/text/token.

## 6. Coherent read-only incident snapshots

Add `profile_authority_read_lock` that requires the pre-existing 0600 authority lock and opens it read-only/shared without mkdir/create/chmod/write. Snapshot export additionally uses optimistic multi-ledger revision fencing, not an impossible global lock:
1. record canonical size/terminal row digest for every incident source ledger;
2. read bounded required rows through each ledger's existing validator/read lock;
3. record the same revisions again;
4. accept only if all match; otherwise retry up to 3 times then return `snapshot_unstable` without output.

No-mutation tests compare recursive file names, contents, modes, mtimes and sizes; atime is explicitly excluded because reads may update it.

Incident map:
- `incomplete_checkin`: wizard session/event ledger; bounded completed-step bitmap, expected no finalized event; fingerprint branch/state/provider=0.
- `low_adherence`: canonical observations + registration/policy; bounded adherence category/count window; fingerprint decision/operator-only/provider=0.
- `safety_hold`: canonical safety events; bounded reason enum/presence; fingerprint human-review/provider=0.
- `kst_rollover`: wizard/schedule/plan; two KST dates and logical clock boundary; fingerprint exactly one target day.
- `stale_callback|duplicate_callback`: operator session ledger + lifecycle; callback state/action/revision relation; fingerprint reject/duplicate and row/provider delta 0.
- `authority_change`: registry/consent/activation/config/session ledgers; mutation point enum and before/after digests; fingerprint no unauthorized append/provider.
- `provider_timeout_unknown|receipt_audit_pending`: delivery ledger; reservation/receipt/audit booleans and logical interruption point; fingerprint unknown or reconcile-with-provider-0.
- `reservation_race`: schedule/adaptive ledger; contender count bucket and barrier point enum; fingerprint one winner/provider=1.
- `disable_restart`: diagnostic/session/config/schedule ledgers; boot/disable relation; fingerprint detached/disabled/provider=0.

`DiagnosticAuditSnapshot` contains only generated opaque IDs, incident class, KST bounds, normalized state sequence, these bounded inputs/concurrency markers, revision/epoch/digests, booleans/counts and expected fingerprint. Export requires a fresh current-boot owner diagnostic capability. Unsupported/stale/unstable/forged requests create no file.

## 7. Synthetic replay enforcement

`materialize_diagnostic_replay` accepts only the strict snapshot and a digest-bound `DiagnosticReplayMapping`, writes only under the isolated root, rebases KST explicitly, and emits synthetic events with `provenance=diagnostic_synthetic_v1`.

Named enforcement targets:
- profile `models.py`: closed provenance enum/tag;
- `store.py`, `wizard_storage.py`/`wizard.py`, `adaptive_nutrition.py`, `customer_schedule.py`: ordinary loaders reject synthetic provenance; diagnostic replay loaders accept only with active session capability;
- `customer_coaching.py`: diagnostic registry/runtime gate;
- gateway `nutrition_coaching.py`/`telegram.py`: diagnostic context required for synthetic projections.

Materialize only the ledgers named in the incident map. Never copy source capabilities, operational row digests, approvals, destinations, receipt contents or customer text. Verify source expected fingerprint equals replay outcome fingerprint for the incident class.

## 8. Promotion manifest exact boundary

`build_diagnostic_promotion_manifest` is read-only and never deploys. Trust roots: profile source workspace and Hermes repository only. Allow repository-relative `.py`, test files, canonical docs, explicit migration source files, and code-side definitions for these schema keys only: `diagnostic_isolation.schema_version`, `max_ttl_minutes`, `allowed_incident_classes`, `require_disposable_customer`, `require_distinct_destinations`, `require_separate_test_bot`, `restart_requires_revalidation`.

Reject runtime config values, destinations/IDs, `.env`, auth/token/secret files, symlinks, traversal, customer/profile data, ledgers, snapshots, replay fixtures, capabilities, messages and generated artifacts. Manifest records file hashes, verification artifact references, required owner approval, health checks and rollback commands; deployment remains human-owned.

## 9. Files and sequencing

Profile: new `diagnostic_isolation.py`; `customer_admin.py`, `customer_coaching.py`, `models.py`, `store.py`, `wizard.py`, `wizard_storage.py`, `adaptive_nutrition.py`, `customer_schedule.py`, `__init__.py`; tests `test_customer_admin.py`, `test_customer_coaching_domain.py`, `test_customer_schedule.py`, `test_adaptive_nutrition.py`, and a new `test_diagnostic_isolation.py` for focused contracts.

Gateway: `nutrition_coaching_config.py`, `nutrition_coaching.py`, `telegram.py`; tests `test_adaptive_nutrition.py`, `test_nutrition_coaching.py`, `test_telegram_group_gating.py`, `test_telegram_physique_checkin.py`.

Docs: canonical profile `PILOT_RUNBOOK.md`, then hash-aligned pointer/HANDOFF/Korean guide/report only where affected.

One validation-coupled Ultragoal story; mandatory parallel executors by profile state/runtime, gateway bootstrap/routes, snapshot/replay/promotion, and tests/docs. Integrate before a single cleaner + verification + Architect + QA/red-team + terminal Critic gate.

## 10. Verification

Unit: transition/recovery crash points; TTL boundaries; boot fencing; ledger corruption; v1 ordinary receipt unchanged; exact diagnostic schema/reasons; ordinary loader rejects marked registry/synthetic provenance; promotion allowlist; full-tree non-mutation excluding atime.

Integration: Topic-59 bootstrap → hot attach → exact one disposable customer; config/auto-discovery cannot attach; same user at three distinct destinations; private-DM and wrong-route all-ingress provider zero; expiry tick/restart/owner/config/customer/bot/route mutations detach and disable; every partial activation/cleanup recovers fail closed.

Replay: every incident class sources exact ledgers, retries unstable reads, materializes only synthetic bounded rows and proves fingerprint equivalence.

E2E/red-team: all ingress kinds; stale/forwarded/duplicate callbacks; KST rollover; incomplete/low-adherence/safety; unknown/audit pending; thread/subprocess races; disable/restart. P2→P6 automated isolated fixture proves existing at-most-once/audited-only semantics and final flags false, delivery revoked, overlay rollback, disposable customer disabled, session closed and processes stopped. Actual Telegram/account/token/manual P2→P6/real deployment remain human-only.

Observability is typed return/local non-sensitive logs/metrics only; no Telegram diagnostic UI beyond explicit authenticated actions.

## Acceptance criteria
1. Ordinary loaders, same-user/distinct-full-triple legality and v1 preflight remain unchanged.
2. Diagnostic workflows and marked registry visibility—not identity sharing itself—require a current-boot active session and consumed owner-authenticated bootstrap capability.
3. Config alone, automatic discovery, ordinary loader, private DM or production capability can never attach diagnostics.
4. Every crash point converges to attached+active or detached+disabled; ambiguous state is recovery_required/provider zero.
5. Snapshot is coherent by revision fence, non-mutating, bounded and authorized; replay is synthetic and fingerprint-equivalent.
6. Promotion manifest contains only allowlisted reviewed changes and does not deploy.
7. Profile full/focused gateway tests and compile checks pass; unrelated failures are reported.
8. Cleaner zero blockers, Architect CLEAR/APPROVE, executor QA/red-team passed and terminal Critic OKAY.
9. Live Telegram, credentials, manual P2→P6 and real-customer deployment remain human-only.

## Intent reconciliation
The prior solo setup is valid because roles use distinct full triples/destinations even when one user owns them. The implementation adds safe diagnostic admission and isolation rather than changing ordinary identity semantics. Problems are reported and fixes requested in this development session; no natural-language Telegram diagnostic UI is added.

## ADR
Decision: Topic-59-authenticated hot-attached diagnostic runtime with marked registry, crash journal, current-boot fencing, coherent bounded snapshots, synthetic replay and allowlisted promotion manifest. Rejected: permanent master bypass and universal three-account requirement. Consequence: broader implementation/test surface, but no ordinary authorization weakening. Human owns live rehearsal and deployment.

# Revision 27 Binding Addendum
This addendum is normative and resolves every Stage-26 ambiguity; Revision 26 remains in force where not replaced below.

## A. Topology: separate dormant diagnostic gateway process
Replace “hot-attach to the ordinary gateway” with a **separate diagnostic gateway process/TelegramAdapter using the existing test bot and isolated profile**. It reuses production gateway code but has a distinct process, profile root, config file, bot token environment and route table. The production gateway is never modified or dynamically attached.

Why chosen: strongest bot/root/process isolation and simpler crash semantics. Rejected hot attachment because one adapter owns one bot and cross-root dynamic routes are ambiguous. Rejected a bespoke second implementation because it would drift from production behavior.

The diagnostic process starts dormant: only the authenticated test Topic-59 review route exists. It cannot expose customer/trainer/lifecycle/provider routes until an owner-authenticated diagnostic activation succeeds. Config locates resources but never authorizes activation.

## B. Closed spec and bootstrap data path
Store exactly one owner-approved private file at `<isolated_root>/config/diagnostic-isolation.json` (regular file, mode 0600, parent modes private, no symlinks). Closed `DiagnosticIsolationSpecV1` fields:
- `schema_version="diagnostic_isolation_spec_v1"`
- `spec_id` opaque UUID
- `authority_profile_root` canonical absolute path
- `isolated_profile_root` canonical absolute path
- `registry_relpath="customers/registry.json"`
- `disposable_customer_key` (internal only)
- `review_operator`, `operator_destination`, `customer_destination`, `trainer_destination` full triples (internal only)
- `test_bot_account_id`, `production_bot_account_digest`
- `allowed_incident_classes` exact enum tuple
- `max_ttl_minutes` integer 1..60
- `approved_by` full canonical owner triple, `approved_at_kst`
- `supersedes_digest`, `spec_digest`, `authority_digest`.

The diagnostic config contains only `diagnostic_spec_path` relative to the isolated root and the authority root path. On startup `DiagnosticHost.__init__` resolves both roots with `Path.resolve(strict=True)`, verifies allowed configured parent roots, privacy/modes/symlinks, exact spec digest/owner authority, and the dormant adapter’s authenticated bot account ID (live `get_me` only during human-run startup; tests inject a typed identity) against `test_bot_account_id`. It compares the separately owner-approved production bot account digest without reading a production token. A mismatch stops startup. No scan, caller path or alternate spec is accepted.

Topic-59 shows only the exact authenticated `diagnostic_prepare` action for this sole spec. `AdaptiveOperatorService` mints the bootstrap capability from the already-loaded verified spec plus refreshed authority; the capability contains the spec digest, not paths. `DiagnosticHost.activate(capability)` is the only loader branch. Config/spec can locate data but cannot activate without the consumed Topic-59 capability.

`operator_destination` is the configured Topic-59 review triple. Customer and trainer destinations are two other pairwise-distinct test spaces; there is no fourth operator space.

## C. Root ownership, locks and final revalidation
`authority_profile_root` owns canonical owner/config approval and the read-only incident export request ledger. `isolated_profile_root` owns diagnostic spec, session, transition, registry, replay and test state.

Any operation touching both uses resolved-path lexical lock order via `multi_profile_authority_lock((authority_root, isolated_root))`, deduplicated and non-reentrant across roots. Writes acquire exclusive locks; read snapshots use read locks/revision fences. Immediately before session/registry append and again before any provider reservation/call, reload and compare authority owner/version, spec digest, bot identity, registry/session/boot and all lifecycle pins. Concurrent change => no attach/append/provider before reservation; existing terminal linked behavior after reservation.

Gateway boot epoch is `secrets.token_hex(32)` generated once in `DiagnosticHost.__init__`, never persisted as reusable authority, injected into every profile session API and capability, and exposed to tests through an explicit constructor parameter. Persisted rows store its digest. A new process therefore makes prior active rows `restart_unvalidated`.

## D. Exact runtime ownership
Add `DiagnosticHost` in gateway `nutrition_coaching.py` (or a narrowly named sibling module if file size requires) owning:
- `_boot_epoch`, `_verified_spec`, `_diagnostic_session`, `_child_coordinator`, `_role_routes`
- `activate(capability)`, `revalidate(capability)`, `detach(reason)`, `recover_startup()`, `_expiry_loop()`, `start()`, `stop()`.

Startup order: verify dormant spec/bot → recover profile transitions and force old sessions disabled → register only Topic-59 diagnostic control route → start 30-second expiry task. Activation transaction commits profile active state before installing child routes; if route installation fails, detach and run cleanup transaction. Route collision rejects before profile activation. Attach is idempotent by session digest. Detach atomically removes role routes under adapter route lock before isolated registry disable/terminal append. A crash after profile active but before route install is recovered as disabled/restart_unvalidated on next startup; a crash after route removal but before disable is likewise completed on startup. `stop()` cancels/awaits expiry task, removes routes, disables/terminalizes, then closes the adapter. Exceptions leave routes absent and `recovery_required`.

## E. Snapshot source authority and exact revision tokens
Future production incident evidence is exported **in the source process/root**, never by the isolated process reading production directly. Add Topic-59 action `diagnostic_audit_export` to the source gateway. It mints a one-use `DiagnosticAuditCapability` bound to source profile/customer/incident/window/owner/live pins and writes only the bounded snapshot to an owner-designated private local artifact directory already configured by the host. The development session may then read that artifact. The isolated diagnostic capability can import only its digest-verified bounded form.

For pre-Gate-D rehearsal, source type is `synthetic_baseline`; no production source root/customer is read.

Revision-fence table:
- wizard/store/schedule/adaptive/operator/delivery JSONL: `(st_dev, st_ino, size, terminal_row_digest)` before/after using each module’s validated reader;
- registry/config/spec/artifact JSON: `(st_dev, st_ino, size, sha256(bytes))` before/after;
- feature epoch/activation/consent/registration: validated canonical document digest plus file tuple;
- directories: sorted `(relative_name, file_tuple)` manifest for only named files.
Any token changes during three retries => `snapshot_unstable`, no artifact. Source capability permits exactly one source customer; snapshot excludes its raw key.

Exact source paths are resolved through existing APIs, not arbitrary paths:
- incomplete/KST: `WizardStorage` drafts/events plus canonical `store.py` events;
- low-adherence/safety: canonical events through `AdaptiveEventStore` plus approved registration/policy;
- callback/authority: adaptive operator session ledger plus canonical registry/consent/activation/config readers;
- provider/audit/reservation: `AdaptiveEventStore` journals and customer schedule validated ledger APIs;
- disable/restart: diagnostic session/config/schedule readers.

`DiagnosticReplayMappingV1` lives at `<isolated_root>/data/diagnostic-replay-mappings/<snapshot_digest>.json`, mode 0600, and contains schema, snapshot digest, disposable customer digest, role destination digests, KST rebase date, approved owner capability digest/time, mapping digest. It stores no source IDs. Replay entrypoint is `run_diagnostic_replay(snapshot, mapping, host)` and returns the incident fingerprint; only a current active diagnostic host accepts synthetic provenance.

## F. Fixed promotion roots and migrations
Root derivation is compiled/host-owned, not caller supplied:
- profile source root: `Path(checkin_cli.__file__).resolve().parent.parent`
- Hermes root: walk parents from `gateway.platforms.nutrition_coaching.__file__` until exact package markers `gateway/` and `tests/gateway/` exist; require canonical expected repository identity recorded in the promotion policy.

Migration allowlist is empty for v1 unless a plan amendment names an exact repository-relative migration file. Thus the first implementation may promote code/tests/docs and the seven listed config-schema definitions only; no migration artifact is automatically allowed.

## G. Exact verification and row terminology
Profile commands, cwd `/home/cube/.hermes/profiles/physique-coach/workspace/checkin_cli`:
- `.venv/bin/python -m pytest -q`
- `.venv/bin/python -m compileall -q checkin_cli`

Gateway cwd `/home/cube/projects/richard/hermes-agent`:
- mandatory focused: `.venv/bin/python -m pytest -q tests/gateway/test_adaptive_nutrition.py tests/gateway/test_nutrition_coaching.py tests/gateway/test_telegram_physique_checkin.py tests/gateway/test_telegram_group_gating.py`
- `.venv/bin/python -m py_compile gateway/platforms/nutrition_coaching.py gateway/platforms/telegram.py gateway/platforms/nutrition_coaching_config.py`
- full `tests/gateway` is run and reported; pre-existing unrelated failures do not silently pass or expand this feature scope, while any changed-surface failure blocks completion.
- docs/hash/link tests and `/tmp` API/algorithm test report are mandatory.
- no network/live Telegram; tests inject bot identity/provider.

Row deltas distinguish `diagnostic_session_rows`, `diagnostic_transition_rows`, `nutrition_lifecycle_rows`, `delivery_rows`, `schedule_rows`, and `provider_calls`:
- prepared: +1 session, no routes/lifecycle/delivery/provider;
- active: prepared/committed transition plus active session, exactly 3 role routes, no nutrition/delivery/provider until action;
- restart_unvalidated/terminal/recovery: cleanup transition+state permitted, routes 0, nutrition/delivery/provider 0;
- stale/wrong/expired capability: all row classes 0 except an optional bounded rejection audit row explicitly excluded from authority, provider 0;
- duplicate: no row/provider delta;
- post-reservation authority loss: existing delivery terminal row only, provider 0;
- recovery: diagnostic transition/session rows only, all product/provider rows 0.

Expected preflight state reasons: prepared=`customer_state_invalid`; prior boot=`restart_revalidation_required`; expired=`session_stale`; terminal=`session_missing`; corrupt=`corrupt_state`; active clean has no reasons.

## H. Parallel ownership
Sequence load-bearing interfaces:
1. Profile-state executor exclusively owns new `diagnostic_isolation.py`, `customer_admin.py`, `customer_coaching.py`, `__init__.py` and publishes typed contracts.
2. After that contract lands, snapshot/replay executor owns a new `diagnostic_evidence.py` plus provenance loader edits; it does not edit `diagnostic_isolation.py`.
3. Gateway executor consumes the finished profile contract.
4. Tests/docs can parallelize only over disjoint files after APIs stabilize. Leader owns integration and all verification.
