## Verdict
**ITERATE**

## Claim Checks

- **Intent and canonical fallback:** The plan preserves the binding choice: genuinely open Korean connective prose rather than a finite template/variant catalog. It locks all truth-bearing content behind local placeholders, rejects a response document-wide, falls back to canonical bytes, and honestly states that lexical validation is strong best effort rather than a semantic theorem. This part is consistent and actionable.
- **All four surfaces:** All four named surfaces are mapped to real code. Daily and weekly renderers exist in `gateway/platforms/telegram.py`; the dualcoachtest card has the stated `현재 판단` / `검토 필요` grammar in its profile-local `adaptive_nutrition.py`; the physique card has the stated code-heavy grammar and exact final status line in its separate profile copy. The proposed slot boundaries preserve headings, actions, buttons, envelopes, and final status.
- **Daily representative path:** The current save route calls `_saved_physique_coaching_feedback`, renders `_nutrition_daily_text(snapshot, feedback)`, and the explicit replay route calls `_render_physique_feedback_replay`. The proposed `FinalizedCoachingArtifact` is a sound way to bind the trusted snapshot to the internal finalized event identity. However, the plan simultaneously says to remove the finalized-render replay route and that every replay remains canonical/no-call; the replacement call path is not specified.
- **Weekly representative path:** The current scheduler rerenders a due weekly report and calls `reserve_customer_task_delivery`; the existing receipt deliberately exposes only digests, so a new locked loader for exact durable body/destination is justified. However, `load_prepared_customer_task_delivery(profile_root, receipt)` cannot by itself prove that stored registry/config pins equal the current gateway authority, because those current digests are not arguments and the profile-local module does not own gateway config. The caller-side comparison or expanded API is missing.
- **Adaptive representative path:** The proposed authority/publication lock ordering and binding-digest revalidation fit the existing `AdaptiveOperatorService` locks and pins. The actual gateway has two fresh-card publication paths: callbacks through `_handle_adaptive_review_callback`, and typed operator-note results through `service.handle_text` → `_send_adaptive_operator_result`. The exact symbol plan covers only the callback path. The text path can currently render/edit a `status == "card"` payload without the proposed coordinator or pending-card commit, so the surface is not fully covered.
- **One direct provider / one request:** Fixed OpenAI endpoint/model, `max_retries=0`, one non-streaming call, no repair/retry/router, and terminal canonical outcomes are correctly stated. But the exact constructor in the plan does not meet its own isolation claim. Installed `openai/_client.py` reads `OPENAI_ORG_ID`, `OPENAI_PROJECT_ID`, and `OPENAI_WEBHOOK_SECRET` whenever those constructor arguments are omitted, and the default HTTP client may honor proxy environment variables. The plan also omits an exact API output-token bound. Therefore “only `OPENAI_API_KEY` is read” and “no proxy may be reached” are not currently implementable from the specified constructor.
- **Privacy:** Raw canonical bodies, values, dates, measurements, notes, destinations, and identities are excluded, and `store=False` plus metadata-only journals are strong controls. However, the wire contract sends `semantic_ids`, `action_ids`, and placeholder tokens while examples use meaningful local names such as `P_DAILY_PARTIAL` and `A_OPERATOR_REVIEW_DECISION`. Unless wire tokens are explicitly opaque per-attempt aliases, the request can reveal missingness, decision/action type, or other domain state despite the “no predicate/decision/action/safety state” promise.
- **Journal and shadow proof:** Shadow correctly returns canonical only and requires proof through the coordinator and all four paths. The journal schema, claim behavior, retention, permissions, and no-content rule are detailed. A load-bearing crash protocol is nevertheless missing: the plan records terminal `selected` only after a daily edit, weekly reservation, or adaptive pending append, but those destination writes are in a different durability domain from the journal. A crash or journal append failure between the two can leave selected bytes visible/durable with only `attempt_started`; later claim expiry would record canonical even though selected bytes may be sent/recovered. Conversely, recording selection first requires a defined restart behavior because selected text is intentionally not stored. The current plan cannot uphold both canonical-on-journal-error and the claimed terminal semantics without a precise two-phase/reconciliation design.
- **Migration preflight:** Both real configs exist and currently contain the obsolete `coaching_feedback_enabled` key; one profile has an enabled valid physique bridge and the other has the key under a disabled physique block, matching the migration cases the plan calls out. The owner/API/script/reason codes and pre-parser-removal ordering are useful. Plain `yaml.safe_load` accepts duplicate mapping keys by last-value-wins, so it cannot prove absence of a shadowed legacy key unless duplicate-key rejection is added. The exact disabled/enabled postprocessor YAML schema is also absent.
- **Attribution and rollout:** The ADR/guide attribution is explicit, commit-pinned, and clearly says no material was copied. Default-off, shadow-first, human-approved, surface-by-surface promotion and rollback intent are sound. The concrete surface/profile enablement matrix and rollback stop/wait/config/restart sequence remain underspecified; config is parsed at `TelegramAdapter.__init__`, so editing config does not immediately disable an already-running coordinator.
- **Referenced files:** All material existing files named in the plan were verified, including both profile copies and their tests/configs. `gateway/platforms/korean_expression.py`, its tests, the audit script, and ADR-021 are correctly marked new; the ADR directory does not currently exist. The supplied plan SHA-256 was not independently recomputed by the available read-only file tool.

## Missing Evidence

Definitely missing or too thin for execution:

