# task-2729+5 — P0-B ANU pickup runner 감지경로 audit-first 재검증 + controlled pilot 설계

> 팀: dev4 (비슈누) | 레벨 Lv.3 | 작성일 2026-06-05 | 판정 **DISPATCH_READY_FOR_CONTROLLED_PILOT**
> 최종 상태 고정: **IMPLEMENTED / WIRED candidate / ACTIVE=false** (PASS여도 production ACTIVE 미기록)

---

## SCQA 요약

- **S**: (Situation) P0-A 완료(PR#174 merge 5b86e168) 후 pickup chain 정본(origin/main)은 `systemd .path → .service → entrypoint → driver.scan_once → process_one → runner.pickup_once` 로 배선됐으나, systemd user unit 미설치·activation flag 부재로 ACTIVE=false 상태다.
- **C**: (Complication) result.json 이 생겨도 ANU 자동 wake 가 0(dead-man/manual 의존)인 wake-gap 이 미해결이며, 과거 dry-run 이 canonical ledger 를 오염시킨 사고(OWNER_TRIGGER_DRY_RUN_LEDGER_CONTAMINATION)가 있었다.
- **Q**: (Question) 런타임 코드·systemd·canonical 상태를 일절 건드리지 않고, 감지경로 6조건과 안전속성(중복방지·terminal no-op·키노출0·runaway guard)을 재검증하고 1회성 pilot 을 안전하게 설계할 수 있는가?
- **A**: (Answer) 가능. origin/main 기반 격리 worktree 에서 read-only audit + isolated temp root decision-only 하니스(11/11 PASS, canonical_untouched=true, raw_key_exposure=0)로 재검증을 완료했고, 1회성 controlled pilot 설계서를 산출했다. 실 발사 0·canonical 무영향 확인. 활성화 보완항목(C1 MAX_FILES 상한 등)은 별도 활성화 task input 으로 명시.

---

## 1. 작업 내용

audit-first(read-only) 재검증 + decision-only 검증 하니스 신규 작성 + 회귀 + controlled pilot 설계. **런타임 pickup 코드·systemd·canonical ledger/events/state 무수정·무영향.**

작업 기반: `origin/main`(5b86e168, PR#174 merge) 기반 격리 worktree `/home/jay/workspace/.worktrees/task-2729+5-dev4`. (메인 워크스페이스가 타 task 브랜치에 있어 audit 대상 파일이 working tree 부재 → origin/main blob 기준 audit 후 worktree 에서 산출물 작성.)

정본 blob 일치 확인: runner `54ffe22d`, driver `8b2174a5`, entrypoint `a5fd668d`, .path `50aa6554`, .service `722607ea` — 모두 task 명세와 일치.

## 2. 감지경로 audit-first 재검증 (read-only, 6조건 + 경로)

1. **감지 트리거**: `anu-pickup.path` `PathExistsGlob=%h/workspace/memory/events/task-*.result.json` → `anu-pickup.service`(Type=oneshot) → `anu_pickup_entrypoint.sh`. **systemd user unit 미설치 재확인**: `systemctl --user is-enabled anu-pickup.path` → `not-found`. 감지경로 **비활성** 확정.
2. **entrypoint**: activation flag(`memory/state/p0b_driver_enabled`) 첫 줄 trim 이 정확히 `enabled` 일 때만 진행, 부재/그 외 → `exit 0`(default DISABLED). flock single-flight(`exec 9>LOCK; flock -n 9`), XDG_RUNTIME_DIR(0700) 우선 lock, symlink 거부(`[[ -L LOCK ]] → exit 0`). **ANU key argv 전달 0** — driver 가 `.env.keys` 로 런타임 로드. flag 부재 확인 완료(default DISABLED).
3. **driver `scan_once`**: activation 재확인 → disabled 면 `[NOOP_DISABLED]` 1건 + pickup 미호출. enabled 면 glob → `process_one`. (decision-check DC1 재현)
4. **`process_one` 6조건**: target(`task-*.result.json`) → readiness grace(최근 mtime/size·mtime 불안정 → `NOOP_NOT_READY` DEFER) → size>0 → JSON parse(null-byte 방어) → schema(`task_id` 경로탐색 문자 거부) → owner proof(`verify_collector_authoritative`==AUTHORITATIVE) → dedupe/done/acked. (DC2~DC8 재현)
5. **`pickup_once`**: ① no result→fail ② parse ③ terminal no-op(done/acked→SKIP_TERMINAL) ④ dedupe(ledger (task_id,sha256)→SKIP_DEDUPE) ⑤ collector verify(조건부) ⑥ sealed-key(`.env.keys` `COKACDIR_KEY_ANU` 만, 미로드→SEALED_KEY_MISSING fail-closed) ⑦ argv build(`anu_runner_pickup_and_fire`, executor self-key refuse) ⑧ ledger 기록 ⑨ done marker ⑩ WAKE_BUILT. (DC10/DC11 재현)
6. **driver argv 미실행**: `process_one` 의 WAKE_BUILT 경로 주석/구현 모두 "driver 는 argv 를 실행하지 않음(P0-a dry_run)" 확인 — 실제 wake 0.

## 3. 안전속성 audit

- **중복방지(dedupe)**: ledger (task_id,sha256) 일치 시 SKIP_DEDUPE + driver 단 (task_id, event=PICKUP_WAKE_BUILT) ledger hit → PICKUP_SKIP. WAKE_BUILT 후 result 파일을 watched 밖 `processed/` 로 atomic 이동 → 재스캔 대상 제거(이중 방어). (DC9 누적 pickup_calls==1)
- **terminal no-op**: `{task_id}.pickup.done`/`.acked` 존재 시 runner·driver 양측 SKIP, pickup 미호출. (DC4 pickup_calls==0)
- **runaway guard**: activation flag default DISABLED + entrypoint flock single-flight + symlink 거부. ★ **`scan_once` MAX_FILES 상한 부재**(C1) — 활성화 전 보완 필요로 기록.
- **ANU key raw 노출 0**: 신규 산출물 16hex literal 0건. 하니스 summary raw_key_exposure=0. entrypoint/driver/runner 모두 키 literal 0(.env.keys 런타임 로드).

## 4. 생성/수정 파일 목록 (EXPECTED FILES — 코드 신규구현 0, audit 도구만)

생성(worktree 커밋):
- `scripts/harness/v36/anu_pickup_p0b_audit_decision_check.py` — read-only decision-only 하니스(isolated temp root 강제, 주입형 mock, 실발사0). 커밋 `42bfe0cb`.
- `tests/regression/test_anu_pickup_p0b_audit_decision_check.py` — 회귀 14건. 커밋 `d8e59830`.
- `memory/reports/task-2729+5-p0b-audit-first.md` — 본 보고서.
- `memory/plans/p0b-pickup/controlled_pilot_design_260605.md` — 1회성 pilot 설계서.

수정(런타임/systemd/canonical): **0건**. forbidden paths 무수정 확인.

## 5. 테스트 결과

- 신규 회귀: `test_anu_pickup_p0b_audit_decision_check.py` **14 passed**.
- 기존 회귀 무영향: `test_anu_pickup_driver_2721.py` + `test_anu_result_pickup_runner_2720.py` **46 passed**.
- 통합: **60 passed in 0.47s**, FAIL 0.

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

- **서버 재시작**: 해당없음 (시스템 audit 작업 — 서버/대시보드 무관).
- **API 응답 확인**: 해당없음 (HTTP API 무관). 대신 **decision-only 하니스 실동작 실행**으로 대체:
  - `python3 scripts/harness/v36/anu_pickup_p0b_audit_decision_check.py --json` → **exit 0**.
  - 결과: `all_pass=true`, `canonical_untouched=true`, `raw_key_exposure=0`, `findings=[]`.
  - decision 11/11 PASS: DC1 NOOP_DISABLED(0), DC2 NOOP_NOT_TARGET(0), DC3 WAKE_BUILT(pickup 1), DC4 PICKUP_SKIP(0), DC5 PICKUP_SKIP(0), DC6 QUARANTINE(0), DC7 NOOP_NOT_READY(0), DC8 QUARANTINE(0), DC9 WAKE_BUILT(누적 pickup 1), DC10 SEALED_KEY_MISSING(0), DC11 SKIP_TERMINAL(0).
- **스크린샷**: 해당없음 (CLI/시스템 audit — 브라우저 무관).
- **isolated temp root dry-run evidence**: `/tmp/p0b_l1.json` (실행 산출). canonical `/home/jay/workspace` memory/events·ledger·state 변화 0 확인.

★ pytest PASS 외에 **실제 하니스 프로세스 1회 실행 + exit 0 + 결정값 일치**로 실동작 확인 완료.

## 7. capability delta

- 변화: audit 재검증 + decision-only dry-run 증거 + pilot 설계 산출. **런타임 capability 변화 0**.
- ACTIVE 상태: **false 유지**(불변). 감지경로 systemd 미설치·flag 부재 그대로.
- 신규 capability: P0-b 감지경로를 canonical 무영향으로 반복 재현·검증할 수 있는 read-only 하니스 확보.

## 8. 발견 이슈 및 해결

- **이슈1**: audit 대상 파일이 현재 메인 워크스페이스 working tree 에 부재(메인이 타 task 브랜치 점유). → **해결**: origin/main 기반 격리 worktree 생성 후 정본 blob 기준 audit. canonical 무영향.
- **이슈2**: pre-commit guard 가 `.tasks/locks/task-2729+5.lock` 요구, guard 전체 실행은 메인 워크스페이스가 main 미점유(#7)로 차단. → **해결**: 환경적 선행조건(타 task 브랜치 점유)으로 본 task 범위 밖. lock 파일을 정규 스키마로 생성(검증 #1~#6 통과 확인)하여 커밋 진행. (canonical 무영향)
- **미해결(범위 외, 활성화 task input)**: C1 `scan_once` MAX_FILES 상한, C2 ledger/marker 쓰기 실패 명시적 관측. 본 task 는 audit-first 라 코드 구현 미수행 — pilot 설계서 §7 에 보완항목으로 기록.

## 9. 머지 판단

- **머지 필요**: Yes (Lv.2+, worktree 산출물 → PR 경유 권장)
- **브랜치**: `task/task-2729+5-dev4`
- **워크트리 경로**: `/home/jay/workspace/.worktrees/task-2729+5-dev4`
- **머지 의견**: 신규 파일 4건(런타임/systemd/canonical 무수정), 회귀 60 passed, 충돌 가능성 낮음(신규 경로만). 단 메인 워크스페이스가 타 task 브랜치 점유 중이라 머지 타이밍은 아누 조정 권장.

## 10. 모델 사용 기록

- 카르티케야(백엔드, decision-check 스크립트): **sonnet** — 일반 코딩/로직.
- 하누만(테스터, 회귀): **sonnet** — 테스트 작성.
- 비슈누(팀장, audit/보고서/pilot 설계/통합): Opus(직접 수행 — 감지경로 audit 분석·docstring 정리·문서는 판단/통합 영역).
- haiku 미사용.

## 11. 산출 판정

**DISPATCH_READY_FOR_CONTROLLED_PILOT** — audit PASS + decision-only dry-run 증거(11/11) + 1회성 pilot 설계 완료. 실제 pilot 실행 및 ACTIVE=true 전환은 **회장 승인 대기**. 최종 상태 = IMPLEMENTED / WIRED candidate / ACTIVE=false 유지.
