# OS_LEVEL_PICKUP_RUNNER_SPEC_VALIDATION_PACKET (D-SPEC-EXACTNESS self-check — 구현/PR/설치/ACTIVE=true/queue 0)

작성: 2026-06-09 KST / ANU 직접 read-only verbatim 대조 / base CODE=/home/jay/p0b-pickup-main
상태: `OS_LEVEL_PICKUP_RUNNER_SPEC_VALIDATION_PENDING_ACTIVE_FALSE`
목적: IMPLEMENTATION_SPEC_PACKET 을 구현 task 발행 전 D-SPEC-EXACTNESS(self-check→external lint→spec-anchor) 검증. **self-check 는 통과 선언이 아니라 실코드 대조로 drift 적발+정정.**

## 1. D-SPEC-EXACTNESS self-check 결과 — ★ 3 DRIFT 적발+정정
verbatim 대조(실코드 grep)로 spec 가정과 실코드 불일치 3건 발견. 정직 기록:

- **DRIFT-1 (시그니처 오류, 정정 필수)**: spec §12 가 `process_one(dry_run=True)` 를 가정했으나 **실 `process_one` 시그니처에 `dry_run` 파라미터 부재**. 실코드는 `launcher_fn=None`(미주입=surface-only=실행 0) + isolated temp(`quarantine_dir`/`processed_dir`/`ledger_path` 주입)로 dry-run 효과 달성.
  - **정정**: dry-run = "launcher_fn 미주입 + relay_fn 미주입 + isolated temp dir 주입"으로 정의(신규 dry_run 플래그 도입은 선택 — 최소변경 위해 미도입 권장). spec §12 이 표현으로 교체.
- **DRIFT-2 (레이어 혼동, 명확화)**: owner outcome enum(`OWNER_ANU=ANU_OWNED` / `OWNER_NOT_ANU=NOT_ANU_OWNED_OR_ACCESS_DENIED` / `OWNER_QUERY_FAILED=QUERY_FAILED` / `OWNER_PENDING=PENDING_OWNER_PROOF`)은 `resolve_authoritative_owner` **내부** 레이어. process_one 이 실제 보는 분기는 `verify_fn(...).verdict == VERDICT_AUTHORITATIVE("AUTHORITATIVE")` **단일 레이어**.
  - **정정**: spec §6 처리표는 owner-proof **2-레이어**로 표기 — (L1 내부) OWNER_* 4-outcome → (L2 process_one) AUTHORITATIVE 여부. closeout 분기는 L2(AUTHORITATIVE) 기준, QUARANTINE/PENDING 세부 사유는 L1 outcome 으로 collector_result.owner_proof 에 기록.
- **DRIFT-3 (마커 혼동, 정정 필수)**: spec §7 이 idempotency 마커를 "`memory/events/<task_id>.done`→`.done.acked`(CLAUDE.md 팀 .done 프로토콜)"로 기술했으나, **실 driver/runner idempotency 마커는 `<task_id>.pickup.done` + `acked_path`**(runner L187 `os.path.exists(done_path) or os.path.exists(acked_path)`). CLAUDE.md 의 팀장 완료 `.done`→`.done.acked` 는 **별개 레이어**(팀 완료 감지).
  - **정정**: collector closeout idempotency 마커 = `<task_id>.pickup.done`(+ acked_path 계열), 팀 `.done` 프로토콜과 **혼용 금지**. spec §7 이 마커명 교체.
- enum/verdict 상수명(VERDICT 9종·OWNER 4종·VERDICT_AUTHORITATIVE)은 verbatim 일치 ✓. collector_result.json·anu-pickup.timer 미존재=신규 확정 ✓.
- **self-check 판정**: PASS_WITH_CORRECTIONS — 3 drift 정정 후 external lint 진입 가능. 정정 전 dispatch 금지.

## 2. expected_files 최종 목록
- **신규(5)**: `deploy/systemd/anu-pickup.timer` · `dispatch/anu_collector_result.py` · `dispatch/anu_terminal_relay.py` · `tests/test_anu_collector_result.py` · `tests/test_anu_pickup_closeout.py`(+ relay 테스트는 closeout 테스트에 통합 가능 — 최종 3 test 파일 이내).
- **수정(2)**: `dispatch/anu_pickup_driver.py`(process_one deterministic closeout 삽입+agent_relay 분기) · dev bot dispatch prompt 템플릿(callback_schedule_created:false 명문).
- **재사용·수정 0(5)**: `dispatch/anu_owned_callback_enforcement.py` · `dispatch/anu_result_pickup_runner.py` · `scripts/anu_pickup_entrypoint.sh` · `deploy/systemd/anu-pickup.path` · `deploy/systemd/anu-pickup.service`.
- **후속·이 task 비포함(1)**: PreToolUse hook(11).

