# RALPLAN — 듀얼코치 단일 고객 유료 파일럿 (Bounded Planner Stage 9, Revision)

## Summary
Elevate the existing 최코치/Hermes coaching base into the smallest safe dual-coach pilot for **one external paid customer** (non-shop): KRW 150,000/month via bank transfer, a 12-week plan written up front, and only the first 4-week loop activated — adaptive customer check-in (60–90s), trainer 30-second session record, per-customer isolation, AI evidence draft → Richard review/edit/approve/send (zero auto-send), weekly summary, and KPI judgement (renewal, check-in ≥80%, satisfaction ≥8/10, operator time ≤60 min/week) — operated over Telegram plus a Richard-only private loopback web screen. This revision (stage 9) applies the Architect BLOCK and Critic ITERATE corrections without scope inflation: the safety predicate is corrected everywhere (consent absent/not granted **or a safety signal present** → no normal draft; owner notified with reason; zero customer send; human review + professional-referral guidance); the implementation-owner map is corrected to the files that actually own adaptive transitions, canonical events, and Telegram send paths; one trainer ingress is defined; monthly automation stays dormant and pilot automation stops after four weeks unless manually extended; and verification gains stopwatch dry runs plus loopback/token/bind checks. Reuse existing registry/schedule/append-only store/grounding/Telegram routing. Explicitly no generic Hermes redesign, no production-wide systemd/auth, no browser framework, no crash-consistency theorem, no generic concurrency work, no exact deployment scripts, no multi-customer expansion.

## Principles
1. Human approval is absolute: AI drafts evidence; it never sends to the customer. Zero pre-approval sends.
2. Isolation is absolute: customer data/context/Telegram addresses never mix with personal coaching; append-only with `supersedes`, never overwrite.
3. Smallest safe surface: only the first-4-week daily/weekly loop runs; the 12-week plan exists as grounding context, not active features; monthly scheduling/reporting stays dormant during weeks 1–4; all pilot automation stops after week 4 unless a human explicitly extends it.
4. Safety bundle gates activation: any unverified safety item = real customer stays disabled.
5. One KPI source of truth: renewal/check-in/satisfaction/operator-time judged from a single record origin.
6. Loopback-only operator web: 127.0.0.1 bind or SSH tunnel, Richard-only, no external exposure, no auth framework.
7. Medical boundary: pain/disorder/eating-risk/drug/extreme-manipulation signals **present** in a record stop normal feedback, hold the draft, notify the owner with the reason, and escalate to human review + professional referral. (Existing contract, `customer_grounding.py`: draft is refused when `safety_signals` is non-empty **or** consent is not granted — this plan matches that predicate verbatim.)

## Intent Diff (reconciliation with deep-interview spec)
- Spec Round 2 correction honored: 3-customer launch → **1 paid customer pilot**.
- Spec Round 4 acceptance honored: private web console is **in** first-pilot scope, but its core is strictly `evidence view → edit → approve → send`.
- Spec Rounds 10–11 closure honored: 12-week plan is written before start; only daily/weekly loop features activate in weeks 1–4; monthly and post-pilot automation stay off by default.
- Lateral-panel guardrail honored: web must not become a separate product; no multi-customer/long-term features.
- Spec dual-record flow honored: the friend-trainer completes a 30-second session record (session done, performance, intensity vs plan, pain, operator note) right after PT, joined to the same customer+date.
- Architect correction honored: the draft gate is "consent absent/not granted **or safety signal present** → no normal draft," never the inverted absence-based reading.
- Critic corrections honored: owner map names the real implementation owners; trainer ingress/authorization/trigger is defined; pilot-mode schedule boundary is testable; verification is observable (stopwatch + HTTP).
- All confirmed outcomes from the assignment are preserved verbatim in scope and acceptance criteria.

