# nutricoach-v140-weekly-operations - Work Plan

## TL;DR (For humans)
<!-- Fill this LAST, after the detailed plan below is written, so it summarizes the REAL plan. -->
<!-- Plain English for a non-engineer: NO file paths, NO todo numbers, NO wave/agent/tool names. -->

**What you'll get:** A default-off NutriCoach weekly-operation capability that records every calendar day's submitted, missed, or late status; shows one privacy-safe status card per day in the operator room; sends one 20:00 reminder; closes missing days at 23:00; and produces a Monday weekly trend draft for owner review.

**Why this approach:** Customer facts remain append-only and Telegram remains only a projection. New state lives in a rollback-safe sidecar so the current pilot runtime and old readers remain valid while reminder, room visibility, and weekly summaries gain explicit recovery semantics.

**What it will NOT do:** It will not expose raw meals, symptoms, free text, or health payloads in the operator room. It will not create monthly reports, automatically activate coaching changes, automatically send weekly coaching, fabricate history, or promise a visible Telegram message after an unknown provider outcome.

**Effort:** XL
**Risk:** High - the work crosses live scheduling, append-only state, Telegram delivery uncertainty, AI drafting, candidate sealing, and a seven-day real-customer observation.
**Decisions to sanity-check:** Seven KST calendar days; 20:00 reminder; 23:00 missed cutoff; one logical reservation and at most one provider call; owner-DM approval; one live customer and one weekly AI generation plus at most one correction pass.

Your next move: after this plan passes high-accuracy review, start it in a dedicated task-owned worktree. Full execution detail follows below.

---

> TL;DR (machine): XL/high-risk, 14 implementation todos plus 5 independent final verifiers; default-off v1.4.0 sidecar, exact-time reminder/missed lifecycle, Topic-59 projection, weekly owner draft, sealed candidate, bounded live observation.

## Scope
### Must have
- Build from an isolated source baseline that reproduces the active v1.3.2 profile wheel and includes the qualified v1.3.3 authority-isolation delta; never develop in the dirty detached source worktree.
- Add a typed `weekly_operations` capability that is compiled, configured, and separately authorized; `enabled` defaults to `false`.
- Parse only KST recurring times `20:00:00` and `23:00:00`, require reminder before cutoff, and reject absolute/naive deadlines.
- Correlate accepted terminal `NUTRITION_CHECKIN` roots and active correction lineages while retaining `MORNING_CHECKIN` compatibility.
- Persist a versioned append-only sidecar pinned to canonical event sequence/digest with `submitted`, `missed`, and `late_submitted` transitions.
- At 23:00, record `missed` independently of reminder outcome; add `reminded_no_response` only when the reminder is `sent_audited`.
- Use one logical reminder reservation and at most one provider call per customer/day. Unknown outcome is terminal; no same-day replacement attempt.
- Project one sanitized logical Topic-59 card per customer/day, send once and then edit by a durable `(customer_key, KST day)` binding.
- Count Monday-Sunday calendar days without changing the existing weekday-only 28-day KPI helper.
- Generate one Monday weekly owner draft from locked canonical facts, with at most one correction pass and deterministic Korean fallback.
- Keep approval and customer delivery in the canonical owner DM. Weekly coaching and plan changes remain manual.
- Prove default-OFF parity, restart/duplicate/race behavior, a deterministic seven-day synthetic week, real Telegram handler behavior, reproducible wheels, migration/rollback, and one permission-sealed seven-day live observation.
- Preserve the currently active candidate, consent, customer data, authority receipts, and an immediate rollback path throughout upgrade.

### Must NOT have (guardrails, anti-slop, scope boundaries)
- No monthly aggregation, `monthly_day` redesign, monthly task, monthly row, or monthly Telegram message.
- No raw weight, calories, macros, meals, symptoms, digestion, free text, customer name, Telegram address, or complete health payload in Topic 59.
- No approval buttons or final delivery action in Topic 59.
- No automatic coaching, plan, adaptive-proposal, or weekly-summary delivery to the customer; the approved static reminder is the sole new automatic-message exception.
- No literal “exactly one visible Telegram message” claim after an unknown provider outcome.
- No strict canonical event variant that makes v1.3.2 readers reject the stream; use the separate v1.4 sidecar.
- No fabricated historical check-ins, retroactive status backfill, mutation of old JSONL rows, or edits to v1.0-v1.3.3 receipts/artifacts.
- No new database, generic Telegram route, calendar system, trainer automation, human 최코치 account access, paid service, dependency upgrade, broad refactor, upstream merge, push, tag, release, or live enablement without its explicit authorization gate.
- No reset, clean, stash, rebase, or modification of unrelated dirty worktree content.

