# task-2729+13 — SEALED_ANU_KEY_SUPPLY_AND_ENTRYPOINT_LAUNCHER_WIRING_PREFLIGHT (audit-first + candidate patch, activation 0)

## 레벨
Lv.3 (sealed key 공급 audit + entrypoint/main launcher_fn 결선 설계/후보patch — production activation 아님, systemd enable 0, real spawn 0, canonical 무손상)

## 발번 주석
회장 지시문은 "task-2729+12로"였으나 task-2729+12 = PR #188 머지 완료(CODE/DATA alignment). collision 회피 + lineage 연속 위해 **task-2729+13**로 발번. 회장 확인 요망.

## 한 줄 목표
**sealed ANU key 공급은 이미 SATISFIED**(.env.keys `export COKACDIR_KEY_ANU` provision·sha 일치·fail-closed 구현 확인)임을 audit-confirm 하고, 실제 남은 gap인 **driver main() launcher_fn 결선**(현재 미결선 → real auto-wake 0)을 real-wake activation flag 로 gating 하는 **최소 candidate patch**로 설계·검증한다. **세션 임시 key 의존 제거(이미 sealed 사용 가능). systemctl enable / ACTIVE=true / canonical activation_epoch / 추가 real spawn 0.**

## 배경 실측 (단일 소스, CODE_ROOT 0ce319ca)
- **sealed key 공급 = 이미 SATISFIED(★정정)**: `.env.keys` line 3 `export COKACDIR_KEY_ANU=<값>` provision 확인, `_default_sealed_key_loader()` 반환값 sha256 == ANU key sha256 일치. 부재 시 None → `pickup_once` 가 `SEALED_KEY_MISSING` **fail-closed(wake 0)**. `sealed_key_loader` 인자 주입 가능(mock). ⇒ 이전 'SEALED_ANU_KEY_SUPPLY 미해결' 보고는 grep 패턴('export ' 접두 미매칭) 오류였음(`SEALED_ANU_KEY_SUPPLY_ACTUALLY_SATISFIED_CORRECTION`).
- L2 canary 의 세션 임시 key 는 **mock pickup_fn 산물**(production 경로 아님). production = sealed loader 사용·fail-closed.
- **남은 실제 gap = gap2(code)만**: driver `main()` = `scan_once(CANONICAL_ROOT, legacy_cutoff=True)` — **launcher_fn 미전달** → launcher_fn=None → real auto-wake 0(surface only). real auto-wake(나) 하려면 main() 이 `launcher_fn=launch_wake(dry_run=<real-wake flag>, anu_key_verifier=<sealed loader 기반>)` 결선 필요.
- 선행: dry_run_false_pilot/precheck packet, code_root_preflight_design_260607.md.

