I read this as a focused TDD bug fix - I’ll inspect the canonical schema and renderer, add and capture a semantic RED test, apply the smallest typed formatting fix, then run the full requested verification and report reproducible evidence.


The canonical contract confirms the real synthetic surface is the 22-field `example_answer` dataset, with the activity clarification revising `activity_rationale`. I’m adding one narrow renderer regression test against those literal canonical values first, then I’ll run only that test to preserve exact RED evidence before touching production code.


RED reproduced the screenshot mechanism exactly: the focused test failed on `목표: 유지`, and pytest captured `목표: 미입력`, `moderate · 미입력`, raw `{'status': 'none', 'items': []}`, and the false-positive health review. I’m now implementing only renderer-local enum, structured-item, restriction-label, and safety classification helpers, plus branch coverage for provided items and both tri-state safety fields.


I read this as an expanded two-defect TDD fix - I’ll add a publication-seam RED case for resolved clarifications reusing stale advisory sections, capture it before changing publication logic, then clear only those stale sections in the existing `current_index > 0` branch and include both defect suites in verification.


The second RED is isolated and exact: the publication seam reused the matching persisted advisory without calling the LLM, then failed because `확인된 내용 - 수정 전 활동 사실입니다.` remained in the post-clarification card. The fix now preserves initial advisory facts/safety at `current_index == 0`, but empties them alongside all other advisory sections only after a clarification, leaving the deterministic summary’s own health classification intact.


Both defects are GREEN: the focused reconciliation/publication file has 30 passing tests, and all seven related nutrition-onboarding modules have 131 passing tests. Final audit is now limited to hashes and reproducible diff artifacts; strict basedpyright and Ruff format are being reported against their unchanged baselines rather than “fixed” via unrelated repository-wide cleanup.


I read this as completed TDD delivery - both confirmed summary defects are fixed and verified without expanding runtime scope.

## RED → GREEN

- Canonical renderer RED captured:
  - `목표: 미입력`
  - `moderate · 미입력`
  - raw `{'status': 'none', 'items': []}`
  - false-positive health review
  - Evidence: `/tmp/st_01a00a96/red.txt`
- Stale advisory RED captured:
  - Post-clarification publication retained `확인된 내용 - 수정 전 활동 사실입니다.`
  - Confirmed LLM was not rerun.
  - Evidence: `/tmp/st_01a00a96/red-stale-advisory.txt`
- GREEN:
  - Focused reconciliation/publication tests: **30 passed**
  - All seven related onboarding test files: **131 passed**

## Fix

- Uses current canonical keys and Korean enum labels.
- Formats `none`/`provided` structured items without developer syntax.
- Includes allergies, intolerances, religious/ethical exclusions, disliked foods, and dietary preferences.
- Safety review occurs only for:
  - provided conditions or medications;
  - true/unknown pregnancy/breastfeeding;
  - true/unknown eating-disorder risk.
- After resolved clarification, deterministic summary replaces all stale advisory sections.
- Initial no-clarification advisory facts remain unchanged.
- No LLM, state-machine, authority, button, service, network, profile, or Git mutations.

## Verification

- Ruff check: passed.
- Compileall: passed.
- `git diff --check`: passed.
- Ruff format baseline audit: both before and after report the same three pre-existing unformatted files; no unrelated mass formatting applied.
- Strict basedpyright baseline audit: **44 existing errors before, 44 after**, zero regression.
- No sleeps, ignores, suppressions, TODOs, or unrelated edits introduced.

## Rendered target summary

```text
- 목표: 유지
- 활동: 보통 · 주 3회 근력 운동
- 식사: 하루 3끼
- 조리·예산: 기본 조리 가능 · 보통
- 식사 시간: 없음
- 알레르기·불내증·식품 제한: 알레르기 없음 · 불내증 없음 · 종교·윤리 제한 없음 · 비선호 식품 없음 · 식품 선호 없음
- 건강 관련 입력: 별도 검토 입력이 없습니다.
```

## Hashes

```text
8fb6ba6f855e7508c525447cdec482ceb240f8c0a5827b2ca0ce4268c6880bb0  gateway/platforms/nutrition_onboarding_reconciliation.py
f04ea498ad12a257fb1322da4c8cfd2f91fc9403f0b978617fcc00df41729209  gateway/platforms/telegram_nutrition_onboarding_runtime_publication.py
fbfa7fc39eb2644d0f35b386929d14415af9de842db8940874c20846371846f1  tests/gateway/test_nutrition_onboarding_reconciliation.py
```

Exact unified diff: `/tmp/st_01a00a96/exact.diff`
SHA-256: `a6b2c79719724ed2e39e0ea28493f57488b2df3c27a19930feb3ca671c84f23f`


I read this as a narrow recovery-path TDD fix - I’ll trace parsing, rewind, baseline validation, and publication digest behavior; capture three RED cases against the shipped legacy shape; then add only exact-prefix normalization on the customer-authorized rewind path and verify the supported UI sequence without touching live state.


The trace confirms two narrow seams: clarification replies and ordinary answers both pass through `parse_answer`, while the legal `수정` callback rewinds only the final field (`schedule_constraints`, cursor 21) through `_rewind_collection`. Publication payload equality includes the rendered body digest, so a corrected body would advance generation only when `_publish` is invoked; deployment alone does not proactively publish. I’m adding RED coverage at those exact seams now.