## Verification strategy
> Zero human intervention - all verification is agent-executed.
- Test decision: TDD with pytest. Every behavior todo begins with one regression that fails for the intended reason, then the minimum implementation makes it pass. Time tests use injected clocks and barriers/events; fixed sleeps and polling waits are forbidden.
- Static checks: run the repository's existing `ruff`, `compileall`, package tests, and candidate-bound interpreter checks. Do not introduce a new toolchain or suppress existing failures.
- Focused profile command: `uv run --project dualcoach/profile pytest dualcoach/profile/tests/test_customer_schedule.py dualcoach/profile/tests/test_customer_reporting.py dualcoach/profile/tests/test_weekly_operations.py -q`.
- Focused gateway command: `uv run pytest -q tests/gateway/test_nutrition_coaching.py tests/gateway/test_telegram_physique_checkin.py tests/gateway/test_nutrition_weekly_operations.py`.
- Broad gates: `uv run --project dualcoach/profile pytest -q`; then `uv run pytest -q tests/gateway` under the same candidate-bound package path used by the sealed runtime. Record known unrelated failures separately; changed seams must have zero failures.
- Manual-surface gate: drive real `TelegramAdapter` handlers with the existing fake Telegram engine, then use a disposable profile and synthetic bot route with network disabled. Live Telegram begins only after a separate permission seal.
- Evidence root: `.omo/evidence/nutricoach-v140-weekly-operations/`; every task writes the named JSON or Markdown receipt atomically and records exact commands, exit codes, hashes, and provider-call counts.
- Required synthetic fixture: KST `2026-08-17` through `2026-08-23`, `submitted=4`, `late_submitted=1`, `missed=2`, `completed=5/7`, `adherence=71.43%`, `reminders=4`, duplicate provider calls `0`, logical Topic-59 cards `7`, Monday owner cards `1`, automatic coaching customer calls `0`, privacy leaks `0`.

## Execution strategy
### Parallel execution waves
> Target 5-8 todos per wave. Fewer than 3 (except the final) means you under-split.
- Wave 1 - source and domain foundation: Todos 1-4. Todo 1 gates every edit; Todos 2-4 may proceed in parallel after its baseline receipt.
- Wave 2 - runtime behavior: Todos 5-8. Reminder/status, room projection, weekly aggregation, and owner drafting develop against the frozen domain contracts.
- Wave 3 - integration and qualification: Todos 9-12. Host wiring precedes the seven-day and Telegram scenarios; all automated/synthetic evidence precedes candidate sealing.
- Wave 4 - bounded live operation: Todos 13-14. A permission-sealed upgrade occurs only at a clean boundary; the seven-day observer uses scheduled wakeups/events, never sleep loops.
- Final wave - F1-F5 run in parallel only after Todo 14. Every verifier must approve the same sealed candidate and evidence manifest.

### Dependency matrix
| Todo | Depends on | Blocks | Can parallelize with |
| --- | --- | --- | --- |
| 1 | none | 2-14 | none |
| 2 | 1 | 5, 9, 11-14 | 3, 4 |
| 3 | 1 | 5-10, 12-14 | 2, 4 |
| 4 | 1 | 5, 7, 9-14 | 2, 3 |
| 5 | 2, 3, 4 | 9-14 | 6, 7, 8 |
| 6 | 2, 3 | 9-14 | 5, 7, 8 |
| 7 | 3, 4 | 8-14 | 5, 6 |
| 8 | 2, 7 | 9-14 | 5, 6 |
| 9 | 2-8 | 10-14 | none |
| 10 | 9 | 12-14 | 11 |
| 11 | 9 | 12-14 | 10 |
| 12 | 10, 11 | 13-14 | none |
| 13 | 12 | 14 | none |
| 14 | 13 | F1-F5 | none |

## Todos
> Implementation + Test = ONE todo. Never separate.
<!-- APPEND TASK BATCHES BELOW THIS LINE WITH edit/apply_patch - never rewrite the headers above. -->
- [x] 1. Materialize a clean candidate-bound source baseline
  - What to do / Must NOT do: Create `/home/cube/projects/richard/.worktrees/nutricoach-v140-impl` on branch `feature/nutricoach-weekly-operations-v1.4.0` from the detached worktree's recorded HEAD, then apply only source bytes proven by the qualified v1.3.2/v1.3.3 wheels and source hashes. Capture a binary tracked-source delta plus candidate-required untracked inventory from `/home/cube/projects/richard/.worktrees/nutricoach-v111-impl`; exclude build/evidence/runtime/cache files. Build twice before feature edits and require Hermes wheel `cf4ccf4872ecd064c9878a11f5e2389262a7e05d561a3df6c004efff3b393f92`, profile wheel `a099b3e1da62d8291fb3442de64e9de9b12e6f67aa63fa8fdf62abccbcabfa29`, Telegram adapter source `8b6c7be44171a49f348d9b1a5d767d81d12e47945c805cd2a321ad675caa0c62`, and regression-test source `75ab5ed563759fc6e5f22a6796ba1cf8b6aa109445b6947ae4644c73fb63d22`. Stop on any mismatch. Must NOT edit, clean, stash, reset, or commit the dirty source worktree.
  - Parallelization: Wave 1 | Blocked by: none | Blocks: 2-14
  - References (executor has NO interview context - be exhaustive): `.omo/evidence/v1.3.2-daily-checkin/qualification.json`; `.omo/evidence/v1.3.3-checkin-authority-isolation/qualification.json`; `/home/cube/.hermes/migrations/dualcoach-v1.3.3-checkin-authority-isolation/live-switch-20260823-2145/deployment-receipt.json`; `/home/cube/.omo/memory/agents/traning-coach-e178cb81/repo/skills/dualcoach-v1-upgrade/SKILL.md`
  - Acceptance criteria (agent-executable): two isolated pre-feature builds produce the exact four hashes above; the new worktree is clean relative to its reconstructed baseline; v1.3.3 focused `87 passed`; active live candidate remains `6c9c4394a9406f7464921be1b86a88429e70c6411fd13b7508ace67e14a6a92f`; write `.omo/evidence/nutricoach-v140-weekly-operations/task-1-baseline.json`.
  - QA scenarios (exact tool + invocation): happy - `git -C /home/cube/projects/richard/.worktrees/nutricoach-v140-impl status --short --branch` plus the existing v1.3.3 two-build verifier; failure - alter one copied source byte in a disposable clone and prove hash verification exits nonzero before tests/build. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-1-baseline.json`.
  - Recommended task executor category: `deep` - source reconstruction and candidate identity require cross-artifact reasoning.
  - Commit: N | prepare a baseline commit manifest only; actual commit requires explicit commit/PR authorization.

- [x] 2. Define the default-off weekly-operations capability contract
  - What to do / Must NOT do: Add a frozen typed `WeeklyOperationsConfig` parsed from `extra.nutrition_coaching.weekly_operations` with `enabled=false`, KST `reminder_time=20:00:00`, `missed_cutoff_time=23:00:00`, `weekly_weekday=0`, and the existing Topic-59 review route. Add a versioned authority receipt binding candidate, config digest, enabled customer keys, owner identity/version, consent digest, issue/expiry, and feature epoch. Runtime requires compiled + configured + authorized + current consent. Reject missing/naive/absolute times, reminder >= cutoff, wrong route, stale authority, or customer not listed. Must NOT overload `AdaptiveNutritionConfig`, enable current customers, or alter existing daily/weekly scheduling when OFF.
  - Parallelization: Wave 1 | Blocked by: 1 | Blocks: 5, 9, 11-14
  - References: `gateway/platforms/nutrition_coaching_config.py:13-178`; `gateway/platforms/telegram.py:4942-5308`; `/home/cube/.hermes/profiles/dualcoachtest/config.yaml:641-681`; `/home/cube/.hermes/profiles/dualcoachtest/customers/registry.json:1-20`; dualcoach upgrade skill compiled/configured/authorized invariant.
  - Acceptance criteria: RED proves omitted config creates zero v1.4 effects and invalid time/order/authority fails closed; GREEN parses only the approved KST schedule, remains OFF by default, and requires a separately sealed per-customer authority receipt. Focused config tests pass and serialize a stable config digest.
  - QA scenarios: happy - `uv run pytest -q tests/gateway/test_nutrition_weekly_operations.py -k config`; failure - fixtures for missing authority, stale consent, wrong Topic 59, `20:00+00:00`, and `23:00/20:00` produce no rows/provider calls. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-2-config.json`.
  - Recommended task executor category: `unspecified-high` - typed config and authority cross gateway and live contracts.
  - Commit: N | planned group `Add default-off weekly operations authority`.