## Decision Drivers
- HANDOFF: registry empty (0 customers), intentionally disabled to prevent accidental customer messages; onboarding order (inactive draft → plan review → consent → validate → enable) already mandated.
- HANDOFF: past Telegram token exposure → rotation required before any customer activation.
- Spec technical context: `customer_reporting.py` lacks satisfaction/payment/renewal/operator-time measurement — the KPI gap is the main additive build, and it must be fed by canonical append-only events, not by turning a reporting projection into storage.
- Spec technical context: current HTML is a static report/binder, not a live console — a new minimal loopback screen is required but must stay minimal.
- Implementation simulation (Critic): adaptive flow transitions live in `checkin_cli/wizard.py`; canonical event types/payloads in `checkin_cli/models.py`; Telegram step rendering/action decoding in `gateway/platforms/physique_checkin.py`; draft rendering, scheduled delivery, callback interception, and sends in `gateway/platforms/telegram.py`; the registry (`customer_coaching.py`) currently has only customer and owner Telegram addresses, and `customer_schedule.py` emits `monthly` tasks for every enabled customer — the owner map and pilot boundary must be built on these facts.
- KPI conjunction (all four must pass) and ≤60 min/week operator budget push the design toward short confirmations on normal days and detailed evidence feedback only on change/problem days.

## Options
- **O1 Operator surface**: (a) minimal stdlib loopback HTTP screen bound to 127.0.0.1 with a single local token — **recommended**; (b) Telegram-only approval — rejected, spec requires the web screen; (c) framework dashboard with global auth — rejected, over-scope.
- **O2 Adaptive check-in**: (a) rule-based branching where anomaly fields (sleep/condition/performance drop) open only related follow-ups — **recommended**; (b) model-driven dynamic questioning — deferred (unpredictable latency/cost, risks 60–90s budget).
- **O3 KPI origin**: (a) canonical typed pilot events (payment/renewal, satisfaction, operator-time) defined in `checkin_cli/models.py`, appended through the existing `EventStore.append_wizard_event` exactly-once mechanism into the same per-customer `events.jsonl` stream, with `customer_reporting.py` kept as the projection/judgement layer over that single stream — **recommended**; (b) manual spreadsheet — rejected, violates single-source requirement; (c) treating `customer_reporting.py` as storage — rejected, it is a projection module.
- **O4 Draft approval storage**: (a) distinct events for AI draft / edited final / approval / send with timestamps — **recommended** (auditability is an acceptance criterion); (b) single overwritten field — rejected, violates append-only.
- **O5 Append mechanism**: (a) reuse the canonical `EventStore.append_wizard_event(Event)` path (lock + dedupe_key exactly-once + append + view rebuild) for every new pilot event type; `store.py` gains **no** generic append path — **recommended**; (b) add a generic append API to `store.py` — rejected, unbounded surface with no pilot need.
- **O6 Trainer ingress**: (a) exactly one trainer Telegram address bound to the pilot customer in the registry; strict exact-triple authorization; trainer-initiated command/button trigger — **recommended**; (b) configured/scheduled post-session prompt — rejected for the pilot (extra scheduling surface, no spec demand); (c) reusing the customer or owner address — rejected, breaks authorization and isolation.
- **O7 Pilot schedule boundary**: (a) pilot-mode projection inside `customer_schedule.py` (the single due-task source): weekday `daily` + `weekly` only during the active window, `monthly` suppressed, nothing after day 28 KST without an operator-set extension date — **recommended**; (b) suppressing monthly at the Telegram delivery site only — rejected, leaves a second due-task truth.

