# task-2729+8 — P0-B real wake 결선 (WAKE_BUILT argv 실 실행) audit-first hardening

- 팀: dev1-team (팀장 헤르메스) | 레벨: Lv.3 | 작성일: 2026-06-06 (KST)
- 완료 판정: **`REAL_WAKE_READINESS_VERIFIED_ACTIVE_FALSE`**
- 기준 main: `14ff8339` | 작업 브랜치: `task/task-2729+8-dev1`

## SCQA 요약

**S**: P0-B pickup driver(`anu_pickup_driver.process_one`)는 6조건 통과 후
`pickup_once` 가 `WAKE_BUILT` + wake argv(`cokacdir --cron … --key <ANU_KEY>`)를 빌드해도,
WAKE_BUILT 분기(구 471–482줄)에서 argv 를 **읽지도 실행하지도 않고**(`fire_cron_id=None`) surface 만 했다.

**C**: systemd enable 전, "real wake 결선이 안전하게 가능한가"가 미검증 상태였다.
real ANU spawn 을 dispatch 단계에서 실행하면 canonical 오염·raw key 노출·중복 wake·runaway 위험이 있다.

**Q**: real ANU spawn 실행 0 · canonical 무오염 · ACTIVE=false 를 유지하면서,
WAKE_BUILT argv 실 실행 결선의 readiness 를 isolated 로 확정할 수 있는가?

**A**: 관심사 분리(driver=decision-only, 신규 launcher=실행)로 결선했다. launcher 는
**dry_run 기본 True**(실행 0, production 무기록) + raw key redaction + 이중 dedupe + fail-closed.
driver 는 `launcher_fn=None`(현행 보존) 기본, 주입 시에만 호출. 회귀 19 + 기존 P0-B 회귀 46 = **65 PASS**,
L1 스모크 10항목 전부 통과(real spawn 0 / canonical 무오염 / raw key 0). pyright reportFunctionMemberAccess 0건.

## 생성/수정 파일 (정확히 5 — 초과 0)

1. `dispatch/anu_pickup_wake_launcher.py` (신규, W1) — wake launcher. `launch_wake()` + `LaunchRecord` + 7 decision 상수.
2. `dispatch/anu_pickup_driver.py` (수정, W2) — `process_one`/`scan_once` 에 `launcher_fn=None` 주입, WAKE_BUILT 분기 결선.
3. `tests/regression/test_anu_pickup_real_wake_wiring_2729p8.py` (신규) — 회귀 + mock launcher decision-only 19 케이스.
4. `memory/reports/task-2729+8.md` (본 보고서).
5. `memory/plans/p0b-pickup/real_wake_wiring_design_260606.md` (pilot design).

- runner(`anu_result_pickup_runner.py`) / callback_enforcement 수정 **0** — argv 빌드 기존 재사용.

## 수정 파일별 검증 상태

| 파일 | 변경 내용 | grep 검증 | 상태 |
|---|---|---|---|
| dispatch/anu_pickup_wake_launcher.py | 신규 wake launcher (launch_wake/LaunchRecord/decision 상수) | grep "def launch_wake" OK | verified |
| dispatch/anu_pickup_driver.py | process_one/scan_once launcher_fn 주입, WAKE_BUILT 결선 | grep "launcher_fn" OK | verified |
| tests/regression/test_anu_pickup_real_wake_wiring_2729p8.py | 회귀+mock decision-only 19 케이스 | grep "def test_" OK | verified |
| memory/reports/task-2729+8.md | SCQA 보고서 + L1 결과 | grep "L1 스모크" OK | verified |
| memory/plans/p0b-pickup/real_wake_wiring_design_260606.md | pilot design | grep "real wake" OK | verified |

## 설계 핵심 (관심사 분리)

- **launcher = 유일 spawn 책임**. `launch_wake(argv, *, task_id, sha256, dry_run=True, root, launch_ledger_path, audit_path, anu_key_verifier, subprocess_runner, clock)`.
- 결정 순서(fail-closed 우선): NO_ARGV → MALFORMED → NON_ANU_KEY → (dedupe)SKIP_DEDUPE/LEDGER_ERROR → DRY_RUN → LAUNCHED.
- dedupe: launcher 자체 ledger(`memory/p0b_state/wake_launch_ledger.jsonl`, event=`WAKE_LAUNCHED`)로 (task_id, sha256) 재확인 — pickup 의 `PICKUP_WAKE_BUILT` ledger 와 분리(후자는 WAKE_BUILT 직전 항상 존재해 dedupe 기준 부적합).
- raw key 0: argv 는 stdout/log/audit/ledger 어디에도 미출력. `LaunchRecord` 는 `argv_len`(길이)만 보유.
- driver: `launcher_fn=None` 기본=현행 보존. 주입 시 WAKE_BUILT 분기에서만 `launcher_fn(res.argv, task_id, sha256)` 호출, `fire_cron_id=lr.decision`(라벨만), 예외는 fail-safe(크래시 0).

## 테스트 결과 (정량)

- 신규 회귀 `test_anu_pickup_real_wake_wiring_2729p8.py`: **19 passed** (0.16s).
- 기존 P0-B 회귀 무영향: `test_anu_result_pickup_runner_2720.py` + `test_anu_pickup_driver_2721.py` + 신규 = **65 passed** (0.31s).
- pyright: 구현 모듈(launcher/driver) 신규 에러 0. 테스트의 `reportFunctionMemberAccess` 0건(recorder 리팩토링). 잔존은 dispatch importlib shim(house 패턴, 기존 테스트 동일) + 의도적 미사용 변수(언더스코어/loop var) 경고뿐 — 심각 타입 에러 0.

