# task-2773 — Delegation Completion Watcher 구현 (workspace 모듈+ledger+테스트)

## 목표 (ANU 완료감지 강제화 — 텍스트 규율 아닌 실행 장치)
ANU 가 dispatch 한 task 의 완료 산출물(.done/.failure-envelope/result.json/PR)을 **강제 감지**하는 watcher 의 **workspace 코드부**를 구현한다. ★merge/activation 무관 · 완료감지 축만. ANU 설계: `memory/reports/delegation_completion_watcher_design_260624.md`.
★ hook wiring(~/.claude/...)과 matrix delta 는 **ANU 가 직접**(이 task 범위 밖). 이 task 는 **workspace 모듈+ledger 호출+테스트만**.

## expected_files (정확히 3개 = 수정 허용)
```text
utils/delegation_watcher.py                       # 신규 모듈
dispatch/core.py                                  # dispatch 성공 지점에 record_delegation() 호출 1줄 (정확 지점 확인 후)
tests/regression/test_delegation_watcher_2773.py  # 신규 테스트 4종
```
※ dispatch 실 성공 지점이 dispatch/__init__.py 라면 그쪽으로 — 단 **둘 중 하나만**(dispatch 패키지 1파일). 확인 후 결정. dispatch.py(86줄 wrapper) 는 건드리지 말 것.

## 구현 지시 (최소·정확)
### utils/delegation_watcher.py (신규, self-contained stdlib)
- `record_delegation(task_id, bot, team, branch, expected_result_paths, dispatch_time, ledger_path=None)` → `memory/state/pending_delegations.jsonl` 에 1줄 append (status="pending"). 중복 task_id 는 append(audit, 최신 우선).
- `check_pending_delegations(workspace=None, ledger_path=None) -> list[dict]` → ledger 의 status="pending" 항목마다:
  - expected_result_paths(.done/.failure-envelope.json/result.json) 디스크 존재 확인.
  - `.done` 존재 → `status_detected="done"`. `.failure-envelope.json` → `failure`. result.json/PR deliverable 있고 `.done` 부재 → **`ready_for_adjudication`**(실패 단정 금지).
  - `.supervisor-crash-marker.json` 존재 → `crash=true` 기록하되, deliverable(result.json/PR) 있으면 `deliverable_ok=true` 로 **분리 평가**(crash 만으로 실패 단정 금지).
  - 반환: hook 이 주입할 수 있는 dict 리스트(task_id·detected·crash·deliverable_ok·needs_adjudication).
- `close_delegation(task_id, status, ledger_path=None)` → ledger 에 close 레코드 append(status in {done/failure/essence_pass/merged}).
- `render_pending_briefing(items) -> str` → hook 주입용 짧은 텍스트(pending/ready_for_adjudication 강조). 없으면 빈 문자열.

### dispatch ledger 호출
- dispatch 성공(봇 spawn dispatched) 지점에서 `record_delegation(...)` 호출 1줄. expected_result_paths = [`memory/events/<task>.done`, `memory/events/<task>.failure-envelope.json`, result.json 경로]. 실패해도 dispatch 비차단(try/except).

### tests/regression/test_delegation_watcher_2773.py (4종, 회장 명시)
1. **ledger 생성**: record_delegation 후 pending_delegations.jsonl 에 항목 존재.
2. **result.json/.done 분리**: result.json(또는 .done 부재 + deliverable) 시 `ready_for_adjudication` 후보로 올라옴(.done 부재만으로 실패 아님).
3. **supervisor-crash 분리**: .supervisor-crash-marker.json + result.json 동시 존재 시 crash=true 이나 deliverable_ok=true 로 분리(실패 단정 0).
4. **prelude 미실행 차단 의미**: check_pending_delegations 가 pending 있으면 비어있지 않은 briefing 반환(= hook 이 주입 강제). pending 0 이면 빈 문자열(무영향).

## 금지
```text
hook 파일(~/.claude/**) 수정 · matrix 수정 · finish-task.sh·gate_shadow·dispatch.py(86줄 wrapper) 수정 ·
P0-B/callback/runner/activation/systemd/owner-pickup 전체 해동 · 자동 merge 권한 확대 ·
enforcement 없이 문서만 추가하고 wired/enforced 라 보고 · expected_files 3개 밖 수정.
```

## STOP 조건
```text
expected_files 밖 수정 필요 · hook/matrix 수정 필요(ANU 영역) · dispatch 성공 지점 불명확 ·
P0-B/activation 축 번짐 · 테스트 없이 완료 · self-contained 깨짐(외부 의존).
```

## 검증 (완료 전 필수)
```text
pytest tests/regression/test_delegation_watcher_2773.py -q  (4종 PASS)
+ utils/delegation_watcher.py py_compile PASS
+ record_delegation→check_pending_delegations 1-shot 실증(ledger 기록→감지)
```

## 보고
```text
변경 파일(expected_files 일치) · delegation_watcher 4함수 · dispatch ledger 호출 지점 · 테스트 4종 결과 ·
ledger 1-shot 실증 · self-contained 증거 · hook wiring/matrix 는 ANU 영역(미수정) 명시 · ENFORCEMENT_0(CANDIDATE) 상태.
```

## allowed_resources
```yaml
allowed_resources:
  paths:
    - "utils/delegation_watcher.py"
    - "dispatch/core.py"
    - "dispatch/__init__.py"
    - "tests/regression/test_delegation_watcher_2773.py"
  forbidden_paths:
    - "dispatch.py"
    - "scripts/finish-task.sh"
    - "memory/state/automation_capability_matrix.json"
    - ".claude/**"
    - ".env*"
  commands:
    - "git"
    - "pytest"
    - "python3"
    - "gh"
  merge_policy: "manual"
  ttl_hours: 12
```