- [x] 3. Implement the append-only day-status sidecar
  - What to do / Must NOT do: Create focused profile modules `checkin_cli/weekly_operations.py` and `checkin_cli/weekly_operations_store.py`, each <=250 pure LOC, for schema `nutricoach-weekly-operations-v1`. Persist a private append-only hash-chained JSONL sidecar with customer key, KST day, state (`submitted|missed|late_submitted`), canonical sequence/digest, source event ID/digest when present, reminder reservation/audit identity when present, predecessor row digest, occurred time, and row digest. Deterministic keys make replays no-ops. `missed -> late_submitted` is the only same-day timeliness transition; corrections update source lineage without changing timeliness. Torn tail may be recoverable only by the existing explicit repair pattern; interior corruption and disagreements fail closed. Must NOT change strict canonical event variants or rewrite prior rows.
  - Parallelization: Wave 1 | Blocked by: 1 | Blocks: 5-10, 12-14
  - References: `dualcoach/profile/checkin_cli/models.py:31-56,864-967`; `dualcoach/profile/checkin_cli/store.py:70-111,460-565`; `dualcoach/profile/checkin_cli/customer_schedule.py:24-60,604-980`. There is no standalone check-in JSON Schema in the qualified source; `models.py` plus `store.py` are the canonical strict contract and the new sidecar must remain separate from them.
  - Acceptance criteria: RED covers duplicate append, illegal transition, canonical pin drift, torn tail, interior corruption, wrong customer/day, and v1.3.2 reader coexistence; GREEN produces deterministic rows with mode `0600`, fsync/atomic boundary evidence, unchanged canonical JSONL bytes, and zero schema-v1 reader regressions.
  - QA scenarios: happy - `uv run --project dualcoach/profile pytest dualcoach/profile/tests/test_weekly_operations.py -q`; failure - byte-flip an interior row and inject a crash after append-before-index to prove fail-closed/recovery behavior without row deletion. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-3-sidecar.json`.
  - Recommended task executor category: `deep` - append-only state, corruption, and compatibility are safety-critical.
  - Commit: N | planned group `Persist weekly day status without changing canonical events`.

- [x] 4. Correlate NutriCoach check-ins and correction lineages
  - What to do / Must NOT do: Add a pure projector that recognizes accepted terminal `NUTRITION_CHECKIN` roots for the exact customer/KST day, follows only the active immutable correction lineage, and retains legacy `MORNING_CHECKIN` support. At or before 23:00 project `submitted`; after a committed `missed`, the first valid root projects `late_submitted`; later corrections change the source pin only. Resolve the 23:00 check-in/cutoff race under one customer/day lock and a single canonical snapshot. Missing, unsafe, unaccepted, wrong-customer, wrong-day, stale, superseded, or malformed events do not count.
  - Parallelization: Wave 1 | Blocked by: 1 | Blocks: 5, 7, 9-14
  - References: `dualcoach/profile/checkin_cli/store.py:70-111`; `dualcoach/profile/checkin_cli/wizard.py:1008-1015`; `dualcoach/profile/checkin_cli/customer_reporting.py:699-750`; `gateway/platforms/telegram.py:10072-10086`; live draft `data/customers/pilot_20260820_01/wizard/drafts/a594ba00240399c36f366e83fff8e405.json`
  - Acceptance criteria: RED reproduces the current bug where a terminal `NUTRITION_CHECKIN` still appears missing; GREEN classifies exact boundary times 22:59:59/23:00:00, preserves correction timeliness, accepts legacy morning events, and selects one winner under concurrent cutoff/check-in barriers.
  - QA scenarios: happy - focused profile tests with an injected KST clock and two correction generations; failure - wrong customer/day, unsafe event, superseded root, and simultaneous cutoff/check-in produce no double terminal state. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-4-correlation.json`.
  - Recommended task executor category: `deep` - root/correction ownership and cutoff races span canonical and sidecar state.
  - Commit: N | planned group `Correlate nutrition check-ins with weekly status`.