## 3. 각 expected_file 의 변경 목적
- `anu-pickup.timer`(신규): path 보완(missed event/boot/daemon gap) — OnBootSec+OnUnitActiveSec, 같은 service 호출.
- `anu_collector_result.py`(신규): collector_result.json dataclass+atomic writer(os.replace), raw key 0.
- `anu_terminal_relay.py`(신규): 2-tier relay(기본 sendfile 보고 / 예외 cron ANU). merge/dispatch/PR 0.
- `tests/*`(신규): isolated regression(verdict·owner-proof 4·agent_relay·green-path wake 0·idempotency).
- `anu_pickup_driver.py`(수정): process_one 의 L2 AUTHORITATIVE PASS↔launcher 사이에 closeout 삽입 → CLOSEOUT_DONE green-path. launcher_fn surface-only 보존.
- dev bot dispatch prompt(수정): callback_schedule_created:false 계약+result.json only.

## 4. forbidden_write_targets
- `dispatch/anu_owned_callback_enforcement.py` 의 owner-proof 핵심(resolve_authoritative_owner/verify_collector_authoritative/probe) — **수정 0**(재사용만).
- `.env.keys`, sealed key 파일 — read-only 로더만.
- `scripts/harness/*`, canonical reset/clean/stash/checkout -f 경로.
- 기존 `memory/events/*`(legacy 128) — closeout 신규 산출(collector_result) 외 기존 result.json/마커 변형 0.
- p0b flags(`memory/state/p0b_driver_enabled`·`p0b_real_wake_enabled`·`p0b_activation_epoch`) — 구현이 enable/설정 **금지**(activation 단계 회장 승인만).
- `anu-pickup.path`/`.service`/`entrypoint.sh` — 수정 0.

## 5. green-path CLOSEOUT_DONE 정의
- 조건(전부 충족): target=task-*.result.json final + schema PASS + (not legacy) + readiness PASS + dedupe miss + **L2 verify=VERDICT_AUTHORITATIVE**(L1 OWNER_ANU) + scope PASS + **agent_relay.required=false**.
- 동작: collector_result.json(closeout_action=done_acked) atomic write + `<task_id>.pickup.done` 마커 + dedupe ledger append. **launcher/relay 호출 0(wake 0).**
- = green-path 결정론 종료 주경로. 기존 WAKE_BUILT 는 agent_relay 예외 시에만.

## 6. agent_relay.required 예외 정의
- required=true 트리거(5): `quarantine_reason`(L1 NOT_ANU/QUERY_FAILED) · `gemini_finding` · `merge_ready_ambiguous` · `critical7` · `consolidated_report`.
- required=false(green): 위 표식 0 → CLOSEOUT_DONE. (선택) sendfile 보고만.
- 예외 동작: 2-tier 중 **cron ANU relay 1회**(terminal relay, merge/dispatch/PR 금지). collector_result.agent_relay 에 reason 기록.

## 7. owner-proof 4-outcome 처리표 (DRIFT-2 정정 반영, 2-레이어)
| L1 outcome(resolve) | L2(process_one verify) | closeout |
|---|---|---|
| OWNER_ANU (ANU_OWNED) | AUTHORITATIVE | green CLOSEOUT_DONE(또는 agent_relay 예외 시 relay) |
| OWNER_NOT_ANU | ≠AUTHORITATIVE | **fail-closed** QUARANTINE + agent_relay(quarantine_reason) |
| OWNER_QUERY_FAILED | ≠AUTHORITATIVE | **fail-closed** QUARANTINE |
| OWNER_PENDING | ≠AUTHORITATIVE | **retry 보류** NOOP_NOT_READY(deferred, false quarantine 차단) |
- `self_key_used:true`→거부 / stale→staleness REJECT. read-only cron-history(발사 0)→coupling 무관.

## 8. idempotency 3중 구조 (DRIFT-3 정정 반영)
- (a) dedupe ledger((task_id, source_result_sha256), pickup_once 패턴 재사용).
- (b) **`<task_id>.pickup.done` + acked_path**(runner 기존 `done_path or acked_path` 체크 재사용) — **driver/collector 전용 마커, CLAUDE.md 팀 .done 프로토콜과 별개**.
- (c) flock single-flight(entrypoint, 기존).
- path 재발화/timer 중복/재부팅 → SKIP. real closeout 1회.