## 작업 (audit-first + candidate patch, isolated 검증)
### A. sealed key 공급 audit + 옵션 비교
- 기존 `_default_sealed_key_loader`/`PICKUP_SEALED_KEY_MISSING` fail-closed 경로 audit(코드 변경 0).
- sealed 공급 방식 후보 비교(설계 문서): **A) .env.keys COKACDIR_KEY_ANU 항목** (현 로더 기본) / **B) systemd `EnvironmentFile=`**(0600, key→env) / **C) 외부 secret store→env injection**. 각 위험/노출면/회전/rollback. ★ 실제 키 값 provision 은 회장/ops(본 task 0).
### B. driver main() launcher_fn 결선 설계 + candidate patch (★옵션2 고정 — 회장 결정)
- ★ **옵션2 고정**: real-wake flag(`memory/state/p0b_real_wake_enabled` == "enabled") **있을 때만** sealed-key 기반 `launcher_fn=functools.partial(launch_wake, dry_run=False, anu_key_verifier=verifier)` 주입. **flag 부재 시 launcher_fn=None 유지(현행 그대로, launcher 함수 자체 호출 0·새 코드경로 실행 0)**. ⇒ entrypoint 가 부르는 `python3 -m dispatch.anu_pickup_driver` default 동작 무변경.
- verifier 구성: sealed loader 값으로 `lambda k: hmac.compare_digest(k, sealed_key)` (상수시간 비교). sealed key 부재 → launcher_fn=None(주입 안 함) → real wake 0.
- ★ flag on 이어도 **fail-closed 전부**: sealed key 부재 / verifier 검증 실패 / non-callable verifier / verifier exception → `FAIL_CLOSED_*` wake 0(launch_wake W1 step3 이미 처리).
- 3중 차단 보존: p0b_driver_enabled(감지) + p0b_real_wake_enabled(real wake) + sealed key. systemd enable 만으로 real spawn 0.
### C. isolated 검증 (temp root, mock sealed provider)
- key 부재 → real pickup fail-closed(PICKUP_SEALED_KEY_MISSING) wake 0 / quarantine 0.
- key 존재(mock sealed_key_loader) → argv 생성되나 **raw key / full argv stdout/log/audit/ledger 출력 0**(argv_len redacted).
- real-wake flag 부재 → dry_run=True(DRY_RUN) real subprocess 0 / flag enabled + mock runner → LAUNCHED(real subprocess 0, sabotage).
- duplicate(SKIP_DEDUPE) / terminal no-op / ledger·marker fail-safe / legacy 140 NOOP_LEGACY_SKIP 이동 0 유지.

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "dispatch/anu_pickup_driver.py"
    - "tests/regression/test_sealed_key_and_launcher_wiring_2729p13.py"
    - "memory/reports/task-2729+13.md"
    - "memory/plans/p0b-pickup/sealed_key_and_launcher_wiring_design_260607.md"
    - "memory/events/task-2729+13.*"
    - "memory/tasks/task-2729+13-sealed-anu-key-supply-and-entrypoint-launcher-wiring-preflight.md"
  read_only_reference:
    - "dispatch/anu_result_pickup_runner.py (_default_sealed_key_loader/PICKUP_SEALED_KEY_MISSING — read only)"
    - "dispatch/anu_pickup_wake_launcher.py (launch_wake/anu_key_verifier — read only)"
    - "scripts/anu_pickup_entrypoint.sh (read only — 변경 시 별도 candidate)"
    - "deploy/systemd/anu-pickup.service (read only)"
    - "utils/env_loader.py (load_env_keys — read only)"
  forbidden_paths:
    - "/home/jay/workspace (canonical working tree — reset/clean/stash/switch 금지)"
    - ".env.keys (실제 ANU key 값 provision/기록 금지 — raw key write 0)"
    - "dispatch/anu_result_pickup_runner.py"
    - "dispatch/anu_pickup_wake_launcher.py"
    - "utils/env_loader.py"
    - "memory/state/** (flag enabled/activation_epoch/real_wake flag enabled 생성 금지)"
    - "memory/events/task-*.result.json (canonical result.json 이동·삭제·quarantine 금지)"
    - "memory/events/task-*.g4-fix-loop-count (G4 counter reset 금지)"
    - "deploy/systemd/** (enable/install 금지)"
    - "dispatch.py"
    - ".github/**"
    - "/usr/local/bin/cokacdir"
    - "task-2716 branch (수정 금지)"