RED is confirmed at all three layers: the parser returns the full sentence, rewind leaves the invalid enum and old rationale untouched, and real `attest_baseline` raises the expected Pydantic enum validation error. I’m implementing one exact marker parser (`활동 수준: <known label>. `), reusing it in parsing and only during a cursor-21 schedule rewind; unmatched prose remains unchanged and therefore fail-closed.


The focused recovery path is GREEN, including real baseline attestation from a temporary service root. Publication inspection also confirms restart behavior: waiting-session recovery calls `_publish`; a body-digest change from durable generation 24 yields generation 25, while an identical payload reuses generation 24 and does not duplicate the card. Deployment therefore republishes only if rendering changed, and it does not normalize persisted answers until the customer uses `수정`.


Final verification is complete: 136 related onboarding tests pass, Ruff/compile/diff checks pass, strict type diagnostics are unchanged at 237 baseline vs 237 current, and formatter status is unchanged at the same three pre-existing files. The minimal driver validates `moderate`, baseline model acceptance, full rationale preservation, and corrected Korean rendering without any service, profile, network, Telegram, provider, evidence, candidate, or Git mutation.


I read this as completed follow-up TDD delivery - exact legacy activity recovery is implemented and fully audited.

## RED → GREEN

RED evidence:

- Parser returned the entire clarification sentence instead of `moderate`.
- Schedule rewind retained the invalid enum and old rationale.
- Real baseline attestation failed with Pydantic’s `activity_category` enum error.

Artifacts:

```text
/tmp/st_01a00a96/followup/red-parse.txt
/tmp/st_01a00a96/followup/red-recovery.txt
```

GREEN:

- Focused recovery tests: **4 passed**
- All related onboarding tests: **136 passed**

## Behavior

- Exact choices such as `보통` still map to `moderate`.
- Only the exact shipped marker `활동 수준: <known label>. ` is recognized.
- Arbitrary or unknown prose remains unchanged and therefore fails closed.
- Customer-authorized cursor-21 rewind:
  - converts the legacy category to `moderate`;
  - moves all trailing text into `activity_rationale`;
  - preserves prior answers;
  - removes only `schedule_constraints`;
  - clears reconciliation;
  - returns collecting at cursor 21.
- Resubmission produces a baseline-valid canonical answer set and corrected Korean summary.
- No new LLM invocation, authority expansion, state transition, or direct migration path was added.

## Supported live UI sequence

1. Deploy/restart.
2. Startup recovery calls `_publish` for waiting activation sessions.
   - Changed rendered body digest: generation 24 advances to 25 and a replacement card is published.
   - Identical body digest: generation 24 is reused; no duplicate card.
   - This follow-up alone does not normalize persisted answers during startup.
3. Customer presses the latest **수정** button.
4. Existing authorized callback rewinds to `schedule_constraints`; exact legacy activity data is normalized during that rewind.
5. Customer resubmits the schedule answer.
6. Existing reconciliation/publication flow renders the corrected card.
7. Customer confirms normally.

The fix adds no provider call. Tests and driver used no LLM or live systems.

## Driver result

```text
parser=moderate
baseline_activity=moderate
baseline_rationale=주 3회, 회당 60분 정도의 중간 강도 근력운동을 희망합니다. 평소 걷기·이동은 하루 약 6,000~8,000보 수준입니다.
- 목표: 유지
- 활동: 보통 · 주 3회, 회당 60분 정도의 중간 강도 근력운동을 희망합니다. 평소 걷기·이동은 하루 약 6,000~8,000보 수준입니다.
- 식사: 하루 3끼
- 조리·예산: 기본 조리 가능 · 보통
- 식사 시간: 없음
- 알레르기·불내증·식품 제한: 알레르기 없음 · 불내증 없음 · 종교·윤리 제한 없음 · 비선호 식품 없음 · 식품 선호 없음
- 건강 관련 입력: 별도 검토 입력이 없습니다.
```

## Verification

- Ruff check: passed
- Compileall: passed
- `git diff --check`: passed
- Related tests: 136 passed
- Strict basedpyright: **237 baseline / 237 current**, zero regression
- Ruff format status: identical baseline/current; same three pre-existing unformatted files
- No live profile, service, network, Telegram, provider, candidate, evidence, or Git mutation

## Hashes

```text
8afb45c5cca082fd85cf07ab43dc5d1062c34678fd268a5722e313ce35cffd8b  gateway/platforms/telegram_nutrition_onboarding_copy.py
3c24d49d656c623edfb95fcfbc7fb0f92365fc123420df66f733f9dbe39d704f  gateway/platforms/telegram_nutrition_onboarding_runtime.py
cc89f68a52c538b3730840b49d1afb0b9762745a64c3e2a7f8a7ead597d4d5f8  tests/gateway/test_telegram_nutrition_onboarding_copy.py
ce57d8240aef145ff9956f65b60b5e8b66316e2527f6845bdfa3a21510509321  tests/gateway/test_telegram_nutrition_onboarding.py
```

Exact unified diff:

```text
/tmp/st_01a00a96/followup/exact.diff
SHA-256 cb15bb8067e665eaaf5a5d0b0d70a8058e0986962a54917b708b9a5e5e9d9a87
```