- [x] 5. Enforce the 20:00 reminder and 23:00 missed lifecycle
  - What to do / Must NOT do: Extend the existing schedule evaluator and ledger adapters rather than creating a second send path. At 20:00, for one eligible unanswered customer/day, reserve the approved static template once; recheck response and all pins immediately before provider authority. Same-day known failure, unknown, stale authority, or explicit rejection records an incident and never creates a replacement reminder. At 23:00, independently append `missed` if no valid response. Add `reminded_no_response` only for `sent_audited`; otherwise attach `reminder_delivery_incident`. A valid response after sending abandons before provider when possible; a post-cutoff response becomes `late_submitted`.
  - Parallelization: Wave 2 | Blocked by: 2, 3, 4 | Blocks: 9-14
  - References: `dualcoach/profile/checkin_cli/customer_schedule.py:211-253,1519-1690,1838-1959`; `dualcoach/profile/tests/test_customer_schedule.py:71-119,252-390`; `gateway/platforms/telegram.py:10049-10243`; `tests/gateway/test_telegram_physique_checkin.py:1518-2209`
  - Acceptance criteria: exact boundary tests 19:59:59/20:00:00 and 22:59:59/23:00:00 pass; one customer/day has <=1 provider call and <=1 reminder reservation lineage; unknown is terminal; `missed` exists regardless of reminder receipt; no reminder when a valid response exists.
  - QA scenarios: happy - `uv run --project dualcoach/profile pytest dualcoach/profile/tests/test_customer_schedule.py -q` and gateway reminder tests; failure - inject timeout, explicit no-send, stale authority, response race, restart after each state, and duplicate concurrent ticks; assert no second provider call. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-5-reminder.json`.
  - Recommended task executor category: `deep` - provider uncertainty and same-day no-retry are release-critical.
  - Commit: N | planned group `Fence weekly reminder and missed cutoff`.

- [x] 6. Add the privacy-safe Topic-59 day-card projector
  - What to do / Must NOT do: Create `gateway/platforms/nutrition_weekly_operations.py` for a separate deterministic projector/publication ledger keyed by `(customer_key, KST day)`. The card whitelist is opaque customer key, date, `submitted|missed|late_submitted`, completed-field count, draft/approval/delivery state labels, and event/status row IDs; never include raw values or names. First publication has one reserved send; later state changes edit the persisted message ID. Record prepared/sending/delivered/sent_audited or terminal unknown for send and edit operations. No approval buttons. A missing/unknown card becomes an operator incident rather than a blind new message.
  - Parallelization: Wave 2 | Blocked by: 2, 3 | Blocks: 9-14
  - References: `gateway/platforms/nutrition_coaching.py:21296-21545`; `gateway/platforms/telegram.py:5318-5367,6103-6225`; `tests/gateway/test_nutrition_coaching.py:2740-2863`; `tests/gateway/test_telegram_physique_checkin.py:2462-2559`; `/home/cube/.hermes/profiles/dualcoachtest/config.yaml:641-676`
  - Acceptance criteria: RED proves current Topic-59 publication cannot bind/edit one customer/day card; GREEN yields seven logical cards for seven days, edits `missed -> late_submitted` on the same message ID, survives restart without duplicate sends, reserves only exact Topic 59, and passes a machine whitelist asserting zero forbidden fields.
  - QA scenarios: happy - real `TelegramAdapter` fake-provider driver sends one card then edits it; failure - wrong topic/user, send unknown, edit unknown, restart, duplicate tick, malformed sidecar, and PII fixture result in zero unauthorized provider calls. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-6-topic59.json`.
  - Recommended task executor category: `unspecified-high` - this is a multi-file Telegram projection feature with strict privacy.
  - Commit: N | planned group `Project daily status into Topic 59`.

