## Verdict
**REJECT**

검토 대상 Revision artifact:
- path: `/home/cube/projects/richard/traning coach/.gjc/_session-019f8455-334a-7000-99ca-318dfd0e06b1/plans/ralplan/019f8455-334a-7000-99ca-318dfd0e06b1/stage-02-revision.md`
- sha256: `32e0f71821b5aa38913b0383f3f1e5adb8768aa05d48894484555c4981e1f971` (ralplan `index.jsonl`의 stage=`revision`, stage_n=`2` 영수증과 일치함)
- stage_n: `2`
- 독립성: Architect 산출물은 읽거나 사용하지 않았습니다.

## Claim Checks
- **이전 REJECT의 상당 부분은 실제로 보강되었습니다.** 기존 dashboard built-in route를 선택하고 plugin/sidecar를 동일 요구를 만족하는 구조 대안으로 비교했으며, Telegram-only/public web은 요구 불충족안으로 분리했습니다. 이는 내부 웹이 필수인 deep-interview 결정 및 최소 공격면 driver와 일관됩니다.
- **핵심 기존 파일은 확인되었습니다.** `customer_coaching.py`, `customer_admin.py`, `models.py`, `store.py`, `wizard.py`, `wizard_storage.py`, `customer_grounding.py`, `customer_reporting.py`, `customer_schedule.py`, `nutrition_coaching.py`, `nutrition_coaching_config.py`, `physique_checkin.py`, `physique_checkin_prompts.py`, `telegram.py`, `hermes_cli/web_server.py`, `hermes_cli/dashboard_auth/middleware.py`, `web/src/App.tsx`, `tests/gateway/test_telegram_physique_checkin.py`, `tests/test_customer_admin.py`, `HANDOFF.md`, `choi_coach_system_report.html`이 실제로 존재합니다. 계획의 신규 모듈은 아직 존재하지 않는 것이 정상입니다.
- **전송 상태 모델은 이전보다 명확합니다.** `approved → sending → accepted|failed|ambiguous`, durable pre-send claim, Telegram `message_id` receipt, ambiguous 자동 재시도 금지, 명시적 reconciliation/resend authorization, 웹/Telegram 동시 요청의 단일 claim 경쟁이 정의되었습니다. Telegram exactly-once를 주장하지 않는 점도 실제 API 한계와 맞습니다.
- **역할·일정·KPI 보강도 실제 코드 충돌을 겨냥합니다.** 현재 `customer_schedule.py`는 활성 고객에게 주말 포함 daily와 월간 task를 생성하고, `customer_reporting.py`는 달력일을 분모로 씁니다. 개정안은 평일 eligible/waived 분모와 첫 4주 monthly 생성 자체의 중단을 명시했습니다. trainer 주소/space disjointness, 복수 세션 `session_id`, supersedes, 통증 hold, 결제와 재결제의 별도 증거, 누락 시 inconclusive도 구체적입니다.
- **수용 기준과 장애 검증은 크게 개선되었습니다.** KST 경계, 중복/누락/겹침, monotonic timed rehearsal, browser Host/Origin/CSRF/session/replay/PII, 테스트 Telegram E2E, send crash window, restore/tombstone, 로그 sentinel 검사를 포함합니다. pre-mortem도 오주소, send crash, auth/CSRF, restore, version skew, 운영시간을 다룹니다.
- **대표 구현 경로 1—activation/role 확장—은 대부분 추적 가능합니다.** 현재 `CustomerSpec`에는 trainer가 없고 `RegistryDocument`는 owner/customer space만 검사하며, `set_customer_enabled`는 registry를 직접 갱신합니다. 계획은 이 경로를 `customer_coaching.py`/`customer_admin.py`/신규 activation 모듈과 테스트에 배정했습니다. 다만 runtime reload 문제는 아래와 같이 남습니다.
- **대표 구현 경로 2—웹 승인 후 실제 Telegram 전송—은 여전히 실행 불가능할 정도로 핵심 seam이 비어 있습니다.** 현재 `NutritionCoachingCoordinator`는 `draft-requests.json`을 관리하고 `telegram.py::_render_nutrition_draft`가 owner 화면에 초안만 렌더링합니다. 실제 Telegram bot 객체와 send call은 gateway의 `TelegramAdapter` 프로세스 안에 있습니다. 반면 선택된 built-in dashboard route는 별도 `hermes dashboard` 프로세스입니다. 개정안은 양쪽이 `ApprovalDeliveryService`를 호출한다고만 했을 뿐, dashboard 요청이 gateway의 live bot으로 전달되는 방식(내구성 outbound queue + gateway worker, 인증된 IPC, 또는 dashboard가 직접 bot client를 소유하는 방식), sender dependency, wake-up/polling, 프로세스 간 lock, 성공 receipt 반환 경계를 선택하지 않았습니다. 이 선택 없이는 `sending`을 누가 소유하는지와 crash injection의 실제 경로를 구현자가 추측해야 합니다.
- **대표 구현 경로 3—dashboard trust boundary—도 owner principal이 정의되지 않았습니다.** 실제 코드는 loopback bind에서 `should_require_auth(...) == False`이고 legacy launch-time bearer만 검사합니다. 이 경로는 `request.state.session`/`user_id` principal을 만들지 않습니다. `request.state.session`은 non-loopback auth gate가 켜진 경우에만 설정됩니다. 따라서 계획의 “기존 authenticated session plus owner-profile principal”은 loopback/SSH 선택안에서 현재 조합할 수 있는 predicate가 아닙니다. bearer possession을 Richard owner capability로 간주할지, console route에만 basic/OAuth identity를 강제하고 `(provider,user_id)` allowlist를 둘지 확정해야 합니다.

