# Architecture Review — Adaptive Nutrition Workflow, Stage 13

## Reviewed artifact
- Planner path: `.gjc/_session-019f8455-334a-7000-99ca-318dfd0e06b1/plans/ralplan/019f8455-334a-7000-99ca-318dfd0e06b1/stage-13-revision.md`
- Planner SHA-256: `604064771fc3dcc4166ddcda28c47c6a216f6f1ca807c4160fcd3333f6b5e353`

## Summary
The plan has strong release gating, source/policy/catalog pinning, correction-aware projections, a conservative numeric policy, topic-59-only control, and a deliberate at-most-one-attempt delivery posture. It is not safe to implement as written: five HIGH contract gaps permit stale or non-deterministic personalized plans, do not define the existing-outbox integration, or rely on a nonexistent withdrawal-deletion workflow.

## Claims
- The planner correctly keeps `CustomerSpec.plan` immutable and places adaptive state in a separate append-only stream (reviewed artifact: status and decision sections). This matches the current immutable `CustomerSpec` boundary in `checkin_cli/customer_coaching.py:104-145`.
- The plan’s correction-head approach is compatible with the current wizard: nutrition corrections are prefilled from the latest completed session and saved as full snapshots with a `supersedes` edge (`checkin_cli/wizard.py:568-616`, `831-862`; `tests/test_customer_nutrition_wizard.py:91-151`).
- The current pilot is an inclusive 28-day interval: `starts_on <= current <= starts_on + timedelta(days=27)` (`gateway/platforms/nutrition_coaching.py:420-432`) and reporting uses the same end boundary (`checkin_cli/customer_reporting.py:520-530`).
- Existing delivery is draft-specific, not a generic proposal outbox: `prepare_delivery` reads legacy drafts/requests and derives a `DraftSelection` before reservation (`gateway/platforms/nutrition_coaching.py:1531-1581`); transport validation requires the matching draft revision, approval event, and pending delivery ledger (`464-513`). The console is likewise bound to this coordinator lifecycle (`checkin_cli/operator_console.py:72-159`).
- Existing consent handling immediately blocks draft routing/transport (`gateway/platforms/nutrition_coaching.py:1329-1400`), but the inspected profile supplies checklist evidence fields for withdrawal/deletion and retention/backup documentation rather than a deletion process (`checkin_cli/customer_admin.py:483-505`, `1169-1232`).

## Analysis

### Stage 1 — Spec compliance
The plan directly addresses the requested safety and auditability boundaries: typed snapshot/decision/proposal contracts; correction graph failure suppression; Decimal policy and exact reconciliation; catalog-only meals; LLM fallback; topic 59 authorization; additive migration; rollback flags; and staged verification. It also correctly leaves Gates B–D disabled until the listed policy values are user-confirmed.

The remaining omissions are contract omissions, not implementation detail. The plan promises deterministic numeric authority and append-only adaptive lifecycle data, but permits a complete replacement revision without describing compiler validation. It promises no stale unsafe delivery, but only rejects stale callback payloads rather than validating the current canonical source at every state mutation. It promises reuse of the current outbox without mapping a `PlanRevisionV1` to that draft-centric outbox.

### Architecture and boundaries
The separate nutrition-plan stream is the right durable boundary. It preserves downgrade compatibility and prevents `CustomerSpec.plan` mutation. The better integration is to define an adaptive coordinator and a narrow transport reservation interface, not to synthesize legacy drafts as hidden parallel state. The adaptive coordinator must own append-only proposal/revision/approval/effective/delivery events and query a generic outbox primitive only after its own current-state validation.

Current code already demonstrates why this separation must be explicit: legacy approval is defined by a `draft_approved` canonical event and delivery state is maintained in `draft-deliveries.json`; its `DraftSelection` is reconstructed from a finalized wizard session. Those identities are not equivalent to an adaptive revision, its compiled meal slots, or its pinned policy/catalog digests.

### Antithesis and constructive synthesis
Rechecking the whole source projection for every action adds I/O and can create more held revisions. That cost is justified because the action rate is human-scale and the plan is safety-sensitive. Cache only derived views, never the authority decision; compare the rebuild digest under the same per-customer lifecycle lock immediately before approval, activation, reservation, and transport.

A broad Korean numeric-language parser is difficult to make complete. The safer option is narrower: render Meal slots and every food/serving/count from deterministic structured components, and make the LLM explanation field incapable of emitting quantity or food tokens. A full grammar is viable only if it recognizes native/Sino-Korean numbers and measure words, maps them to semantic fields, and is regression-tested against bypasses.

## Root Cause
The plan defines durable records and desired invariants in detail, but leaves four load-bearing cross-boundary contracts implicit: freshness invalidation, deterministic revision construction, adaptive delivery adaptation, and data-deletion ownership. Those gaps allow correct-looking individual components to compose into an unsafe lifecycle.

