# task-2721+4 — PR #167 P0-b CRITICAL+HIGH fix: path watcher 무한 재트리거 차단 + lock 경로 안전화

## 회장 인가 (2026-06-02, Option 1 — fresh CRITICAL+HIGH 명시 승인)
PR #167(head `818b351f`) fresh:
- **CRITICAL(무한 재트리거)**: 처리 완료된 `task-*.result.json` 이 계속 `PathExistsGlob` 대상에 남아 systemd path watcher 가 **무한 재감지/재실행**. P0-b OS-level pickup 핵심 안정성.
- **HIGH(/tmp lock)**: `/tmp` 고정 lock 파일 = symlink/truncation 위험.
dismiss 금지. PR hold/전면 재설계 없이 **expected_files 6개 내부 bounded fix**.
★ 이번이 fresh CRITICAL+HIGH 명시 승인. 이 후 또 새 HIGH/CRITICAL 나오면 추가 자동 fix 금지 → CHAIR_REQUIRED.

## worktree
- `/home/jay/workspace/.worktrees/task-2721-dev1` (branch `task/task-2721-dev1`, head `818b351f`)에서 **이어서**. base origin/main 29175f80(P0-a 포함).

## expected_files (PR #167 동일 6개 — 그 외 수정 금지)
1. `deploy/systemd/anu-pickup.path`  ← 수정 허용
2. `deploy/systemd/anu-pickup.service`
3. `scripts/anu_pickup_entrypoint.sh`  ← 수정 허용(lock 경로)
4. `dispatch/anu_pickup_driver.py`  ← 주 수정(terminal 파일 처리)
5. `tests/regression/test_anu_pickup_driver_2721.py`
6. `docs/p0b_driver_runbook_260601.md`
★ `scripts/finish-task.sh` 수정 금지(result.json writer atomic 화 = **P0-b+1 후속 유지**). P0-a main 무수정.

## 수정 1 — CRITICAL: 무한 재트리거 차단 (terminal 파일 처리)
- ★ 처리 완료된 result.json 이 **PathExistsGlob 대상에 계속 남지 않도록** driver 처리 후 terminal 파일을 **안전하게 이동/rename**.
- **terminal verdict별 파일 처리 정책 명확화**:
  - `WAKE_BUILT`(wake 성공) → result.json 을 **watched 밖**(예: `memory/p0b_state/processed/`)으로 이동(또는 `.consumed` rename 으로 `task-*.result.json` glob 비대상화).
  - `PICKUP_SKIP`(이미 처리/dedupe/done) → 동일하게 glob 비대상으로(재감지 0).
  - `QUARANTINE` → 기존대로 watched 밖 quarantine 이동(재감지 0).
  - `NOOP_NOT_READY`/`DEFER` → **그대로 둠**(다음 트리거 재평가 — 의도적 잔류, 단 grace 후 terminal 처리).
  - `NOOP_NOT_TARGET`/`NOOP_DISABLED` → 파일 미이동(원래 대상 아님/비활성).
- ★ 이동/rename 은 `os.replace`/`shutil.move` 로 atomic. 이동 실패 시 fail-safe(크래시 0, evidence 기록). **단 result writer atomic 화는 하지 말 것**(소비 측 이동만).
- 결과: terminal 도달분은 glob 재매칭 0 → systemd path watcher 무한 재트리거 소멸. DEFER 만 일시 잔류(grace 후 수렴).

## 수정 2 — HIGH: lock 경로 안전화 (/tmp 고정 중단)
- ★ `/tmp` 고정 lock 파일 사용 **중단**. **workspace/state 내부 안전 경로** 사용(예: `memory/p0b_state/locks/anu-pickup-${UID}.driver.lock` 또는 `$XDG_RUNTIME_DIR` 우선 + workspace fallback).
- lock 파일 생성 시 **parent dir 존재/권한 안전 보장**(`mkdir -p` + 소유자 한정), **symlink/truncate 위험 제거**(예: `flock` 대상 파일을 O_NOFOLLOW 류/심볼릭 거부, world-writable 디렉터리 회피).
- driver-level flock single-flight 유지. ★ pickup_once 내부 lock 재도입 금지(lock-free 유지).

## 수정 3 — medium 2건 (조건부)
- dedupe 성능 / quarantine overwrite medium 은 **이번 CRITICAL/HIGH 안정성에 직접 필요한 작은 보강이면 함께** 처리. 범위 커지면 **evidence-based resolve 후보로 분리**(코드 변경 0).
- quarantine overwrite: 동일 basename 재격리 시 덮어쓰기 방지(타임스탬프/카운터 suffix) — 작은 보강이면 포함.

