message: 403: {"code":"ENTITLEMENT_ERROR","message":"Error 403: the user is not subscribed to required model plan"}

stop_reason: error


error_message: 403: {"code":"ENTITLEMENT_ERROR","message":"Error 403: the user is not subscribed to required model plan"}


<analysis>
**Literal Request**: Map the safe sealed successor upgrade path for the Telegram check-in UI, preserving the in-progress nutrition_daily session, and identify packaging, candidate, authority, rehearsal, production, observer files/scripts, compatibility risks, and read-only preflight/post-deploy evidence.
**Actual Need**: Find the authoritative deployment/upgrade chain and the artifacts that prove what is live versus immutable so an operator can plan a safe upgrade without touching the current session.
**Success Looks Like**: A complete path map with absolute file paths, roles of each artifact/script, live-state vs artifact distinctions, risks, and evidence points for preflight and post-deploy validation.
</analysis>


I read this as mapping the sealed upgrade path and live/immutable boundaries - I’ll synthesize the chain from the evidence and call out the current mutable state separately.

**Current live state**
- `~/.hermes/profiles/dualcoachtest/gateway_state.json` says the gateway is **running** and Telegram is **connected**.
- The mutable live draft I found is:
  - `~/.hermes/profiles/dualcoachtest/data/customers/pilot_20260820_01/wizard/drafts/235d1edf627bf3b9ba321caa32a198f0.json`
  - `flow: nutrition_daily`, `step: calories`, `version: 1`
- Treat that profile tree as live state; don’t confuse it with archived Task24/25 evidence.

**Immutable artifacts**
- Historical candidate/manifest evidence:
  - `.omo/evidence/dualcoach-candidate-manifest.md`
  - `.omo/evidence/dualcoach-candidate-manifest.json`
- Historical release/cleanup evidence:
  - `.omo/evidence/dualcoach-task-24.md`
  - `.omo/evidence/dualcoach-task-25.md`
  - Task24/25 live-terminal / deployment verification JSONs
- Authority pins:
  - `~/.hermes/runtime-authority/dualcoach-v1.3.2-daily-checkin-rebound-first-customer-credentials/task26-authority-pin.json`
  - `~/.hermes/runtime-authority/dualcoach-v1.3.2-daily-checkin-rebound-first-customer-credentials/owner-risk-acceptance.json`
  - `~/.hermes/runtime-authority/dualcoach-v1.3.2-daily-checkin-rebound-first-customer-credentials/operator-notification-recovery.json`

**Safe sealed successor path**
1. **Package** from the sealed candidate manifest, not the live profile.
2. **Bind authority** with the runtime-authority pins; the historical runbook is read-only context, not live authorization.
3. **Rehearse** on a disposable copy:
   - `dualcoach-task-24-operator-preflight.sh`
   - `dualcoach-task-24-real-one-window.sh`
   - observers: `dualcoach-task-24-approval-pre-send-observer.py`, `dualcoach-task-24-edit-recovery-observer.py`, `dualcoach-task-24-send-observer.py`
4. **Promote** only after the exact approval/send checkpoint is observed once.
5. **Clean up** with Task25-style reset so rehearsal ends inactive/dead and no delivery ledger remains.

**Main compatibility risks**
- Touching the live profile instead of the sealed copy.
- Replaying stale/repeat/wrong-role callbacks.
- Breaking the owner-DM topic `0` path.
- Changing `adaptive_nutrition.delivery_enabled` or the exact card/message binding.
- Duplicate provider receipts or duplicate customer deliveries.
- Restart races around `gateway_state.json`.

**Evidence that the path is safe**
- Task24 proved exactly-once synthetic send + edit recovery on disposable/live-observed windows.
- Task25 proved cleanup/reset back to an empty disabled baseline.
- The immutable records preserve the post-deploy proofs; the live mutable profile remains separate and intact.