- [x] 7. Build seven-calendar-day weekly aggregates
  - What to do / Must NOT do: Add a new weekly-operations summary type and builder using exactly Monday 00:00 through Sunday 23:59:59 KST. Join active canonical check-ins with the v1.4 sidecar to report submitted, late, missed, completed/7, adherence percentage, bounded weight trend, reminder incidents, and prior-week comparison. Keep the existing `_weekday_dates` and 28-day KPI behavior byte-for-byte unchanged. Summary output contains aggregates only; raw payloads and customer identity remain excluded.
  - Parallelization: Wave 2 | Blocked by: 3, 4 | Blocks: 8-14
  - References: `dualcoach/profile/checkin_cli/customer_reporting.py:17-166,409-479,617-750`; `dualcoach/profile/tests/test_customer_reporting.py:80-120,661-690`; v1.3.2 qualification `daily_checkin_days=all_calendar_days`
  - Acceptance criteria: the approved synthetic week returns `4 submitted`, `1 late`, `2 missed`, `5/7`, `71.43%`; duplicate/corrected events do not change counts; timezone boundaries are deterministic; the existing KPI tests remain unchanged and pass.
  - QA scenarios: happy - `uv run --project dualcoach/profile pytest dualcoach/profile/tests/test_customer_reporting.py dualcoach/profile/tests/test_weekly_operations.py -q`; failure - missing sidecar, digest disagreement, Sunday/Monday boundary, duplicate roots, and wrong customer fail closed without leaking raw values. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-7-summary.json`.
  - Recommended task executor category: `unspecified-high` - aggregation is bounded but crosses two authoritative streams.
  - Commit: N | planned group `Aggregate seven-day weekly operations`.

- [x] 8. Ground the Monday AI draft and preserve owner-DM authority
  - What to do / Must NOT do: Extend the existing weekly grounding path so code locks every number, status, trend, decision option, and action. The model may explain only those approved fields using the shipped 최코치 public-knowledge package. Allow one generation plus at most one correction pass. Invalid schema, drift, provider outage, or exhausted budget uses deterministic Korean copy. Create exactly one owner-DM weekly draft through `create_weekly_review_draft`; approval/edit/send remain the existing owner lifecycle. Never place approval buttons in Topic 59 and never auto-send the weekly summary to the customer.
  - Parallelization: Wave 2 | Blocked by: 2, 7 | Blocks: 9-14
  - References: `dualcoach/profile/checkin_cli/customer_reporting.py:88-166`; `gateway/platforms/nutrition_coaching.py:4109-4169`; `gateway/platforms/telegram.py:9314-9483,10594-10864`; `tests/gateway/test_nutrition_coaching.py:386-443`; `tests/gateway/test_telegram_physique_checkin.py:1413-1517`
  - Acceptance criteria: one Monday source creates one owner-DM draft; replay returns the same logical draft; model cannot alter numeric/decision fields; outage produces deterministic copy; provider calls <=2; customer weekly sends remain zero until the owner uses the existing approved delivery action.
  - QA scenarios: happy - fake model returns valid bounded explanation and owner edits/approves through real lifecycle; failure - hallucinated number, stale grounding digest, malformed result, timeout, wrong owner route, and preapproval send all fail or fall back without customer transport. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-8-owner-draft.json`.
  - Recommended task executor category: `deep` - model grounding must remain subordinate to deterministic authority.
  - Commit: N | planned group `Ground weekly draft behind owner approval`.

- [x] 9. Wire the capability into the production dispatcher
  - What to do / Must NOT do: Integrate the new coordinator into `nutrition-coaching-tick` using the existing one-minute scheduler, exact configured routes, registry refresh, and task26 authority fence. Order each tick: validate capability/authority/consent -> snapshot canonical/sidecar state -> due reminder/cutoff -> day-card projection -> Monday summary/draft. Reserve Topic 59 before generic dispatch. Feature OFF must call none of the new projectors/providers and leave v1.3.2 daily launchers/weekly owner behavior unchanged. Preserve dormant monthly behavior.
  - Parallelization: Wave 3 | Blocked by: 2-8 | Blocks: 10-14
  - References: `gateway/platforms/telegram.py:9904-10864`; `dualcoach/profile/checkin_cli/customer_schedule.py:211-253`; `tests/gateway/test_nutrition_coaching.py:633-765`; `tests/gateway/test_telegram_physique_checkin.py:1743-2209`; live cron `/home/cube/.hermes/profiles/dualcoachtest/cron/jobs.json`
  - Acceptance criteria: default OFF produces zero v1.4 rows/provider calls and unchanged baseline receipts; ON with valid authority executes due work once; stale authority/consent/wrong route fails closed; duplicate/concurrent ticks share one provider authority; monthly tasks/messages remain zero.
  - QA scenarios: happy - invoke `_send_nutrition_coaching_tick_authorized` at each boundary with fake clocks and real stores; failure - toggle OFF mid-tick, revoke consent, drift candidate/config, corrupt ledger, wrong Topic 59, and concurrent ticks. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-9-dispatcher.json`.
  - Recommended task executor category: `deep` - host wiring combines all authority and scheduling boundaries.
  - Commit: N | planned group `Wire weekly operations dispatcher`.

- [x] 10. Prove the deterministic seven-day Golden Path
  - What to do / Must NOT do: Add a fake-clock, no-network driver for `2026-08-17` through `2026-08-23` using real profile stores and gateway coordinator. Script four on-time submissions, one post-cutoff submission, two missing days, four eligible reminders, duplicate ticks, process restarts, one known reminder failure, one unknown card edit, and Monday summary generation. Use event/barrier synchronization, never sleeps. Emit a canonical scenario receipt and manifest.
  - Parallelization: Wave 3 | Blocked by: 9 | Blocks: 12-14
  - References: `.omo/evidence/dualcoach-golden-path-contract.md:33-34,93`; `scripts/dualcoach_v111_fake_telegram_engine.py`; `scripts/run_dualcoach_v111_disposable_e2e.py`; focused tests from Todos 3-9
  - Acceptance criteria: exact final counts are submitted `4`, late `1`, missed `2`, completed `5/7`, adherence `71.43%`, reminders `4`, duplicate calls `0`, logical Topic-59 cards `7`, Monday owner cards `1`, automatic coaching customer calls `0`, privacy leaks `0`; every row/message is bound into `task-10-golden-path.json`.
  - QA scenarios: happy - run the new driver twice from clean temp roots and require byte-identical normalized receipts; failure - inject crashes after every append/fsync/provider boundary plus cutoff race and assert either reconciled success or terminal unknown, never duplication. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-10-golden-path.json`.
  - Recommended task executor category: `deep` - this is the cross-module behavioral proof.
  - Commit: N | planned group `Prove weekly operations Golden Path`.