```

## EXPECTED FILES (정확히 5 — 초과 시 즉시 HOLD_FOR_CHAIR)
1. `dispatch/anu_pickup_driver.py` — main() launcher_fn 결선 + real-wake activation flag 게이팅(default dry_run=True). sealed loader→verifier.
2. `tests/regression/test_sealed_key_and_launcher_wiring_2729p13.py` — sealed key 부재/존재 fail-closed + wiring + redaction + real-wake flag 게이팅 + dedupe/terminal/legacy NOOP 회귀
3. `memory/reports/task-2729+13.md` — audit/검증 결과 + 필수확인 10 + sealed 공급 옵션 A/B/C
4. `memory/plans/p0b-pickup/sealed_key_and_launcher_wiring_design_260607.md` — 설계(공급 옵션·wiring·real-wake flag·fail-closed)
5. (필요 시 evidence/harness 1개)
- ★ runner/launcher/env_loader **무변경**(read-only). entrypoint/service 변경 필요 시 별도 candidate(본 task 범위 외). 실제 키 provision 0. systemd enable 0.

## 필수 확인 (회장 verbatim 10)
1. CODE_ROOT/DATA root 분리 상태(CODE=${HOME}/p0b-pickup-main, DATA=canonical). 2. production entrypoint 가 실행하는 코드 경로(CODE_ROOT). 3. launcher_fn 이 production 에서 결선되는 위치(main()). 4. sealed ANU key env name(COKACDIR_KEY_ANU) + 로드 실패 fail-closed(PICKUP_SEALED_KEY_MISSING wake 0). 5. key 부재 시 real wake 절대 미실행. 6. key 존재 시 argv 생성되나 raw key 출력 0. 7. logs/audit/ledger 에 argv_len/redacted 만. 8. duplicate wake 방지 + ledger failure fail-safe 유지. 9. activation_epoch 이전 legacy 140 영구 skip invariant 유지. 10. ACTIVE=false 유지(flag/real_wake flag/epoch 미생성, systemd not-enabled).

## 금지 (회장 verbatim)
1. systemctl enable --now  2. production ACTIVE 전환  3. canonical activation_epoch 생성  4. 추가 real ANU spawn  5. raw key 출력  6. canonical result.json 이동·삭제·quarantine  7. task-2716 수정  8. canonical reset/clean/stash -u/checkout -f  9. ACTIVE=true 선언  10. G4 counter reset  11. PR merge/push/comment 자동 실행  12. .env.keys 에 실제 키 값 기록
- 모든 검증 isolated temp + mock sealed provider. canonical 무손상.

## 이번 라운드 범위 (회장 verbatim)
- **구현 + isolated verify + PR_READY_CANDIDATE 까지.** ★ PR 생성 / CI·Gemini gate / merge 는 **별도 승인 전까지 진행 0**. production activation 아님.

## 필수 검증 (회장 verbatim 15)
1. sealed key present/absent 각각. 2. key absent→wake 0 fail-closed. 3. key present→argv 생성 가능·raw key 출력 0. 4. real-wake flag off→launcher_fn=None·launcher 호출 0. 5. real-wake flag on→mock launcher로만·실제 subprocess/cokacdir 실행 0. 6. legacy 140 skip invariant. 7. duplicate 0. 8. terminal marker no-op. 9. ledger/marker failure fail-safe. 10. raw key 0. 11. ACTIVE=false. 12. systemd not enabled. 13. activation_epoch absent. 14. canonical delta 0. 15. **subprocess.run/Popen/call/os.system sabotage 상태에서 regression PASS**.

## 완료 판정 (회장 verbatim)
- 위 15 + isolated(key 부재 wake 0 / 존재 redacted / flag off launcher_fn=None / flag on mock launcher real subprocess 0) PASS → **`PR_READY_CANDIDATE_SEALED_KEY_LAUNCHER_WIRING_ACTIVE_FALSE`** 보고(로컬 verify까지, PR 미생성).
- raw key risk / real spawn 필요 / ACTIVE=true 필요 / systemd enable 필요 / expected_files 5 초과 / canonical write 필요 → **`HOLD_FOR_CHAIR`** 중단.
- ★ PR 생성·CI/Gemini gate·merge·activation 은 별도 회장 승인 전까지 금지.

## doctrine
직접 코딩 금지(ANU)/봇 위임 / canonical·task-2716 무손상 / isolated temp + mock sealed provider / runner·launcher·env_loader 무변경 / 실제 키 provision 0 / real-wake flag default dry_run / activation 실행 0 / raw key 0 / same-PR push 금지·bot trigger 금지·chain limit·long polling 금지.
```yaml
callback_envelope_byte_limit: 3900
callback_collector_role: ANU
callback_owner_key_source: ".env.keys COKACDIR_KEY_ANU (sealed, literal 출력 0)"
```