## Findings
1. **HIGH — `stage-13-revision.md:67-69` — Revalidate current sources before every adaptive lifecycle transition.** A new correction, safety hold, consent revocation, deactivation, policy/catalog replacement, or feature-epoch change can leave an old proposal internally consistent and still eligible to approve, activate, reserve, or send. Stale callback-token validation is insufficient. Define a single action precondition that reloads authority, rebuilds/validates the projection, compares source/correction/policy/catalog/epoch digests, and appends held or superseded on mismatch before any effective or delivery transition. **Reported P1.**
2. **HIGH — `stage-13-revision.md:61` — Constrain revisions to compiler-validated deterministic changes.** `PlanRevisionV1` accepts a complete replacement payload and the lifecycle exposes `edit`, but no validation binds that replacement to the policy compiler, catalog compiler, or explanation validator. A manual numeric/food edit can bypass the plan’s deterministic-authority claim. Accept only bounded typed overrides (or prohibit numeric/meal edits), derive the replacement with the pinned compiler, and reject approval unless all current validations and reconciliations pass. **Reported P1.**
3. **HIGH — `stage-13-revision.md:85` — Close Korean number-word bypasses in the explanation validator.** Unicode-digit normalization does not catch quantity phrases such as `세 끼`, `두 조각`, or `반 공기`. They can introduce unpinned quantities or servings without matching the numeric allowlist. Deterministically render meals and quantities outside LLM prose, or implement complete Korean numeral/measure-word and catalog-alias validation. **Reported P1.**
4. **HIGH — `stage-13-revision.md:12` — Specify an adaptive-to-outbox adapter contract.** Existing reservation and audit APIs accept legacy draft/session identities and require `draft_approved`; the plan supplies `PlanRevisionV1` instead. Define the exact adapter input/output and event mapping, including exact adaptive revision/digest, rendered-text digest, destination, actor, reservation, reconciliation receipt, and one canonical adaptive sent audit. Do not introduce a mutable second draft lifecycle merely to fit the old API. **Reported P1.**
5. **HIGH — `stage-13-revision.md:96` — Define the withdrawal deletion and backup-retention procedure.** The plan invokes an existing process not present in the inspected profile. Define accountable ownership; the inventory of stream/index/outbox/card/backup copies; deadline and legal-hold rule; deletion and backup-expiry mechanics; PII-free immutable deletion audit; and restore behavior. Immediate revocation must block processing/delivery independently. **Reported P1.**
6. **MEDIUM — `stage-13-revision.md:6` — Define `d_plus` from the existing inclusive pilot window.** D+1..D+28/D+29 are authoritative but the calculation is not defined. Specify `d_plus = (kst_day - starts_on).days + 1` in Asia/Seoul, reject pre-start dates, and test D+0/D+1/D+28/D+29. **Reported P2.**

## Recommendations
1. Add a coordinator-owned `validate_current_revision(action, revision_id)` precondition for approve, activate, reserve, reconcile, and send. It must atomically recheck registry activation/consent, feature epoch, live safety, date window, correction graph/source digest, policy/catalog digests, and revision invariants.
2. Replace free-form complete revision replacement with a typed operator-override request. The compiler must produce the replacement proposal, meal slots, explanation allowance set, and digest; any direct numeric, meal, or explanation mutation must fail.
3. Extract or wrap a minimal generic outbox reservation interface. Keep adaptive lifecycle events in `nutrition-plans/events.jsonl`; adapt only the final transport attempt/receipt reconciliation instead of coupling adaptive revisions to `drafts.json`.
4. Use structured deterministic rendering for food IDs, servings, meal indices, and all quantities. Limit LLM output to no-quantity rationale, or otherwise implement a complete Korean number/measure-word validator with adversarial vectors.
5. Write and operationalize the withdrawal deletion/retention procedure before Gate D; do not represent checklist documentation as a runtime deletion mechanism.
6. Define `d_plus` and exact calendar fixture boundaries before Gate A. Add tests for source changes between every operator action, direct revision tampering, Korean quantity bypasses, adapter crash points, withdrawal with backups, and date edges.

## Tradeoffs
| Decision | Recommended option | Why |
|---|---|---|
| Freshness | Rebuild-and-compare under lifecycle lock | Human-rate operations make correctness more valuable than cache savings. |
| Revision edits | Typed override then deterministic rebuild | Preserves human control without letting it bypass policy/catalog safety. |
| Delivery reuse | Narrow adapter over generic transport reservation | Retains proven no-blind-resend mechanics without legacy draft coupling. |
| LLM meal rendering | Structured deterministic renderer | Smaller and safer than attempting unrestricted Korean numeral parsing. |
| Withdrawal | Explicit retention/deletion workflow | Makes health-data removal and backup behavior auditable rather than aspirational. |

## Verification
Do not run tests for this planning review. Gate D must additionally prove source-change invalidation before each mutation, revision-tamper rejection, Korean numeral/measure-word rejection or deterministic rendering, adaptive adapter crash/reconciliation behavior, and withdrawal/deletion/backup-expiry behavior without PII.

## Architectural Status
BLOCK

## Code Review Recommendation
REQUEST CHANGES

## Verdict
**BLOCK / REQUEST CHANGES.** The concise blocker summary is: define live-state revalidation, compiler-constrained revisions, Korean-safe rendering validation, the adaptive outbox adapter, and an actual withdrawal/deletion-retention procedure before implementation proceeds beyond shadow analytics.
