# task-2730 — OS-level pickup runner deterministic closeout 구현 (DESIGN_LOCKED · dispatch 미승인)

상태: `OS_LEVEL_PICKUP_RUNNER_DESIGN_LOCKED_TASK_SPEC_PENDING_ACTIVE_FALSE`
작성: 2026-06-10 KST / ANU / base CODE=/home/jay/p0b-pickup-main(origin/main #186/#187)
★ 이 파일은 **구현 task 명세 + spec-anchor**. **dispatch 미승인** — 회장 최종 dispatch 승인 전 발사 0.

## 0. SPEC-ANCHOR (D-SPEC-EXACTNESS 무결성)
- **locked design reference (단일 출처)**:
  - `memory/plans/p0b-pickup/os_level_pickup_runner_design_lock_candidate_packet_260610.md` sha256=`57194abc002cc37c4847193eba750fe6f2de8ca4c72d8a6ba0297eb68b826534`
  - `memory/plans/p0b-pickup/os_level_pickup_runner_corrected_spec_v2_packet_260609.md` sha256=`876ee683d04c7a6ff2521b1e0a4a84ee0b06438586290e4cddad36ea162d7502`
- **보존 anchor (최소 2, 축약/삭제 금지)**:
  - ANCHOR-A: closeout write OWNER = `pickup_once`(+helper `anu_collector_result.write_collector_result`), **process_one 미소유**.
  - ANCHOR-B: durability order = **ledger(dedupe·fsync) → collector_result(atomic os.replace) → done marker(terminal sentinel·마지막)**.
- 구현은 이 anchor 와 design reference 를 위반하면 HOLD. 봇이 spec 축약/재해석 금지.

## 1. locked design reference
- 위 §0 2개 packet 이 design 단일 출처. 본 task md 와 충돌 시 design packet 우선. 핵심:
  - OS pickup runner=production path 주경로. green result.json=runner deterministic closeout(CLOSEOUT_DONE, wake 0). agent_relay.required 예외만 2-tier terminal relay. detection=systemd path+timer. owner-proof=read-only cron-history. legacy/epoch fail-closed.

## 2. expected_files
- **신규(≤5)**: `deploy/systemd/anu-pickup.timer` · `dispatch/anu_collector_result.py` · `dispatch/anu_terminal_relay.py` · `tests/test_anu_pickup_closeout.py`(collector/relay 테스트 통합 허용, 총 테스트 ≤3 파일).
- **수정(3)**: `dispatch/anu_result_pickup_runner.py`(closeout 통합 + CLOSEOUT_DONE verdict) · `dispatch/anu_pickup_driver.py`(VERDICT_CLOSEOUT_DONE + relay 분기) · dev bot dispatch prompt 템플릿(relay_hints + callback_schedule_created contract).
- expected_files 밖 수정 = scope 위반 HOLD.

## 3. forbidden_write_targets
- `dispatch/anu_owned_callback_enforcement.py` owner-proof 핵심(resolve_authoritative_owner / verify_collector_authoritative / RealCokacdirCronHistoryProbe) — **수정 0**(재사용만).
- `.env.keys` / sealed key — read-only 로더만.
- `scripts/anu_pickup_entrypoint.sh` · `deploy/systemd/anu-pickup.path` · `anu-pickup.service` — **수정 0**.
- `scripts/harness/*`, canonical reset/clean/stash -u/checkout -f.
- p0b flags(`memory/state/p0b_driver_enabled` · `p0b_real_wake_enabled` · `p0b_activation_epoch`) — enable/설정 **금지**.
- 기존 `memory/events/*`(legacy 128) — collector_result 신규 산출 외 기존 result.json/마커 변형 0.

## 4. implementation scope
- **A. pickup_once closeout 통합**(`anu_result_pickup_runner.py`): owner-proof AUTHORITATIVE + sealed-key 후, **§8 ledger append 직후 ↔ §9 marker 직전**에:
  - result.json `relay_hints` 읽어 `agent_relay.required` 판정(quarantine_reason=L1 NOT_ANU/QUERY_FAILED runner 생성, 4종=relay_hints 필드만·추론 0).
  - required=false → `write_collector_result(closeout_action=done_acked)` → marker → **CLOSEOUT_DONE 반환**(wake argv 미사용).
  - required=true → 기존 wake argv 경로 → collector_result(relay) → marker → WAKE_BUILT.
  - 순서 불변(ANCHOR-B): ledger→collector_result→marker.
- **B. collector_result writer**(`anu_collector_result.py`, 신규): schema dataclass + atomic os.replace writer. 필드=task_id/source_result_sha256/verdict/owner_proof{l1_outcome,l2_verdict,schedule_id,query_ok}/dedupe/scope/closeout_action/agent_relay{required,reason}/contract_violation/ts_kst/runner_version. **raw key 0**.
- **C. terminal relay**(`anu_terminal_relay.py`, 신규): allowlist-only static. 2함수(send_report=`cokacdir --sendfile` 고정argv / relay_to_anu=`cokacdir --cron` 고정argv). shell=False·git/gh/dispatch/merge import 0·subcommand 화이트리스트.
- **D. driver verdict 분기**(`anu_pickup_driver.py`): pickup verdict CLOSEOUT_DONE→VERDICT_CLOSEOUT_DONE(launcher 미호출, move_processed) / WAKE_BUILT→relay 분기.
- **E. systemd timer**(`anu-pickup.timer`, 신규): OnBootSec+OnUnitActiveSec=120s, 같은 service 호출. **파일 작성만**(설치 0).
- **F. devbot prompt**: relay_hints + callback_schedule_created:false contract 명문.
- 신규 owner 로직 0(owner-proof 재사용).

## 5. non-scope / forbidden actions
- systemd `systemctl enable/start` 실행 — **금지**(unit 파일 작성만).
- p0b flag enable / activation_epoch 설정 — **금지**.
- production result.json(events 128) 실처리 — **금지**.
- owner-proof 로직 수정 / 신규 owner 판정 — **금지**.
- same-PR post-Gemini push / bot trigger(/gemini review 봇 작성) / chain 무한 +N / long polling 대기 — **금지**(doctrine).
- expected_files 밖 수정 / spec 축약 / 수동 .done — **금지**.

## 6. regression plan
- ① owner-proof L1/L2: OWNER_ANU→CLOSEOUT_DONE / NOT_ANU·QUERY_FAILED→QUARANTINE(fail-closed) / PENDING→NOOP_NOT_READY(retry) / self_key_used→거부.
- ② agent_relay: relay_hints 4종 각 true→relay 분기 / 전부 false→green CLOSEOUT_DONE(wake 0) / 필드 부재→false.
- ③ durability: ledger→collector_result→marker 순서 + crash 3케이스(ledger후/collector후marker전/marker후) 단일 closeout.
- ④ idempotency: dedupe ledger + pickup.done/acked + flock, path+timer race 1회.
- ⑤ terminal relay static: shell=False·merge/dispatch/PR import 0(정적 검사) assert.
- ⑥ green-path launcher_fn 호출 0 assert(wake 0).
- ⑦ collector_result raw key 0(owner_key/argv literal 0).
- ⑧ legacy/epoch fail-closed + DRIFT-1/2/3 회귀(유지 PASS).

## 7. dry-run isolated validation
- flag OFF + isolated temp(quarantine_dir/processed_dir/ledger_path/evidence_path 주입) + launcher_fn/relay_fn 미주입.
- fixture: fake cron-history probe(OWNER_ANU/NOT_ANU/QUERY_FAILED/PENDING) + fake result.json(완전/relay_hints/schema 위반/legacy/dedupe/self_key).
- **canonical events 0 touch** assert. 실 wake/relay/마커(canonical) 0.

## 8. implementation 후 external lint 재실행 조건
- 구현+regression GREEN 후 **구현물 재lint**(Codex, design-lock candidate §3 10항목): closeout owner/durability order/CLOSEOUT_DONE 정의/relay_hints read path/terminal_relay static import 검사/idempotency 3-stage crash+flock/raw key0/green flag gate/legacy·DRIFT 회귀/regression·dry-run isolated.
- **HIGH/CRITICAL=0 → spec LOCKED**. 미충족 시 AUTO_REMEDIATION(non-Critical) 또는 회장 보고(Critical7).

## 9. systemd 설치 금지
- 구현 task = unit 파일(`anu-pickup.timer`) **작성만**. `systemctl --user enable/start` 0. path/timer/service 미설치 유지. 설치=activation 단계 별도 승인.

## 10. ACTIVE=true 금지
- p0b_driver_enabled·p0b_real_wake_enabled enable 0. ACTIVE=false 유지. 구현·regression·dry-run=flag OFF + isolated.

## 11. production queue 처리 금지
- events 128(legacy) 무변동. activation_epoch 미설정→전 result legacy fail-closed. production result 실처리 0. test=isolated fixture(canonical 0 touch).

## 12. dispatch 전 회장 최종 승인 필요
1. **(현재)** task md + spec-anchor 회장 검토.
2. dispatch 승인(팀 배정·발사) — **회장 명시 승인 전 발사 0**.
3. 구현 완료 → regression/dry-run GREEN 보고.
4. 구현물 재lint HIGH/CRITICAL=0 → spec LOCKED.
5. systemd 설치·flag·epoch = 별도 activation 승인(ACTIVE=true 전).

## 금지 (현재)
구현 / dispatch / PR 생성 / systemd 설치 / ACTIVE=true / production queue 처리 / canary 실행. **task md + spec-anchor 보고까지만.**

## 판정
- task-2730 구현 task md + spec-anchor READY. locked design ref 2 packet(sha256 고정) + 보존 anchor 2(closeout owner=pickup_once / order ledger→collector→marker). expected_files 4신규+3수정. regression 8 + dry-run isolated + 구현 후 재lint(HIGH/CRITICAL=0→LOCKED). dispatch=회장 최종 승인 대기. 구현/설치/canary 0.