## regression (추가/갱신)
- 기존 26 PASS 유지/증가.
- ★ **처리 완료 result.json 이 path watcher 재트리거 대상에 남지 않음**: WAKE_BUILT/PICKUP_SKIP/QUARANTINE 후 `task-*.result.json` glob 재매칭 0(이동/rename 입증).
- ★ **DEFER 는 잔류**(재평가 대상) — terminal 아님 입증.
- ★ **/tmp lock symlink/truncation 위험 제거** 입증(정적: `/tmp` 고정 0 + symlink 거부 로직 / 또는 테스트).
- 기존: 오래된 invalid JSON quarantine / recent partial JSON DEFER / path-traversal / fail-safe / 출력물 watched 밖 / default no-op 유지.
- pickup_once 전부 mock/stub. 실 pickup/wake/ANU key wake 실행 0. key literal 0.

## 검증 (finalize 전)
- `python3 -m pytest tests/regression/test_anu_pickup_driver_2721.py -q` 전 PASS(26→증가).
- `git diff --name-only origin/main` = 6파일. finish-task.sh 0. ANU key net-new 0.
- terminal 파일 이동/rename 로직 존재. `/tmp` 고정 lock 0. parent dir 보장 + symlink 방어 존재.

## 금지 (회장 verbatim)
- finish-task.sh 수정 금지(writer atomic = P0-b+1 유지) · systemctl enable/start/daemon-reload 금지 · unit 설치 금지 · activation flag 생성 금지.
- 실 pickup/wake/ANU key wake 실행 금지 · merge 금지 · force push/rebase/admin override 금지.
- ANU key literal 노출 0 · pickup_once lock 재도입 금지 · P0-a main 무수정 · expected_files 밖 수정 금지.
- active=false / installed=false / wired=false 유지. capability matrix 과장 금지.
- ★ 새 HIGH/CRITICAL 또 발생 / expected_files 밖 / 권한확장 / forbidden / 동일 blocker 반복 시 → 추가 fix 금지, **CHAIR_REQUIRED 보고**.

## finalize (로컬 commit 까지만)
1. fix → regression PASS → `git add` 6파일 → 로컬 commit. **push/PR/merge 금지(ANU 수행)**.
2. `memory/reports/task-2721.md` 에 CRITICAL+HIGH fix 내역(terminal 파일 처리 / lock 경로 안전화) 추가.
3. `memory/events/task-2721+4.done` 생성. ANU key(c119085, sealed) callback. ★ ANU key literal 노출 0.

## ANU 후속 (봇 아님 — governance)
독립 재검증(6파일/terminal 이동·glob 재매칭 0/DEFER 잔류/lock 경로 안전·/tmp 고정 0/regression/key 0/active=false) → FF push → OWNER `/gemini review` 1회 → CI GREEN + fresh unresolved 0 → **MERGE_READY_CANDIDATE** 보고 / 새 HIGH·CRITICAL·동일 blocker 반복 시 CHAIR_REQUIRED. merge 회장 승인 전 금지.

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "deploy/systemd/anu-pickup.path"
    - "deploy/systemd/anu-pickup.service"
    - "scripts/anu_pickup_entrypoint.sh"
    - "dispatch/anu_pickup_driver.py"
    - "tests/regression/test_anu_pickup_driver_2721.py"
    - "docs/p0b_driver_runbook_260601.md"
    - "memory/events/task-2721+4.done"
    - "memory/reports/task-2721.md"
  forbidden_paths:
    - "scripts/finish-task.sh"
    - "dispatch/anu_result_pickup_runner.py"
    - "dispatch/anu_owned_callback_enforcement.py"
    - ".github/**"
  commands:
    - "pytest"
    - "python3 -m pytest"
    - "python3 -m py_compile"
  merge_policy: "none"
  ttl_hours: 48
```

## ★ dispatch 템플릿 G3(PR/머지) 무시. finalize 로컬 commit only. finish-task --action pr/systemctl/설치 일체 금지.

## goal_assertions (auto-generated)
- `python3 -m pytest tests/regression/test_anu_pickup_driver_2721.py -q`
- `python3 -c "import sys; s=open('scripts/anu_pickup_entrypoint.sh').read(); sys.exit(0 if '/tmp/anu-pickup' not in s else 1)"`
- `python3 -c "import sys; s=open('dispatch/anu_pickup_driver.py').read(); sys.exit(0 if ('os.replace' in s or 'shutil.move' in s) and 'processed' in s.lower() or 'consumed' in s.lower() else 1)"`