# Task26 replacement consent observer

Status: `READY_BEFORE_CONSENT` after independent live arm-only verification.

## Supersession decision

The lifecycle observer at `task26-lifecycle-observer-st_01a005b4` is not safe for this stage. It is sealed to plan `7ace03c6...`, runbook v4, placeholder runtime IDs, and outbox/activation/delivery events after consent. Its directory validator also rejects the live `data/onboarding` mode. It remains byte-identical and is superseded only for the current consent stage by this append-only observer.

This observer binds candidate `2e0894ea...`, wheel `af4a9d0a...`, current plan `d816dbbd...`, golden/recovery runbook v6, replacement session `cb_PCczfFXoI4GjvCxLBs1oRA`, sid hash `53b4f95b...`, customer `task26_live_2e_r2_20260815_8527916639`, actor/chat/topic `8527916639/8527916639/0`, role-claim message `158`, consent-card message `159`, owner `8693203710`, bootstrap generation `4`, and `AWAITING_CONSENT`.

## Exact normal callback trace

1. Telegram callback routing resolves the active bootstrap session by DM chat and requires namespace `cc1`, state `AWAITING_CONSENT`, exact customer role route, and consent-card message `159`.
2. `NutritionCoachingCoordinator.handle_customer_consent_callback` authenticates the registered route and deterministic `privacy-v1` grant callback. It atomically replaces `customers/registry.json`, changing only this disabled customer's consent from unset/false to granted with the KST date and `privacy-v1`.
3. The adapter retires the consent card by editing Telegram message `159`.
4. The bootstrap CAS re-reads the same session and requires unchanged generation/card/publication attempt. It atomically replaces `data/onboarding/telegram-customer-bootstrap-v1/ledger.json`: generation `4 -> 5`, state `AWAITING_CONSENT -> AWAITING_ACTIVATION`, card receipt `159 -> null`, and a new `updated_at`; no other session may change.
5. `start_after_consent` idempotently atomically replaces `customers/registry.json` with the same granted `privacy-v1` consent, derives exact route evidence `8527916639/8527916639/0/159`, and derives consent receipt digest `5e3067fe...` from actor, card, generation 5, and notice version.
6. The onboarding store creates the private tree `data/customers/task26_live_2e_r2_20260815_8527916639/nutrition-onboarding/`, its `lock`, empty `session.json`, `transient/`, and `transient/workflow.json`. The workflow begins `collecting`, cursor `0`, with consumed update marker `159` and the exact consent receipt digest.
7. Normal prompt publication changes onboarding `session.json` through PREPARED and COMMITTED, and changes `data/onboarding/telegram-publication-outbox-v1/ledger.json` through DISPATCHING, RECEIPTED, and COMMITTED around the Telegram prompt send. After the handler completes, `data/telegram-ingress-receipts-v1-d0aacf0f4bdbb7c0.json` receives the update-ID receipt.

The consent-stage observer intentionally stops at step 4: the exact durable consent commit. It invokes no Telegram/provider/network API, consumes no raw update, and neither polls nor sleeps. It watches the registry and bootstrap authority directories before reading the baseline, rejects any target event crossing that boundary, writes `READY_BEFORE_CONSENT`, and waits on inotify for at most 1800 monotonic seconds.

## Exact launch

Run from `/home/cube/projects/richard/traning coach`; both output files must be absent:

```bash
python3 -B '.omo/evidence/task26/task26-consent-observer-st_01a007da/consent_observer.py' observe --profile '/home/cube/.hermes/profiles/dualcoachtest' --ready '.omo/evidence/task26/task26-consent-observer-st_01a007da/live-consent-ready.redacted.json' --receipt '.omo/evidence/task26/task26-consent-observer-st_01a007da/live-consent-committed.redacted.json' --timeout 1800
```

Do not touch the card until stdout and the ready file both report `READY_BEFORE_CONSENT`. Then actor `8527916639` must press `내용 확인 후 동의` exactly once on DM consent-card message `159`. Keep the observer running until `PASS_CONSENT_COMMITTED` or a fail-closed exit.