- [x] 11. Exercise real Telegram handlers in a disposable profile
  - What to do / Must NOT do: Add typed PEP-723/usage-documented `scripts/run_nutricoach_v140_disposable_e2e.py` and drive the actual callback/text/tick handlers and `TelegramAdapter` send/edit methods through the existing fake Telegram engine and a disposable profile. Support `--network-disabled --scenario weekly-operations` and `--verify-privacy`. Exercise customer reminder, Topic-59 day card, late edit, owner-DM weekly draft, owner approval, and one approved customer send. Include bad input, wrong user/topic/chat, stale callback, duplicate update, provider timeout, and `--help`/preflight surfaces. Network and live credentials remain disabled.
  - Parallelization: Wave 3 | Blocked by: 9 | Blocks: 12-14
  - References: `gateway/platforms/telegram.py:6103-6225,6345-6800,7481-8010,9904-10864`; `scripts/dualcoach_v111_fake_telegram.py`; `scripts/dualcoach_v111_fake_telegram_engine.py`; `tests/gateway/test_telegram_physique_checkin.py`
  - Acceptance criteria: actual rendered cards contain only whitelisted fields; one day card is edited in place; owner controls exist only in DM; customer receives no weekly message before approval; one approved send records a durable exactly-once receipt; wrong routes have zero provider calls.
  - QA scenarios: happy - run the disposable E2E entry point and inspect captured Telegram updates/messages; failure - wrong topic/user, unknown send/edit, callback replay, stale authority, and corrupt sidecar. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-11-telegram-e2e.json` plus sanitized transcripts.
  - Recommended task executor category: `deep` - real-surface QA spans production handlers and transport semantics.
  - Commit: N | planned group `Exercise weekly operations Telegram surfaces`.

- [x] 12. Build and seal the immutable v1.4.0 candidate
  - What to do / Must NOT do: Add `scripts/verify_nutricoach_v140_candidate.py` as a typed PEP-723/usage-documented verifier for this release; do not reuse `verify_dualcoach_v11_candidate.py`, whose contract allows only the v1.1 TTL delta. The v1.4 verifier must validate both wheel RECORD inventories, a manifest-declared allowlist of every changed member, unchanged-member byte equality against the reconstructed baseline, source-tree/wheel/profile/config/policy/evidence hashes, full canonical product derivation, source and installed seven-day Golden Path receipts, migration/rollback receipts, default-OFF receipt, and candidate inequality from any single wheel digest. Run focused and broad profile/gateway suites under the exact candidate interpreter, ruff, compileall, module-size/no-excuse audit, two independent wheel builds, and installed-wheel Golden Path. Prepare two atomic commit groups (source; evidence/inventory) with Lore trailers, but do not commit, tag, push, publish, or deploy unless the later `/start-work` invocation or an explicit owner message authorizes that git/release action.
  - Parallelization: Wave 3 | Blocked by: 10, 11 | Blocks: 13-14
  - References: v1.3.2 and v1.3.3 qualification JSON; `scripts/verify_dualcoach_v11_candidate.py:1-164` as the explicitly incompatible TTL-only precedent; `scripts/dualcoach_v111_evidence.py`; dualcoach upgrade skill “Sealing a delta-qualified feature candidate”; `.agents/skills/lore-commits/SKILL.md`
  - Acceptance criteria: `uv run scripts/verify_nutricoach_v140_candidate.py --base .omo/evidence/nutricoach-v140-weekly-operations/task-1-baseline.json --successor .omo/evidence/nutricoach-v140-weekly-operations/task-12-candidate --manifest .omo/evidence/nutricoach-v140-weekly-operations/task-12-candidate/manifest.json` exits 0 and prints `NUTRICOACH_V140_CANDIDATE_PASS`; focused tests and all changed seams pass; broad suites have zero new failures; feature OFF matches baseline; two builds have identical wheel hashes; installed-wheel Golden Path matches source; manifest contains no dirty/untracked/uninventoried bytes; candidate digest is not equal to any single wheel digest; qualification status is `QUALIFIED_PENDING_LIVE_AUTHORIZATION`.
  - QA scenarios: happy - execute the exact verifier invocation above against both builds and installed candidate and require `NUTRICOACH_V140_CANDIDATE_PASS`; failure - substitute one changed-member allowlist entry and one wheel/source/config byte in disposable copies and require nonzero exit before qualification. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-12-candidate/`.
  - Recommended task executor category: `deep` - release identity and reproducibility are high-risk.
  - Commit: N | stage nothing; exact source/evidence commit messages are prepared for explicit authorization only.

- [ ] 13. Perform a permission-sealed bounded-pilot upgrade
  - What to do / Must NOT do: Choose the next clean Monday only after candidate qualification. Produce a read-only preflight that proves one enabled consenting customer, no pending onboarding/owner review/send/unknown provider outcome, active candidate `6c9c4394…`, exact snapshots, current authority, privacy whitelist, AI spend cap, migration dry-run, and rollback to the previous runtime. Create a one-use permission seal and stop for explicit owner authorization. After authorization only: stop Gateway, snapshot customer/profile/authority bytes, install v1.4 with capability OFF, run migration/no-backfill initialization, start and smoke-check baseline, arm capability for only `pilot_20260820_01`, restart, and verify current consent/authority/state. On any drift, stop and restore the previous runtime/config/snapshot.
  - Parallelization: Wave 4 | Blocked by: 12 | Blocks: 14
  - References: dualcoach upgrade skill live bounded-pilot sequence; `/home/cube/.hermes/migrations/dualcoach-v1.3.3-checkin-authority-isolation/live-switch-20260823-2145/deployment-receipt.json`; `/home/cube/.hermes/profiles/dualcoachtest/config.yaml`; `/home/cube/.hermes/profiles/dualcoachtest/customers/registry.json`; current systemd service and task26 authority receipts
  - Acceptance criteria: no live mutation occurs before the exact one-use approval receipt; Gateway is stopped during install/migration; all other profiles and past receipts remain byte-identical; feature starts OFF then enables only the named customer; rollback rehearsal restores the exact prior runtime; deployment receipt binds candidate/config/authority/snapshots and reports `PASS`.
  - QA scenarios: happy - read-only preflight, authorized clean-boundary install, baseline smoke, then feature enable; failure - pending review, unknown delivery, stale consent/authority, digest drift, failed migration, or smoke failure prevents enablement and restores prior runtime. Evidence `/home/cube/.hermes/migrations/nutricoach-v1.4.0-weekly-operations/<timestamp>/`.
  - Recommended task executor category: `deep` - this is a permission-gated live mutation with rollback.
  - Commit: N | live receipts are immutable external evidence, not source commits.