## 9. legacy / epoch fail-closed 검증
- `_legacy_cutoff_check`: epoch **부재→skip("epoch_absent")**(fail-open 금지) / mtime<epoch→NOOP_LEGACY_SKIP(move0/wake0/quarantine0/collector_result 미작성) / mtime≥epoch→정상.
- 기존 events 128(activation 이전)=전부 legacy→무변동 보장. 회장 전제3·4 정합 ✓.

## 10. callback_schedule_created:false enforcement 위치
- **위치 3**: (a) dev bot dispatch prompt 명문(작성 계약) (b) result.json schema 필수 필드(`callback_schedule_created:false`) (c) runner 검증 — 필드 부재/true → collector_result 에 `contract_violation` 기록 + (즉시분) 관측. **차단은 후속 hook(11).**
- 즉시분 = 관측·기록(필드+prompt). 실차단 = hook.

## 11. PreToolUse hook 후속 범위 (이 task 비구현)
- 범위: dev bot 세션 settings 의 PreToolUse hook — Bash tool 의 `cokacdir ... --cron` 패턴 deny(self-collector 근원 실차단).
- 결선: 세션 launch settings.json hook 등록 + 미적용 시 dispatch 거부 fail-closed.
- ★ false positive 회피(정상 cokacdir 사용과 cron 등록 구분) + 세션 결선 = **별도 task**. 이 spec 은 설계만, 구현 0.

## 12. external lint(Codex) 필요 여부 + 체크 항목
- **필요: YES**(Lv.3+ runtime code·governance 민감·self-collector 경계). self-check PASS_WITH_CORRECTIONS 는 필요조건이지 충분조건 아님.
- Codex 체크 항목:
  1. DRIFT 1~3 정정이 spec 본문에 정확 반영됐는지(dry_run 부재·2-레이어·pickup.done 마커).
  2. process_one closeout 삽입이 기존 launcher_fn surface-only/ACTIVE=false 불변을 깨지 않는지.
  3. owner-proof read-only(cron-fire 0) 보장 — relay 외 경로에서 --cron 호출 0.
  4. agent_relay 예외 cron relay 가 merge/dispatch/PR API 정적 차단인지.
  5. legacy/epoch fail-closed(fail-open 경로 0).
  6. collector_result raw key 0(argv literal/owner_key 0).
  7. idempotency 3중이 race(동시 path+timer)에서 1회 보장.
  8. forbidden_write_targets 정적 가드.
  9. callback_schedule_created enforcement 가 관측(즉시)·차단(후속) 분리 정확.
- ※ external lint = **dispatch 직전** 단계. lint 전 dispatch 금지.

## 13. implementation task 발행 전 회장 승인 필요 항목
1. DRIFT 1~3 정정 spec 승인.
2. expected_files 최종(5신규+2수정+5재사용+1후속) 승인.
3. external lint(Codex) 실행 승인.
4. lint 결과(HIGH/CRITICAL 0) 후 dispatch 승인.
5. systemd 설치·flag enable·activation_epoch 설정 = **구현 후 별도 activation 승인**(이 단계 아님).
6. ACTIVE=false 유지(구현·테스트 동안).

## capability matrix
- self_check = PASS_WITH_CORRECTIONS(3 DRIFT 정정).
- external_lint = REQUIRED_NOT_YET_RUN.
- spec_status = NOT_LOCKED(정정+lint 전).
- ACTIVE=false / production_activation_gate = HARD BLOCK.

## 금지 (현재)
구현 / PR / systemd 설치 / ACTIVE=true / production queue 처리 / daemon restart / direct Claude launch / 추가 canary / **external lint 전 dispatch**. **validation packet 까지만.**

## 판정
- **OS_LEVEL_PICKUP_RUNNER_SPEC_VALIDATION_PACKET_READY**. self-check=PASS_WITH_CORRECTIONS(DRIFT-1 dry_run 부재·DRIFT-2 owner 2-레이어·DRIFT-3 pickup.done 마커 정정). expected_files 5신규+2수정+5재사용+1후속. external lint(Codex) 9 체크항목 REQUIRED. spec NOT_LOCKED. 정정 spec 승인→lint 승인→lint GREEN→dispatch 승인 순. 구현/설치/canary=회장 별도 승인.
