I read this as a correctness review - I will inspect the current NutriCoach changes and return a PASS/FAIL with only verified blocker findings.


I read this as an implementation review with no edits - I’m validating the focused replay, recovery, scheduler, and delivery paths, then will report only confirmed blockers.


I read this as a review-only request - reporting confirmed blockers without edits.

**FAIL — 4 blockers**

1. `dualcoach/profile/checkin_cli/nutrition_onboarding_projection.py:78-89`
   Finalization replay hashes the entire projected registry. After customer B finalizes, replaying customer A's identical finalization changes that digest and raises `conflicting nutrition onboarding projection replay`. Reproduced.

2. `gateway/platforms/dualcoach_activation_cutover.py:409-412`
   Activation replay reads the single global activation journal. After customer B activates, replaying customer A fails because the journal names B. The same global journal is also used for notice authority at `495-510`.

3. `gateway/platforms/telegram_customer_bootstrap.py:311-316,1089-1102`
   If the bootstrap projection (`ledger.json`) is missing while the append-only journal survives, startup appends an empty ledger event instead of restoring the journal's last state. Reproduced: one session became zero.

4. `gateway/platforms/telegram.py:10771,10596-10615`
   Supplied `now` is not normalized to KST before the daily-current check. The same instant evaluates `False` as UTC and `True` as KST, so a valid daily task can be skipped.

Verified:
- New-customer focused tests: 9 passed.
- Scheduler/delivery focused tests: 21 passed.
- Profile schedule tests: 28 passed.
- Single-customer finalization crash-replay test: passed.
- Production activation-notice drain and uncertain-publication recovery paths exist; the blockers above prevent approval.


I read this as reproduction handoff - providing the exact isolated commands used for the four findings.

Run from the combined worktree:

```bash
cd /home/cube/projects/richard/.worktrees/nutricoach-v150-combined
export PYTHONDONTWRITEBYTECODE=1
export PYTHONPATH="$PWD/dualcoach/profile"
PY=.venv/bin/python
```

1. **Cross-customer finalization replay** — previously prints `ValueError: conflicting nutrition onboarding projection replay`.

```bash
$PY - <<'PY'
from pathlib import Path
from tempfile import TemporaryDirectory
from checkin_cli.nutrition_onboarding_projection import apply_nutrition_onboarding_projection

D = lambda c: c * 64
with TemporaryDirectory() as tmp:
    root = Path(tmp)
    customers = root / "customers"
    customers.mkdir()
    (customers / "registry.json").write_text(
        '{"customers":[{"customer_key":"client_001","enabled":false},'
        '{"customer_key":"client_002","enabled":false}]}'
    )
    apply_nutrition_onboarding_projection(
        root, customer_key="client_001", nutrition_profile={"v": 1}, plan={"p": 1},
        artifact_bundle_digest=D("a"), readiness_receipt_digest=D("b"),
    )
    apply_nutrition_onboarding_projection(
        root, customer_key="client_002", nutrition_profile={"v": 2}, plan={"p": 2},
        artifact_bundle_digest=D("c"), readiness_receipt_digest=D("d"),
    )
    try:
        apply_nutrition_onboarding_projection(
            root, customer_key="client_001", nutrition_profile={"v": 1}, plan={"p": 1},
            artifact_bundle_digest=D("a"), readiness_receipt_digest=D("b"),
        )
    except ValueError as exc:
        print(type(exc).__name__ + ": " + str(exc))
    else:
        raise AssertionError("replay unexpectedly succeeded")
PY
```

2. **Activation replay after another customer's activation** — previously prints `ActivationCutoverError: committed customer activation is unavailable`.

```bash
$PY - <<'PY'
import json
from pathlib import Path
from tempfile import TemporaryDirectory
from gateway.platforms.dualcoach_activation_cutover import (
    ActivationCutoverError,
    _finalize_membership_activation_binding,
)

with TemporaryDirectory() as tmp:
    root = Path(tmp)
    data = root / "data"
    data.mkdir()

    # Simulates client_002 becoming the most recent global activation.
    activation = data / "customer-activation-journal.json"
    activation.write_text(json.dumps({
        "state": "committed",
        "customer_id": "client_002",
    }))
    activation.chmod(0o600)

    evidence = root / "membership.json"
    evidence.write_text("{}")
    evidence.chmod(0o600)

    try:
        _finalize_membership_activation_binding(
            root, evidence, customer_id="client_001"
        )
    except ActivationCutoverError as exc:
        print(type(exc).__name__ + ": " + str(exc))
    else:
        raise AssertionError("replay unexpectedly reached membership binding")
PY
```