## In Scope
- One external paid customer: KRW 150k/month bank transfer, first 4-week pilot of a 12-week plan.
- Adaptive weekday customer check-in (60–90s; normal days short, anomaly days open only related follow-ups).
- Trainer 30-second session record (session done, performance, intensity vs plan, pain, operator note) submitted from exactly one registry-bound trainer Telegram address via a trainer-initiated command/button, joined to the same customer+KST date.
- AI evidence draft showing 12-week plan, recent records, trainer records, approved 최코치 knowledge (≤5 excerpts), and judgement rationale; **no normal draft when AI consent is absent/not granted OR any safety signal is present**; a present safety signal additionally notifies the owner with the hold reason, sends nothing to the customer, and routes the record to human review with professional-referral guidance.
- Richard review/edit/approve/send on Telegram **and** a private loopback web screen; draft/final/edit history stored as distinct append-only events; 0 pre-approval sends.
- Weekly summary: check-in rate, key trends, keep-behaviors, change-behaviors, next decision point.
- KPI single source: scheduled vs completed check-ins, satisfaction, operator work time, first payment and actual renewal; 4-week judgement = conjunction of renewal done, check-in ≥80%, satisfaction ≥8/10, ≤60 min/week.
- Pilot-mode scheduling: weekday daily + weekly tasks only in weeks 1–4; monthly scheduling/reporting dormant; all pilot automation stops after KST day 28 of the pilot unless Richard manually records an extension date.
- Safety bundle: token rotation, mis-send prevention with test account, consent versioning + AI provider terms check (training use/retention/region/sub-processors), withdrawal/deletion/backup/log-retention procedures documented and tested, manual fallback mode without duplicate sends.
- Regression: personal check-in and Hermes wrapper suites stay green.

## Out of Scope
- Business registration, PG, auto-billing; multi-customer/multi-trainer/role accounts; B2B/SaaS; customer web portal; monthly auto-report delivery; auto knowledge refresh; AI auto-send; **generic Hermes redesign; production-wide systemd or auth changes; browser framework; crash-consistency theorem work; generic concurrency work; exact deployment scripts; any multi-customer expansion**; shop DB/brand/payment/facility recruitment; any merge/replacement of the personal coaching flow; configured/scheduled trainer prompts (trainer flow is trainer-initiated only in the pilot).

## File-Level Changes (bounded implementation-owner map — reuse first, no redesign)
- `checkin_cli/models.py` — canonical pilot event contract: new `EventType` members (`TRAINER_SESSION_RECORD`, `PAYMENT_RECORD`, `SATISFACTION_RECORD`, `OPERATOR_TIME_RECORD`, `DRAFT_CREATED`, `DRAFT_EDITED`, `DRAFT_APPROVED`, `DRAFT_SENT`) and minimal frozen typed payload models (trainer session fields; payment amount/date/period; satisfaction score; operator minutes/task; draft text refs and editor identity). No generic dict payloads.
- `checkin_cli/wizard.py` — adaptive nutrition check-in branching transitions (normal-day short path; sleep/condition/performance anomalies open only related follow-ups) and the trainer session flow transitions (5 fields, ≤30s budget, KST-date stamped at finalize).
- `checkin_cli/wizard_models.py` — included **only because a distinct trainer flow is chosen** (O6a): exactly one new `WizardFlow` member for the trainer session plus its typed session state. No other change.
- `checkin_cli/customer_coaching.py` — registry: add optional `trainer: TelegramAddress | None` to `CustomerSpec`, set for the one pilot customer; validation that the trainer address differs from the customer and owner addresses; keep plan/consent/validation models otherwise intact.
- `checkin_cli/customer_admin.py` — CLI: bind the trainer address during onboarding; record payment/satisfaction/operator-time events (appended via the canonical path); an explicit `extend` command that records the pilot extension date; keep add/consent/enable gating and registry validation.
- `checkin_cli/customer_schedule.py` — pilot-mode projection (O7a): emit weekday `daily` and `weekly` tasks only while the KST date is inside the active window (`plan.starts_on` + 28 days, or the operator-set extension date); never emit `monthly` during pilot mode; emit nothing after the window without an extension; keep claim/no-duplicate semantics unchanged.
- `checkin_cli/customer_grounding.py` — assemble the evidence draft (plan, trends, trainer session records, approved knowledge ≤5 excerpts, rationale). Predicate stays exactly the existing correct one: return no draft when consent is not granted **or** any safety signal is present; on a present signal, surface the hold reason so the adapter can notify the owner.
- `checkin_cli/customer_reporting.py` — weekly summary + 4-week KPI judgement projected from the same per-customer `events.jsonl` stream, now including the new typed pilot events.
- New `checkin_cli/operator_console.py` — stdlib loopback HTTP screen: bind 127.0.0.1 only (refuse any non-loopback bind), one local token (missing or wrong token → request rejected), draft queue view → edit → approve → send wired to the **same** approval/send path as Telegram; no framework, no external exposure.
- `checkin_cli/store.py` — **explicitly unchanged: no generic append path is added.** The canonical append-only stream mechanism is the existing `EventStore.append_wizard_event(Event)` (record lock + `dedupe_key` exactly-once + append + deterministic view rebuild). Every new pilot event is constructed as a schema-conformant typed `Event` from `models.py` and appended through that method; reporting and grounding consume the same stream. (O5a)
- `gateway/platforms/nutrition_coaching.py` — coordinator: resolve and strictly authorize the trainer route (incoming exact `(user_id, chat_id, topic_id)` triple must equal the pilot customer's bound trainer address; the customer's own address and any foreign sender get a fixed refusal and no state change); trainer completion → append `TRAINER_SESSION_RECORD` via the canonical path; keep owner-only draft request tokens and the `safety_held` completion notice, now carrying the hold reason.
- `gateway/platforms/physique_checkin.py` — step rendering/action decoding for the adaptive nutrition steps and the trainer session steps; extend the `_STEP`/`_ACTION` decoding bounds accordingly; render the safety-hold reply.
- `gateway/platforms/telegram.py` — route the trainer command/button and callbacks to the coordinator; owner draft/approve/send callbacks; scheduled delivery honoring pilot-mode tasks (the monthly rendering branch stays dormant for pilot customers); owner safety-hold notification with the reason; no customer send except the approved path.
- Docs: safety/ops runbook (withdrawal, deletion, backup, retention, manual fallback, provider-terms checklist) + one ADR.