## Missing Evidence
### Definitely missing
1. **Dashboard↔gateway delivery process contract**: dashboard가 승인 기록만 append하고 gateway가 보내는지, IPC로 gateway를 호출하는지, dashboard가 Telegram client를 소유하는지 결정과 정확한 callsite가 없습니다. dashboard와 owner Telegram command가 “같은 서비스”를 호출한다는 문장만으로 transport/process ownership은 해결되지 않습니다.
2. **Owner-principal derivation**: loopback legacy bearer에는 user principal이 없습니다. `physique-coach` profile 선택값은 권한 있는 사람의 신원 증거도 아닙니다. owner credential provisioning, allowlist 저장 위치, session-to-owner 매핑, 실패 상태가 정의되지 않았습니다.
3. **Dashboard 실행 lifecycle**: 확인된 systemd unit `/home/cube/.config/systemd/user/physique-coach-gateway.service`는 `gateway run`만 실행합니다. dashboard 서버 unit/command/port/HERMES_HOME/build artifact 설치 및 재시작 주체가 계획에 없습니다. Phase 5의 “service/config scripts or units actually identified during implementation”은 배포 계획이 아니라 실행자에게 핵심 결정을 미룹니다.
4. **Feature-flag config callsite**: `physiqueCoach.approvalConsole`의 canonical config owner와 schema/migration이 없습니다. 기존 Hermes 기본 설정은 `hermes_cli/config.py`의 `DEFAULT_CONFIG["dashboard"]` 및 snake_case 관례를 쓰지만 이 파일은 Phase 3/5 범위에 없습니다. gateway 쪽 `nutrition_coaching_config.py`는 별도 `extra.nutrition_coaching` 경계라 dashboard flag를 대신하지 않습니다.
5. **Registry/activation hot-reload**: `TelegramAdapter._get_nutrition_coaching()`은 registry를 읽어 coordinator를 캐시합니다. 서비스 기동 뒤 `customer_admin enable`, 주소 변경, revoke/delete가 일어나도 coordinator route가 갱신되지 않습니다. 개정안은 restart 또는 version-aware reload/invalidation 계약과 acceptance를 지정하지 않았습니다.
6. **Revoke/delete의 실제 상태 의미**: “queued/approved/sending/ambiguous마다 expected state를 명세하고 테스트”가 acceptance로만 남았고 그 expected state가 계획에 없습니다. 특히 revoke가 Telegram API 호출 중 들어온 경우 취소 불가능한 send를 어떻게 기록하는지, append-only 원본과 물리 삭제를 어떻게 양립시키는지, retention 기간/backup purge 시점/삭제 완료 증거가 확정되지 않았습니다.
7. **원자료 추적성**: deep-interview spec의 정확한 경로는 stage-01에서 확인되지만 RTF `2026-07-21` 이후 원자료와 승인 PDF의 path/version/hash는 여전히 없습니다. 프로젝트 경로에서 해당 RTF/PDF를 찾지 못했습니다. “private location에 복사하거나 hash/source location 기록”은 산출물 위치와 누락 시 차단 기준을 정하지 않습니다.
8. **재현 가능한 명령과 rollout gate**: 검증 범주는 좋지만 profile venv/PYTHONPATH, Hermes pytest, frontend test/build, browser E2E의 정확한 실행 명령과 테스트 파일이 아직 “may be added” 상태입니다. schema handshake를 pre-mortem에서 언급하지만 배포 중 호환 버전을 판정하는 명령/receipt와 rollback rehearsal acceptance도 없습니다.