- [ ] 14. Observe and close one real seven-day operating window
  - What to do / Must NOT do: Add typed PEP-723/usage-documented `scripts/verify_nutricoach_v140_live_observation.py` with `--receipt-root`, `--verify-cleanup`, and `--verify-rollback`. Observe Monday-Sunday for only the authorized customer using event-driven service/journal watchers and scheduled wakeups, never foreground sleeps or poll loops. Each day reconcile 08:00 launcher, actual submission or 20:00 reminder, 23:00 status, Topic-59 card, and durable receipts. On next Monday reconcile one owner-DM weekly draft and verify no automatic customer weekly send. Abort and roll back immediately on privacy leak, duplicate provider call/card, unknown delivery requiring human reconciliation, ledger corruption, authority/consent drift, or incorrect cutoff. If all pass, keep the bounded capability enabled for that customer and seal the seven-day observation/cleanup manifest.
  - Parallelization: Wave 4 | Blocked by: 13 | Blocks: F1-F5
  - References: deployed v1.4 migration receipt from Todo 13; customer schedule `daily_time=08:00:00`, `weekly_weekday=0`; live cron tick; sidecar/schedule/publication ledgers; owner-DM draft and delivery ledgers
  - Acceptance criteria: seven calendar days have one logical status each; actual observed reminder/submission outcomes reconcile exactly; no privacy leak or duplicate call; one Monday owner draft exists; customer weekly sends remain zero before owner approval; cleanup finds no stale claims/capabilities/unknown rows; final manifest and hashes verify.
  - QA scenarios: happy - event-driven daily receipts plus Monday owner-draft check; failure - injected/reproduced authority drift or provider unknown triggers the documented stop/rollback path and a truthful NO-GO receipt. Evidence `.omo/evidence/nutricoach-v140-weekly-operations/task-14-live-observation/`.
  - Recommended task executor category: `deep` - week-long live evidence and abort handling require sustained system reasoning.
  - Commit: N | observation receipts remain outside source history unless separately authorized.

## Final verification wave
> Runs in parallel after ALL todos. ALL must APPROVE. Surface results and wait for the user's explicit okay before declaring complete.
- [ ] F1. Objective and invariant compliance audit
  - Verify every approved behavior and Must-NOT-Have against the exact candidate and manifest; reject self-reported or grep-only evidence. Recompute synthetic/live counts and inspect default-OFF parity.
  - Recommended task executor category: `unspecified-high`
  - QA scenarios: run `uv run scripts/verify_nutricoach_v140_candidate.py --base .omo/evidence/nutricoach-v140-weekly-operations/task-1-baseline.json --successor .omo/evidence/nutricoach-v140-weekly-operations/task-12-candidate --manifest .omo/evidence/nutricoach-v140-weekly-operations/task-12-candidate/manifest.json` and independently parse `task-10-golden-path.json`; require `NUTRICOACH_V140_CANDIDATE_PASS`, counts `4/1/2`, `5/7`, `71.43%`, feature-OFF zero effects, and zero Must-NOT-Have violations.
  - Evidence: `.omo/evidence/nutricoach-v140-weekly-operations/final/F1-objective.json`
- [ ] F2. Privacy, consent, and authority audit
  - Inspect Topic-59 rendered payloads, sidecar inventory/retention, owner-DM controls, consent and feature authority, wrong-route tests, AI budget, and one-customer scope. Any raw health value/name/address in Topic 59 is a blocker.
  - Recommended task executor category: `unspecified-high`
  - QA scenarios: run `uv run pytest -q tests/gateway/test_nutrition_weekly_operations.py -k 'privacy or authority or wrong_route or consent'` and the disposable transcript scanner `uv run scripts/run_nutricoach_v140_disposable_e2e.py --verify-privacy --network-disabled`; require exit 0, provider calls `0` for denied fixtures, one authorized customer, and forbidden-field count `0`.
  - Evidence: `.omo/evidence/nutricoach-v140-weekly-operations/final/F2-privacy-authority.json`
- [ ] F3. Reliability and exactly-once audit
  - Re-run duplicate/concurrent ticks, cutoff race, restart boundaries, torn/interior corruption, reminder/card send/edit unknown, audit reconciliation, and customer approved-delivery tests. Require <=1 provider call per logical reservation and terminal uncertainty without retry.
  - Recommended task executor category: `deep`
  - QA scenarios: run `uv run --project dualcoach/profile pytest dualcoach/profile/tests/test_customer_schedule.py dualcoach/profile/tests/test_weekly_operations.py -q` and `uv run pytest -q tests/gateway/test_nutrition_weekly_operations.py -k 'duplicate or concurrent or race or restart or corrupt or unknown or reconciliation'`; require exit 0, every logical reservation provider-call count <=1, and every unknown outcome terminal with retry count `0`.
  - Evidence: `.omo/evidence/nutricoach-v140-weekly-operations/final/F3-reliability.json`