## Sequencing & Dependencies
1. **Safety Gate 0 (blocks everything customer-facing)**: rotate Telegram token; `registry validate`; isolation audit; test-account mis-send prevention check; provider terms vs consent text alignment.
2. Canonical event contract (`models.py`) + registry trainer address (`customer_coaching.py`) + unit tests. Depends on Gate 0 for test fixtures only.
3. Adaptive check-in branching + trainer session flow across `wizard.py`, `wizard_models.py`, `physique_checkin.py`, `nutrition_coaching.py`, and `telegram.py` routing + tests (flow-structure timing budgets, trainer authorization, same-customer+KST-date join).
4. Grounding evidence draft incl. trainer records + draft/edit/approve/send audit events; predicate tests: (a) consent granted + no safety signal → draft produced; (b) consent absent → no draft; (c) any safety signal present → no normal draft + owner notification with reason + zero customer send; verify 0 pre-approval sends.
5. Pilot-mode schedule projection in `customer_schedule.py`: weekday daily/weekly only, monthly dormant, hard stop after KST day 28 without extension, extension date re-enables; claim semantics unchanged.
6. Loopback operator console (minimal) wired to the same approve/send path as Telegram; non-loopback bind and missing/wrong token rejection tests.
7. Weekly summary + KPI judgement report.
8. Runbook + manual fallback drill (model/web/Telegram outage → human operation, no duplicate sends on recovery).
9. End-to-end dry run with a test account including stopwatch runs and loopback HTTP checks; only after every safety acceptance criterion passes, follow the mandated onboarding order to enable the real customer.
Dependencies: 2→3,4; 4→6; 3,4→7; 5 before any enabled dry run; all →9. Personal-flow regression suite runs after every step.