1. Exact `korean_expression_postprocessor` YAML schema, allowed keys/types, disabled/shadow/enabled examples, per-surface gates, and the exact fail-closed behavior for every malformed/unknown combination.
2. A durable, crash-consistent state machine across the feature journal and each destination write, including fsync order, late worker fencing, idempotent restart, and how `selected`, `commit_failed`, and `publication_failed` may coexist.
3. Explicit opaque wire aliases for semantic/action/placeholder identifiers and a serialized-request privacy acceptance test.
4. Coverage of adaptive cards created by typed operator-note input, not only callback-generated cards.
5. An exact prepared-weekly loader/caller contract that compares stored pins to current registry/config authority without rerendering or calling the model.
6. Strict duplicate-key YAML handling in migration preflight.
7. Repository-compliant verification commands: `AGENTS.md` requires `scripts/run_tests.sh`, but every proposed test command invokes `pytest` directly; a final full-suite gate is also absent.

## Approval Boundary

No product implementation, config cutover, live calls, or promotion is approved from this revision. The planner may retain the chosen free-prose architecture, four slot definitions, fixed OpenAI-only provider decision, default-off/shadow rollout concept, attribution, and file map. Execution should wait for the required contracts below to be added.

## Summary

- **Clarity:** High at the conceptual/surface level; insufficient at config, wire aliasing, restart, and secondary adaptive entry paths.
- **Verifiability:** Strong adversarial-test intent, weakened by direct-`pytest` commands, no full-suite gate, and an unprovable cross-store journal claim.
- **Completeness:** All requested themes are discussed, but several load-bearing implementation paths are incomplete.
- **Big Picture:** Presentation-only authority boundaries and default-off rollout fit the system; cross-store durability and runtime rollback need reconciliation with that model.
- **Principle/Option Consistency:** Free prose plus canonical fallback is consistent. “Only API key/no proxy,” “journal error selects canonical,” and “all fresh adaptive cards” conflict with specified implementation details.
- **Alternatives Depth:** Rejected finite composition and whole-body rewriting are well justified. Journal-before-destination versus destination-before-journal, and prepared-pin verification options, need explicit treatment.
- **Risk/Verification Rigor:** Strong semantic/privacy test inventory and honest residual-risk statement; durability, Unicode-format, transport-environment, and migration-parser risks need added gates.

## Required Changes

1. **Specify the exact config contract.** Provide complete disabled, shadow, and enabled YAML examples; exact allowed key sets/types; mode and per-surface enumeration; fixed provider fields; and profile-by-profile promotion/rollback values. State how malformed disabled and malformed enabled blocks affect startup, rows, and client construction.
2. **Fix direct-client isolation.** Explicitly neutralize SDK reads of organization/project/webhook environment variables, supply an HTTP client with `trust_env=False`, disallow redirects/alternate hosts, pin TLS verification behavior, and set an exact completion-token limit. Add tests with hostile `OPENAI_ORG_ID`, `OPENAI_PROJECT_ID`, `OPENAI_WEBHOOK_SECRET`, `OPENAI_BASE_URL`, and proxy variables proving only the explicit endpoint and API key are used and only one request occurs.
3. **Make wire identifiers opaque.** Map every local semantic/action/placeholder identifier to random or HMAC-derived non-semantic wire aliases; do not send names like `PARTIAL`, `REVIEW`, `SAFETY`, field labels, or action meanings. Test the full serialized request against forbidden domain terms and every raw identity/value.
4. **Define the durable attempt protocol.** Require `attempt_started` to be locked, flushed, and fsynced before the provider call. Define accepted `(state, outcome)` transitions and a cross-store protocol for daily edit, weekly reservation, and adaptive pending append. Resolve crashes and journal-write failures at every boundary without republishing selected bytes, making a second provider call, or falsely recording canonical. Include crash-injection tests for each boundary and a late-thread result that cannot commit after deadline.
5. **Complete the prepared-weekly contract.** Define `PinnedScheduledDelivery` fields and whether `load_prepared_customer_task_delivery` accepts expected registry/config/destination digests or returns pins for an explicit gateway comparison. Specify the exact existing-`prepared` branch before any report build/postprocessing, and prove it uses durable body/destination, current authority, zero rerenders, and zero model calls.
6. **Cover every fresh adaptive-card producer.** Route both callback cards and typed note-edit cards (`_send_adaptive_operator_result`) through the same presentation preparation and `validate_and_mark_presented_card` commit. Define how a consumed callback is revalidated, how a typed-input session supplies the binding identity, and whether authority-race failure means canonical commit or deliberately no edit. Test both profile grammars on both paths.
7. **Resolve daily replay behavior.** Either preserve the explicit replay request with a canonical-only renderer or deliberately remove the command and document its new behavior. Do not both delete `_render_physique_feedback_replay` and promise canonical replay without a replacement. Test first save, duplicate callback, explicit replay, restart replay, and generic-conversation non-entry with zero postprocessor calls after the first claim.
8. **Strengthen validator and migration specifics.** Define rejection of Unicode bidi/zero-width/format controls and non-approved scripts while retaining open Korean prose. Make the audit script reject duplicate YAML keys (including nested mappings), define bounded input/file handling, and state the exact build/config/preflight/parser-removal order with expected redacted receipts for both current profile shapes.
9. **Correct verification and release gates.** Replace direct `pytest` invocations with `scripts/run_tests.sh`, verify marker registration/collection through the wrapper, add the full Hermes suite before promotion, and keep both profile suites explicit. Bound live proof with exact request/output token budgets and assert 48 calls means 48 successful single requests with no hidden SDK retry. Add rollback tests that stop new attempts before waiting out in-flight claims, then restart with disabled config.