## ★ L1 스모크테스트 결과 (필수 기록)

- **서버 재시작**: 해당없음 (서버/API/프론트 없는 모듈 결선 audit-first task).
- **API 응답 확인**: 해당없음.
- **스크린샷**: 해당없음 (UI 없음).
- **실동작 검증(subprocess/정제 유형)**: isolated temp root 에서 `process_one → launch_wake` 실 결선 실행 — **통과**. 10항목 결과:
  1. driver verdict = `WAKE_BUILT`
  2. fire_cron_id = `DRY_RUN` (decision 라벨만 surface, 키/argv 0)
  3. real spawn calls = **0** (dry_run 기본, mock subprocess 미호출)
  4. launch ledger = MISSING (dry-run production 무기록 — OWNER_TRIGGER_DRY_RUN_LEDGER_CONTAMINATION 방지)
  5. real-mode(dry_run=False) decision = `LAUNCHED`, rc=0
  6. mock spawn = 1회 (real-mode 정상 발사)
  7. ledger raw key = **ABSENT** (redacted)
  8. to_json raw key = **ABSENT**
  9. dedupe 재발사 = `SKIP_DEDUPE`, spawn 누적 1 (중복 wake 0)
  10. canonical ledger(`/home/jay/workspace/memory/p0b_state/wake_launch_ledger.jsonl`) = **ABSENT** (무오염)
- 결론: pytest PASS + 실 결선 동작 동시 확인. real wake readiness 확정.

## 회장 verbatim 검증 (12 / 12 충족)

1 WAKE_BUILT 에서만 launcher 호출(B12) · 2 legacy cutoff launcher 0(pickup 단계 미반환) · 3 terminal marker launcher 0(B14) · 4 MAX/defer launcher 0(NOOP_NOT_READY) · 5 ledger/marker failure launcher 0(B13/A9) · 6 duplicate wake 0(A8/L1#9) · 7 raw key 0(A3/A7/A10/L1#7,8) · 8 실제 spawn 0(A1/L1#3 mock) · 9 dry-run/mock isolated temp(전 케이스 tmp_path) · 10 canonical 영향 0(L1#10) · 11 ACTIVE=false 유지(activation flag/systemd 미터치) · 12 기존 decision-only 보존(B11, launcher_fn=None 기본).

## 중단 조건 (8 / 8 해당 없음)

5파일 정확 · real spawn 없이 mock 검증 가능 · canonical write 불필요(isolated) · raw key 노출 0 · dedupe 이중 명확 · ACTIVE=true 불필요 · systemd enable 불필요 · fresh HIGH/CRITICAL 0.

## LOCK 준수 (회장 verbatim 9)

systemctl enable 0 · production ACTIVE 전환 0 · activation_epoch write 0 · canonical result.json 이동/삭제 0 · **real ANU spawn 실행 0**(dry_run 기본+mock) · PR merge/push/comment 0(본 보고 시점) · raw ANU key 출력 0 · ACTIVE=true 선언 0 · legacy result.json 재처리 0.

## 발견 이슈 및 해결

### 자체 해결 (3건)
1. **launcher `uuid` 미사용 import** — 제거(불칸 구현물 정리, pyright 경고 0).
2. **테스트 `.calls` 함수 속성 접근 reportFunctionMemberAccess (9건)** — recorder 를 `(fn, calls_list)` 튜플 반환으로 리팩토링하여 0건 해소.
3. **테스트 `glob` 미사용 import** — 제거.

### 범위 외 미해결 (0건)
- 없음. driver `main(argv=None)` CLI 시그니처의 `argv` 미사용 경고는 본 task 변경과 무관한 사전 존재 항목(범위 외, 미수정).

## 머지 판단

- **머지 필요**: Defer (★ LOCK #6 "실제 PR merge/push/comment 금지" — 본 task 에서 머지 실행 0. ANU/회장 판단 대상.)
- **브랜치**: `task/task-2729+8-dev1`
- **워크트리 경로**: `/home/jay/workspace/.worktrees/task-2729+8-dev1`
- **머지 의견**: 5파일 정확, 65 회귀 PASS, L1 10항목 통과, raw key/canonical/real-spawn 위험 0. runner/callback_enforcement 무수정으로 기존 계약 보존. 코드 자체는 머지 가능 품질이나, 본 task 는 "real wake 결선 readiness 확정"(`REAL_WAKE_READINESS_VERIFIED_ACTIVE_FALSE`)이 산출물이며 LOCK #6 에 따라 PR merge/push 는 수행하지 않음. launcher_fn 기본 None 으로 production 결선·activation 은 별도 회장 승인 대상. finish-task.sh 는 project_path 미지정(머지 스킵)으로 실행.

## 모델 사용 기록

- 헤르메스(팀장, Opus): 설계 문서·통합 검토·L1·보고서.
- 불칸(백엔드, general-purpose/Sonnet): W1 launcher + W2 driver 결선 구현.
- 아르고스(테스터, general-purpose/Sonnet): 회귀+mock 테스트 19 케이스 + pyright 정리.
- haiku 미사용(시스템 hardening 정밀 작업 — sonnet 이상 사용).

## 비고 (완료 판정 의미)

본 PASS = "real wake 결선 readiness 확정" 입력 자료. **production ACTIVE 전환 아님 / real wake 실행 0**.
pickup chain = IMPLEMENTED / WIRED candidate / ACTIVE=false 유지. systemd enable·activation_epoch 생성·
real wake pilot·production activation 은 모두 별도 회장 승인 전까지 금지.