## Acceptance Criteria (testable)
- AC1 Customer registered as inactive draft; independent storage root, Telegram address, consent record, and 12-week plan verified before `enable`; activation impossible otherwise.
- AC2 Token rotated; with a test account, cross-customer/personal mis-send count = 0 and permission boundaries verified.
- AC3 Weekday check-in completed in 60–90s in a stopwatch dry run; on normal days zero unnecessary detail questions open.
- AC4 On sleep/condition/performance anomalies, only related follow-up questions open.
- AC5 Trainer record (done, performance, intensity vs plan, pain, operator note) completed in ≤30s in a stopwatch dry run.
- AC6 Customer check-in and trainer record join on the same customer+KST date; 0 records from other customers or personal data.
- AC7 Draft displays 12-week plan, recent records, trainer records, approved knowledge excerpts, and rationale; **consent absent/not granted OR any safety signal present → no normal draft.**
- AC8 Richard can view evidence, edit, approve, send from the loopback web screen and Telegram.
- AC9 Pre-approval customer sends = 0; AI original, edited final, and edit history stored as distinct events.
- AC10 Normal days produce short confirmation; change/problem days produce detailed feedback.
- AC11 Weekly summary contains check-in rate, key trends, keep/change behaviors, next decision point.
- AC12 Single source yields scheduled denominator/completed count, satisfaction, all operator work time, first payment, actual renewal; 4-week judgement = logical AND of renewal, ≥80%, ≥8/10, ≤60 min/week.
- AC13 Withdrawal/deletion/backup/log-handling/retention procedures documented and tested.
- AC14 Provider training-use/retention/region/sub-processor terms checked and matched to consent version.
- AC15 Model/web/Telegram outage → manual human operation; recovery without duplicate sends.
- AC16 Personal check-in and Hermes regression suites all pass (baseline: 776 passed per HANDOFF).
- AC17 **Safety escalation**: a present pain/disorder/eating-risk/drug/extreme-manipulation signal blocks the normal draft and any customer send, notifies Richard with the hold reason, and transitions the record to human review with professional-referral guidance.
- AC18 **Pilot boundary**: during weeks 1–4 only weekday `daily` and `weekly` pilot tasks are emitted; monthly scheduling/reporting stays dormant; after KST day 28 no automated pilot task runs unless Richard manually records an extension date; the 12-week plan remains grounding-only throughout.
- AC19 **Trainer authorization**: exactly one trainer Telegram address is bound to the pilot customer; the exact trainer triple is accepted into the trainer flow; the customer's own address is rejected; any foreign sender is rejected with a fixed refusal and no state change; the trigger is a trainer-initiated command/button (no configured prompt).
- AC20 **Console hardening**: the loopback console refuses a non-127.0.0.1 bind; requests with a missing or wrong local token are rejected; view/edit/approve/send are exercised over HTTP against 127.0.0.1.

## Focused Verification
- Re-run existing baselines after each step: profile tests (75), Telegram/Hermes wrapper tests (701), core wrapper tests (109); `compileall` on touched packages.
- New targeted tests: adaptive branching (normal vs anomaly); trainer authorization (exact trainer accepted; customer address rejected; foreign sender rejected; record joins same customer+KST date); isolation join (zero cross-contamination); draft predicate three-case tests (consent granted + no signal → draft; consent absent → no draft; signal present → no normal draft + owner notice with reason + zero customer send); approve/send audit (0 pre-approval sends); KPI judgement arithmetic incl. boundary values (79%/80%, 7.9/8.0, 60/61 min); pilot-mode schedule (monthly dormant in weeks 1–4; no tasks after KST day 28 without extension; extension re-enables); loopback console refuses non-loopback bind; missing/wrong local token rejected.
- **Stopwatch dry runs** with the test account: normal-day customer check-in inside 60–90s; anomaly-day check-in inside budget with only related follow-ups; trainer session record ≤30s.
- **Loopback HTTP checks**: view the draft queue, edit, approve, and send over 127.0.0.1 (curl or stdlib client); confirm sends traverse the same approval path and produce the distinct audit events; confirm zero pre-approval sends.
- Manual drills: mis-send prevention with test account; outage→manual→recovery no-duplicate drill; withdrawal/deletion procedure walkthrough.
- Onboarding checklist execution (HANDOFF §6) as the final pre-activation gate.