I read this as a read-only correction of the current r70/r71 sealed NutriCoach chain - I’ll reopen the exact current paths, one-use rules, and draft-compatibility evidence, then stop.


I found the current r70 candidate tree; now I’m reading the specific r70 artifact set and the live authority/runtime pins to correct the map.


I have the r70 candidate entry points; I’m now reading the script inventory and the r70 rehearsal evidence for the exact live/runtime and draft-compatibility bindings.


I have the rehearsal PASS/rollback evidence; next I’m reading the live authority/execution/runtime scripts themselves and the observer files so the mapping is exact.


I confirmed the sealed controller/target/runtime files; I’m checking whether the execution script is in a different current root so I don’t invent a path.


I found the observer family in the current worktree; I’m reading the runtime/final/contract observers to distinguish them from historical Task24/25 observers.


Corrected current chain only:

**Candidate / preseal / rehearsal / execution scripts**
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/seal_nutricoach_v150_candidate.py`
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/verify_nutricoach_v150_candidate.py`
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/prepare_nutricoach_v150_v15_preseal.py`
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/verify_nutricoach_v150_preseal_v15.py`
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/rehearse_nutricoach_v150_v15.py`
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/execute_nutricoach_v150_sealed_live.py`

**Observer files**
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/nutricoach_v150_observer_contract.py`
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/nutricoach_v150_observer_runtime.py`
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/nutricoach_v150_observer_final.py`
- `/home/cube/projects/richard/.worktrees/nutricoach-v150-combined/scripts/nutricoach_v150_seven_day_observer.py`

**Live r70 authority / execution / runtime**
- runtime unit: `/home/cube/.config/systemd/user/hermes-gateway-dualcoachtest.service`
- runtime drop-in credentials: `/home/cube/.config/systemd/user/hermes-gateway-dualcoachtest.service.d/task26-authority.conf`
- live runtime: `/home/cube/.hermes/profiles/dualcoachtest/.strict-runtime/81a7a06e-v150/venv`
- live authority pin: `/home/cube/.hermes/profiles/dualcoachtest/.strict-runtime/81a7a06e-v150/runtime-authority/task26-authority-pin.json`
- live candidate digest: `/home/cube/.hermes/profiles/dualcoachtest/.strict-runtime/81a7a06e-v150/runtime-authority/task26-candidate-digest`
- preseal package root: `/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/live-transaction-preseal-v15-runtime-authority-r70/`
- execution root: `/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/live-executions-v15/nutricoach-v150-v15-runtime-authority-r70/`
- approval ledger: `/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/live-authorization-v15/nutricoach-v150-v15-runtime-authority-r70/`
- observer output: `/home/cube/.hermes/migrations/nutricoach-v1.5.0-combined/observer-r70/`

**One-use rules**
- `ApprovalLedger.reserve()` creates one reservation; `consume()` is irreversible and blocks reuse.
- `execute()` only runs when candidate/package/runtime/wheel hashes and the approval phrase all match exactly.
- `execute_nutricoach_v150_sealed_live.py` is only a sandbox wrapper; it does not mutate live state itself.
- `rehearse_nutricoach_v150_v15.py` uses disposable clones and proves rollback on all fault cases.
- observer rows are append-only and hash-chained; finalization is write-once after the window closes.

**In-flight draft compatibility evidence**
- Current live gateway state is running/connected on `81a7a06e-v150`.
- `observer-r70/observations.jsonl` rows show `candidate_matches=true`, `committed=true`, `channel_inbox_off=true`, `capacity=5`, `journal_clean=true`, `nrestarts=0`, and `weekly_enabled=true`.
- `live-executions-v15/...-r70/phase.json` is `COMMITTED`.
- `live-authorization-v15/...-r70/authorization-consumed.json` is `SUCCEEDED`.
- I found no current `nutrition_daily`/draft files under the live profile data tree, so there is no live draft mutation to conflict with.
- No current `r71` path showed up in the tree; the live chain visible here stops at `r70`.