# task-2729+8 (r2) — P0-B real wake 결선 + Gemini HIGH remediation (Option A replacement)

## 레벨
Lv.3 (real wake 결선 + 보안 remediation. production activation/real spawn 실행 아님)

## 배경 (단일 소스)
- PR #183(head 13f1a8fc) = SUPERSEDED. fresh base(c6aacb5e, #181+#182)로 real wake launcher 결선 완료했으나 Gemini fresh **HIGH + SECURITY-HIGH** 적발 → merge blocker.
- same-PR push 금지 → **Option A replacement**(새 branch, fresh origin/main base)로 수정 재구현.
- 기존 #183 산출 5파일을 base 로 하되 아래 HIGH/MEDIUM 수정 반영.

## ★ 수정 목표 (회장 verbatim — Gemini HIGH/SECURITY remediation)
1. **HIGH (`wake_launcher.py` `_iso`)**: timezone-aware clock 입력을 **UTC 로 변환한 뒤** Z suffix. (`dt.tzinfo is not None → dt.astimezone(timezone.utc)`)
2. naive datetime(`tzinfo is None`)은 **명시적 UTC 처리 또는 fail-safe 정책**을 코드+테스트에 고정.
3. **SECURITY-HIGH (`anu_key_verifier`)**: `anu_key_verifier` 가 None 아닌데 **callable 아니면 fail-closed**(`DECISION_FAIL_CLOSED_NON_ANU_KEY`).
4. verifier **결과 false / 예외** 도 **fail-closed**.
5. ledger/audit/stdout 에 **raw key / full argv 노출 0** 유지(redaction).
6. dry-run/mock 기본에서 **real subprocess/os.system/cokacdir 실행 0** 유지.
7. **MEDIUM (try-block hygiene)**: `with open(...)` 일원화로 정리 — expected_files 안에서.

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "dispatch/anu_pickup_wake_launcher.py"
    - "dispatch/anu_pickup_driver.py"
    - "tests/regression/test_anu_pickup_real_wake_wiring_2729p8.py"
    - "memory/reports/task-2729+8.md"
    - "memory/plans/p0b-pickup/real_wake_wiring_design_260606.md"
    - "memory/events/task-2729+8.*"
    - "memory/tasks/task-2729+8-real-wake-wiring-r2.md"
  read_only_reference:
    - "dispatch/anu_result_pickup_runner.py (read only)"
    - "dispatch/anu_owned_callback_enforcement.py (read only)"
    - "tests/regression/test_anu_pickup_activation_hardening_2729p7.py (baseline 무영향)"
  forbidden_paths:
    - "dispatch/anu_result_pickup_runner.py"
    - "dispatch/anu_owned_callback_enforcement.py"
    - "scripts/anu_pickup_entrypoint.sh"
    - "deploy/systemd/**"
    - "memory/events/task-*.result.json"
    - "memory/events/owner-trigger-audit.jsonl"
    - "memory/events/callback_4tuple_index.jsonl"
    - "memory/state/**"
    - "memory/p0b_state/**"
    - "utils/**"
    - "scripts/finish-task.sh"
    - "dispatch.py"
    - ".github/**"
    - "hooks/**"
    - "/home/jay/.claude/**"
    - "/usr/local/bin/cokacdir"
```

## EXPECTED FILES (기존 5 유지 — 초과 시 중단·HOLD_FOR_CHAIR)
1. `dispatch/anu_pickup_wake_launcher.py` (W1 + HIGH/SECURITY fix)
2. `dispatch/anu_pickup_driver.py` (W2 launcher_fn 결선, default None)
3. `tests/regression/test_anu_pickup_real_wake_wiring_2729p8.py` (timezone/verifier fail-closed 케이스 추가)
4. `memory/reports/task-2729+8.md`
5. `memory/plans/p0b-pickup/real_wake_wiring_design_260606.md`

## ★ base 요구 (필수)
- 반드시 **fresh origin/main(c6aacb5e 또는 이후)** base. #181 hardening + #182 base isolation 포함 실측. stale(14ff8339) 시 즉시 HOLD.

## 필수 검증 (회장 verbatim 13)
1. diff 5파일 유지. 2. raw key 0. 3. ACTIVE=false. 4. systemd enable 0. 5. activation_epoch 0. 6. canonical result.json 126 무변동. 7. real spawn 0. 8. subprocess.run/Popen/call/os.system **sabotage 상태에서 테스트 PASS**. 9. launcher_fn=None 기본 decision-only 유지. 10. WAKE_BUILT + injected launcher 에서만 launcher 호출. 11. legacy cutoff/MAX defer/terminal no-op/ledger failure 경로 launcher 0. 12. CI GREEN. 13. fresh Gemini HIGH/CRITICAL 0.

## 금지 (회장 verbatim)
1. PR #183 same-branch push  2. rebase/force  3. systemctl enable  4. production ACTIVE  5. activation_epoch 생성  6. real ANU spawn  7. canonical result.json 이동·삭제·quarantine  8. ACTIVE=true 선언  9. merge
- 모든 검증 isolated temp root. canonical 무손상.

## 완료 판정
- replacement PR 생성 후 13 gate PASS → **MERGE_APPROVAL_CANDIDATE_REAL_WAKE_READINESS_ACTIVE_FALSE**.
- merge·production activation 별도 회장 승인 전 금지.
- ★ commit/finalize 가 EXTERNAL_DIRTY_BLOCKER(start_task_guard #7)로 막히면 수동 .done 금지, ANU callback envelope + ANU recovery(lock 복구+commit+PR) 허용.

## doctrine
직접 코딩 금지(ANU)/봇 위임 / same-PR post-Gemini push 금지 / fail-closed 우선 / raw key 0 / isolated temp root / callback ANU key 독립·self-collector 금지.