## Risks & Mitigations
- R1 Token leak reuse → rotate first; assume old token compromised (HANDOFF §6).
- R2 Mis-send to wrong chat/topic → inactive-draft gating, test-account verification, claim checks before retry.
- R3 Auto-send regression → single send path behind explicit approval; audit events; tests assert 0 pre-approval sends.
- R4 Loopback screen exposure → 127.0.0.1-only bind test, local token (0600 file), wrong/missing token rejection tests, SSH tunnel doc; no external interface.
- R5 KPI source gaps → canonical typed events in `models.py` appended via the existing exactly-once path, not ad-hoc notes; judgement test with boundary values.
- R6 Scope creep (multi-customer, dashboard) → out-of-scope list enforced at review; web core limited to evidence→edit→approve→send.
- R7 Provider terms mismatch → terms checklist tied to consent version before activation (AC14).
- R8 Operator time >60 min/week → short-confirmation default; time logged per task from day 1 so breaches surface weekly.
- R9 Safety signal mishandled → grounding hard-block on present signals, owner notification with reason, human review + professional-referral path; tested (AC17).
- R10 Trainer impersonation/misroute → single registry-bound trainer address, exact-triple authorization, customer/foreign rejection tests (AC19).
- R11 Pilot overrun (automation continuing past 4 weeks or monthly firing) → pilot-mode projection in the single due-task source; hard stop without manual extension (AC18).
- R12 Append-path drift (parallel write paths) → one canonical mechanism (`append_wizard_event`), `store.py` unchanged (O5a).

## Rollback
- Keep customer `enabled=false` until all safety ACs pass; disabling is a single registry state change.
- All customer data changes are append-only with `supersedes`, so any record-level change is reversible without data loss.
- Loopback console is additive; removing it leaves the Telegram approval path intact.
- Personal coaching flow untouched; regression suites confirm no bleed.
- If the pilot must halt mid-course: disable the customer, stop schedules via existing claim semantics (no duplicate sends), retain/delete per documented retention procedure.

## ADR & Intent Reconciliation
- **ADR-1**: Adopt minimal stdlib loopback console over framework dashboard (O1a) — satisfies spec Round 4 with least surface; aligns with lateral-panel guardrail against a separate product.
- **ADR-2**: Rule-based adaptive check-in (O2a) — protects the 60–90s budget and operator-time KPI; model-driven questioning deferred.
- **ADR-3**: Canonical typed pilot events in `models.py` appended via `EventStore.append_wizard_event` into the single per-customer stream, with `customer_reporting.py` as projection/judgement only (O3a) — required for the 4-week conjunction judgement without turning a reporting module into storage.
- **ADR-4**: Distinct draft/final/approval audit events (O4a) — preserves append-only principle and AC9 auditability.
- **ADR-5**: `store.py` gains no generic append path (O5a); the existing exactly-once `append_wizard_event` is the canonical append-only stream mechanism for all new pilot event types — bounded, and it preserves the lock/dedupe/rebuild invariants.
- **ADR-6**: One registry-bound trainer address with exact-triple authorization and a trainer-initiated command/button trigger (O6a); a distinct lightweight trainer wizard flow is chosen, which is the sole reason `wizard_models.py` is in the owner map; configured/scheduled trainer prompts are rejected for the pilot.
- **ADR-7**: Pilot-mode projection inside `customer_schedule.py` as the single due-task source (O7a): weekday daily/weekly only in weeks 1–4, monthly dormant, full stop after KST day 28 unless an operator-set extension date exists; the 12-week plan remains grounding-only.
- **Reconciliation**: the plan preserves every confirmed outcome (1 external paid customer, KRW 150k, 12-week plan, 4-week pilot, adaptive check-in, 30s trainer record, isolation, evidence draft, Richard review/edit/approve/send, Telegram + private loopback screen, weekly summary, four KPIs, safety + human approval) and excludes every named anti-scope item (no generic Hermes redesign, no production-wide systemd/auth, no browser framework, no crash-consistency theorem, no generic concurrency, no exact deployment scripts, no multi-customer expansion). The stage-8 inverted safety predicate is corrected everywhere to the existing contract (consent absent **or safety signal present** → no normal draft + owner notification + human review/referral). No conflict with HANDOFF operating principles (SOUL.md remains supreme; customer auto-send remains forbidden).

## Handoff
- Executor: implement steps 2–8 strictly in sequence; touch only the files named in the bounded owner map; escalate before touching anything else.
- Critic: review against AC1–AC20 and the anti-scope list before any real-customer enable.
- Escalate to architect only if a listed touch point requires structural change beyond reuse.
- Final activation (step 9) is a human-gated checklist execution, not an autonomous action.
