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"}


I read this as a read-only implementation map - here’s the exact surface and boundaries.

**Core surface**
- `gateway/platforms/nutrition_coaching.py`
  - `open_launcher("nutrition_daily")`
  - `bind_launcher(...)`
  - `_terminal_launcher_reply(...)`
  - This is where a customer nutrition_daily launcher is opened and already-completed sessions are turned into the “already done” terminal notice.
- `gateway/platforms/physique_checkin.py`
  - `PhysiqueCheckinBridge.open_launcher`
  - `handle_callback`
  - `handle_text`
  - `_callback_transition`
  - `_nutrition_summary_prompt`
  - `_binding_expects_text`
  - `_advance`
  - `active_checkin_snapshot`, `finalized_coaching_snapshot`, `finalized_event`, `apply_model_action`
- `gateway/platforms/telegram.py`
  - `send_physique_checkin_launcher`
  - `_handle_callback_query` (`pc1:` dispatch)
  - `_render_physique_callback_prompt`
  - `_saved_physique_coaching_feedback`
  - `_nutrition_daily_text`
  - `nutrition_daily_customer_text`
- `dualcoach/profile/checkin_cli/wizard.py`
  - `WizardService.start_nutrition`
  - `answer`
  - `_summary_action`
  - `_save`
  - `_field_action`
- `dualcoach/profile/checkin_cli/wizard_storage.py`
  - `find_open`, `find_completed`, `find_latest_finalized`, `find_latest_finalized_through`, `save`, `load`
- `dualcoach/profile/checkin_cli/wizard_models.py`
  - `WizardFlow.NUTRITION`
  - `WizardStatus.ADVANCED/SAVED/INVALID/REJECTED/DEFERRED`
- `gateway/platforms/physique_checkin_prompts.py`
  - `WizardPrompt`
  - `build_wizard_prompt`
- `gateway/platforms/physique_checkin_bindings.py`
  - `WizardBinding`
  - `BindingStore`
- `gateway/platforms/physique_checkin_config.py`
  - config gate for exact owner/chat/topic and feature enablement

**Call sequence**
1. `nutrition_coaching.py::open_launcher("nutrition_daily")`
2. `PhysiqueCheckinBridge.open_launcher("nutrition_daily")`
3. launcher callback is bound with `bind_launcher_message(session_id, message_id)`
4. Telegram receives `pc1:` in `_handle_callback_query`
5. `_handle_callback_query` calls `PhysiqueCheckinBridge.handle_callback(...)`
6. `handle_callback` validates owner/chat/topic/message/version, then routes:
   - `launch` -> first prompt
   - `summary:a1` -> edit menu
   - `summary:a0` -> save
   - `edit_menu:eN` -> field edit
   - nav actions -> `_advance`
7. On save, `WizardService.answer(..., "save")` -> `_summary_action` -> `_save`
8. After save, Telegram’s `_render_physique_callback_prompt` replaces the message with `_nutrition_daily_text(finalized snapshot)`, and `_saved_physique_coaching_feedback` can add optional post-save coaching.

**Reusable mechanisms**
- Navigation/progress: `WizardBinding.step/version/awaiting_text/message_id`
- Persistence: `BindingStore`, `WizardStorage`, `WizardSession.finalized_event_id`, `find_open/find_completed`
- UI contract: `CallbackData`, `WizardPrompt`, `WizardReply`, `build_wizard_prompt`
- Opaque callback grammar: `pc1:` callbacks only; no answer payloads in callback data

**Tests to lean on**
- `dualcoach/profile/tests/test_customer_nutrition_wizard.py`
  - `test_nutrition_daily_persists_full_nutrition_and_recovery_snapshot`
  - `test_completed_nutrition_day_reopens_without_duplicate_event`
  - `test_completed_nutrition_day_can_be_corrected_with_an_append_only_event`
  - `test_repeated_nutrition_corrections_accumulate_from_latest_snapshot`
- `tests/gateway/test_customer_nutrition_ux.py`
  - `test_daily_checkin_can_finish_without_typing_a_workout`
  - `test_customer_completion_copy_hides_internal_markers`
- `tests/gateway/test_telegram_physique_checkin.py`
  - `test_customer_nutrition_edit_menu_uses_compact_korean_fields`
  - `test_summary_uses_three_compact_actions_and_a_flow_specific_two_column_edit_menu`
  - `test_edit_tab_changes_the_same_binding_screen_and_field_callback_enters_correction`
  - callback grammar/length tests for `pc1:` and opaque actions
- `tests/gateway/test_nutrition_coaching.py`
  - nutrition_daily launcher/bind/round-trip coverage

**Boundaries to preserve**
- Must keep `pc1:` opaque callback shape and size limits
- Must keep versioned binding + exact owner/chat/topic/message validation
- Must keep `WizardStatus` semantics and on-disk draft/event persistence
- Must not broaden unrelated callback namespaces or scheduler cards
- `cron/physique_inline_card.py` is scheduler-boundary code for `physique-checkin-morning`, `physique-source-review`, and `nutrition-coaching-tick`; it is not the nutrition_daily customer-launch path

No edits made.