- [ ] F4. Real-surface and seven-day QA audit
  - Drive fake Telegram real handlers, inspect sanitized transcripts, verify the installed-candidate synthetic week, and independently reconcile the permission-sealed live seven-day receipts and Monday owner draft.
  - Recommended task executor category: `unspecified-high`
  - QA scenarios: run `uv run scripts/run_nutricoach_v140_disposable_e2e.py --network-disabled --scenario weekly-operations` and `uv run scripts/verify_nutricoach_v140_live_observation.py --receipt-root .omo/evidence/nutricoach-v140-weekly-operations/task-14-live-observation`; require `DISPOSABLE_WEEKLY_OPERATIONS_PASS`, seven logical day cards, one Monday owner draft, no preapproval weekly customer send, and a valid PASS or truthful rollback-bound NO-GO live receipt.
  - Evidence: `.omo/evidence/nutricoach-v140-weekly-operations/final/F4-real-surface.json`
- [ ] F5. Provenance, migration, rollback, and cleanup audit
  - Recompute source/candidate/wheel/config/evidence identities; prove old candidates/receipts and other profiles are unchanged; verify rollback material, no stale claims/capabilities/unknown rows, no monthly artifacts, and exact candidate-bound interpreter.
  - Recommended task executor category: `deep`
  - QA scenarios: run the exact v1.4 candidate verifier from F1 plus `uv run scripts/verify_nutricoach_v140_live_observation.py --receipt-root .omo/evidence/nutricoach-v140-weekly-operations/task-14-live-observation --verify-cleanup --verify-rollback`; require exit 0, separately matching source/Hermes/profile/candidate digests, byte-identical protected inventories, zero stale claims/capabilities/unknown rows, zero monthly artifacts, and the candidate-bound interpreter hash.
  - Evidence: `.omo/evidence/nutricoach-v140-weekly-operations/final/F5-provenance-cleanup.json`

## Commit strategy
- Default: no commit, tag, push, PR, release, or deployment merely from executing the plan.
- All code changes occur only in `/home/cube/projects/richard/.worktrees/nutricoach-v140-impl`; unrelated dirty paths remain untouched.
- If the user explicitly invokes `/start-work ... --make-pr` or separately authorizes commits, create exactly two atomic Lore-form commits:
  1. source + direct tests, with candidate-bound rationale and Tested trailers;
  2. evidence + authoritative inventory, only after the source commit is green and reproducible.
- Never mix live receipts, customer data, credentials, runtime snapshots, or unrelated cleanup into source commits. `--ship` is the only handoff mode that authorizes push/PR review/merge continuation.

## Success criteria
- The final plan implementation has 14 completed implementation todos and all five final verifiers approve the same candidate/evidence manifest.
- Feature OFF yields zero v1.4 sidecar rows, reminders, Topic-59 calls, monthly work, activation changes, or baseline behavior drift.
- Feature ON for one authorized customer enforces 20:00 reminder, 23:00 missed cutoff, seven calendar days, correction-stable timeliness, and no same-day reminder replacement.
- Topic 59 contains one logical sanitized card per customer/day and no raw health values, names, addresses, free text, or approval actions.
- Weekly aggregation and AI draft are deterministic in facts, owner-DM gated, bounded to one generation plus one correction, and never auto-delivered to the customer.
- Synthetic Golden Path matches the exact approved 4/1/2, 5/7, 71.43%, 4 reminders, 7 cards, 1 owner card, zero duplicate calls, zero auto-coaching sends, and zero privacy leaks.
- Two independent builds are reproducible; candidate identity binds full product inputs; old candidates/readers/receipts remain valid; migration and rollback pass.
- No live change occurs without a one-use permission seal. The real seven-day observation either closes with a verified PASS and bounded capability active for the single customer, or truthfully rolls back and records NO-GO.

## v1.5 combined-candidate amendment — 2026-08-27

- The user superseded the v1.4-only live upgrade with one combined v1.5
  upgrade containing this qualified weekly-operations source, Channel Inbox,
  and bounded multi-customer admission.
- Todo 13 remains unchecked. Its prior v1.4 package, permission seal, and
  captured approval phrase MUST NOT be executed or reused because they bind a
  different candidate.
- Todo 13 now resumes only after
  `.omo/plans/nutricoach-v150-combined-seal-upgrade.md` produces one exact
  `QUALIFIED_PENDING_LIVE_AUTHORIZATION` v1.5 candidate and a new candidate-
  bound `AWAITING_AUTHORIZATION` package.
- Todo 14 and F1-F5 will observe and audit that exact installed v1.5 candidate,
  not the historical v1.4 candidate and not a mixed sequence of two upgrades.
- Until the new one-use approval is supplied, both v1.5 capabilities remain
  OFF and no live profile, service, Telegram, provider, customer, or watcher
  mutation is authorized.
- The replacement candidate is now sealed as
  `066a794d44861d2cd0fe8c1ea14c0050e00219b38a2d2026b389772783056dad`;
  its package is `AWAITING_AUTHORIZATION` with digest
  `a362d994b41a5d05ed2fcdafc76482e72d18ff69334cd8249eec061bff733acb`.
  Todo 13 remains unchecked until that exact new approval is supplied and the
  live action succeeds. Todo 14's seven-day observation is bound to this exact
  v1.5 candidate.