### Thin but possibly resolvable
- `CustomerSpec` registry의 mutable rewrite와 “모든 identity/event는 append-only” 원칙의 경계가 불명확합니다. registry를 projection으로 둘지 identity change도 event로 둘지 명시하면 해소됩니다.
- dashboard route가 profile runtime package를 어떻게 import/resolve하는지 명시되지 않았습니다. gateway는 현재 `workspace/checkin_cli`를 `sys.path`에 직접 추가하므로 dashboard에도 안정적인 package seam이 필요합니다.
- frontend test는 “existing convention”으로만 적혀 있습니다. 현재 발견된 frontend tests가 대부분 `web/src/lib/*.test.ts`이므로 page behavior/browser security를 어느 runner에서 검증할지 지정해야 합니다.

## Approval Boundary
- 진행 가능: Phase 0의 읽기 전용 source inventory, 현재 callsite/정책 gap matrix, provider 정책 증거 수집, token epoch 확인, RTF/PDF 식별과 hash 기록.
- 제한적으로 설계 가능: append-only event schema와 순수 KPI projection의 상세 설계/fixture 초안.
- 승인되지 않음: dashboard/approval/delivery 구현, 실제 고객·trainer 등록 또는 활성화, Telegram 테스트 발송, 서비스 배포. 핵심 process/auth/lifecycle 계약이 없어서 현재 계획으로 구현하면 보안 및 중복발송 의미가 구현자 선택에 따라 달라집니다.

## Summary
- **Clarity:** domain 단계와 상태명은 명확해졌지만 dashboard↔gateway 실행 seam과 owner principal은 불명확합니다.
- **Verifiability:** 상태·KPI·보안 시나리오는 강해졌으나 정확한 명령, revoke expected state, live process topology가 없어 end-to-end 합격 판정이 재현되지 않습니다.
- **Completeness:** 이전 callsite, KPI, privacy, pre-mortem, rollout 항목 대부분을 추가했지만 config/reload/dashboard service/source evidence가 빠졌습니다.
- **Big Picture:** 단일 고객·사람 승인·내부 웹·at-most-once 방향은 적합합니다. 다만 선택한 두 프로세스가 실제 전송을 공유하는 운영 구조가 빠져 핵심 제품 루프가 닫히지 않습니다.
- **Principle/Option Consistency:** 선택안과 drivers는 일관되고 이전 Telegram-only 대안 모순은 해소되었습니다.
- **Alternatives Depth:** built-in/plugin/sidecar 비교는 충분합니다. 선택된 built-in 안 내부의 delivery IPC/worker 대안 비교가 추가로 필요합니다.
- **Risk/Verification Rigor:** 위험 목록은 강해졌지만 핵심 위험의 실제 owner/process와 rollback 명령이 없어 완결되지 않습니다.

## Required Changes
1. **End-to-end process topology를 확정하십시오.** Dashboard route → canonical decision store → outbound executor → live `TelegramAdapter`/Bot → receipt의 정확한 순서를 선택하고 각 프로세스, queue/IPC, lock, wake-up, timeout, crash owner, 모듈 및 테스트 파일을 지정하십시오. Web과 Telegram command가 동일 claim을 경쟁하는 대표 sequence diagram과 각 fault-injection expected state를 넣으십시오.
2. **Owner 인증 계약을 확정하십시오.** (a) loopback bearer를 단일 owner capability로 명시하고 “principal” 주장을 제거하거나, (b) console route에서 basic/OAuth gate를 강제하고 profile registry의 owner와 별도 `(provider,user_id)` allowlist를 결합하십시오. 선택에 맞춰 session idle, CSRF, Origin, audit, credential provisioning/recovery 테스트를 구체화하십시오.
3. **실제 config/lifecycle callsite를 추가하십시오.** 최소 `hermes_cli/config.py`, dashboard start/bootstrap 또는 정확한 unit 파일/명령, web build artifact 설치 경로, `TelegramAdapter` registry cache reload/invalidation을 phase와 acceptance에 배정하십시오. camelCase/snake_case 및 dashboard/gateway flag 소유권도 하나로 정하십시오.
4. **Privacy 상태표를 계획 본문에서 완성하십시오.** revoke/delete가 queued/approved/sending/accepted/ambiguous일 때의 허용 전이, in-flight send 한계, tombstone 위치, raw/derived/log/backup 삭제 방식, retention 값 또는 activation-required policy field, purge 완료 evidence를 명시하십시오. Append-only audit와 삭제의 경계를 분리하십시오.
5. **입력 증거를 고정하십시오.** RTF/PDF의 exact path 또는 immutable private evidence ID/hash, traceability matrix 산출물 path, 원자료 미확보 시 launch block을 명시하십시오.
6. **검증·배포·롤백을 실행 명령 수준으로 마감하십시오.** profile/Hermes/frontend/browser suite의 정확한 command와 파일, dashboard/gateway 양쪽 시작·health·version-handshake gate, schema reader compatibility check, flag enable 순서, rollback rehearsal 및 receipt 위치를 적으십시오.