For the regression test, give `client_001` a valid per-customer activation receipt plus an existing matching membership-binding event; replay must succeed without appending another binding or using `client_002`'s global receipt.

3. **Missing bootstrap projection despite surviving journal** — previously prints `recovered_sessions= 0` and `session_present= False`.

```bash
$PY - <<'PY'
from pathlib import Path
from tempfile import TemporaryDirectory
from gateway.platforms.telegram_customer_bootstrap import CustomerDraft, RoomBootstrapStore

with TemporaryDirectory() as tmp:
    store = RoomBootstrapStore(Path(tmp) / "bootstrap")
    session = store.prepare_rehearsal_customer_invite(
        CustomerDraft(
            customer_key="client_001",
            display_name="Client",
            starts_on="2026-08-21",
            daily_time="08:00",
            weekly_weekday=0,
            monthly_day=1,
            calories_kcal=2200,
            protein_g=140,
            meals=("breakfast",),
            customer_user_id="10",
        ),
        bot_username="dualcoachtestbot",
        owner_id="12",
    ).session

    store.ledger_path.unlink()  # Keep events.jsonl intact.
    recovered = RoomBootstrapStore(store.state_dir)

    print("original_sessions=", 1)
    print("recovered_sessions=", len(recovered.list_sessions()))
    print(
        "session_present=",
        any(item.session_id == session.session_id for item in recovered.list_sessions()),
    )
PY
```

4. **Timezone-dependent daily authorization** — previously prints `same_instant=True`, then `utc=False`, `kst=True`.

```bash
$PY - <<'PY'
from datetime import date, datetime, time, timezone
from types import SimpleNamespace
from zoneinfo import ZoneInfo

from gateway.platforms.telegram import TelegramAdapter

task = SimpleNamespace(kst_day=date(2026, 7, 21))
customer = SimpleNamespace(spec=SimpleNamespace(
    enabled=True,
    plan=SimpleNamespace(starts_on=date(2026, 7, 1)),
    schedule=SimpleNamespace(daily_time=time(8)),
))

utc_representation = datetime(2026, 7, 20, 23, 17, tzinfo=timezone.utc)
kst_representation = utc_representation.astimezone(ZoneInfo("Asia/Seoul"))

print("same_instant=", utc_representation == kst_representation)
print("utc=", TelegramAdapter._nutrition_daily_task_is_current(
    task, customer, utc_representation,
))
print("kst=", TelegramAdapter._nutrition_daily_task_is_current(
    task, customer, kst_representation,
))
PY
```

The fixed behavior for #1, #3, and #4 should be success / preserved session / equal `True` decisions. #2 should reach the customer-scoped binding path and treat the existing matching binding as idempotent.


I read this as verification of the four repaired blockers - rerunning the reproductions and their activation-binding equivalent.


I read this as verification - PASS; blocker_count: 0; remaining_blockers: none.


I read this as a narrow final review - inspecting only the deferred-notice and migration-marker changes, then running their targeted tests.


FAIL

blocker_count: 1

remaining_blocker: `gateway/platforms/telegram_customer_bootstrap.py:1306-1309,1342-1343` fsyncs the marker directory before `chmod(0500)` and never fsyncs the journal-head directory after `os.replace`. A power loss can durably retain the marker while losing the required head or 0500 protection, making valid journal recovery fail.


I read this as final durability verification - checking the repaired ordering and rerunning the focused regressions.


PASS

blocker_count: 0

remaining_blocker: none


I read this as a narrow r59 cron review - inspecting the two changed paths and regression tests, then running only their focused coverage.


I read this as a conclusion request - PASS; blocker_count: 0.


I read this as a narrow r60 review - tracing only the finalized-snapshot selector, weekly session switch, and their regression tests.


I read this as conclusion - FAIL.

blocker_count: 1

remaining blocker: `dualcoach/profile/checkin_cli/wizard_storage.py:251-255` has no tie-breaker beyond KST date and mtime. Equal mtimes select glob iteration order; reproduced opposite selections for reversed file order.


I read this as a narrow r61 verification - checking the tie-break implementation and rerunning reversed-order, future, and safety cases.


PASS

blocker_count: 0


I read this as a narrow r62 review - tracing the no-snapshot guard's ordering and running only its fake-host regression.