# task-616.1 완료 보고서: .done 프로토콜 근본 재설계 (Pull 모델 전환)

**S**: .done 프로토콜이 3번 수정(607.1, 609.1, 613.1) 후에도 실패하여, 에이전트 미팅(2026-03-16) 전원 합의로 Push→Pull 모델 전환이 결정되었다. 근본 원인은 cokacdir --cron으로 새 아누 세션을 깨우면 현재 대화와 단절되어 보고가 제이회장님에게 전달되지 않는 것이다.

**C**: 기존 Push 모델의 .done.notified → .done.clear 3단계 상태 전이가 과도하게 복잡하여, 레이스 컨디션, 중복 알림, 아카이브 타이밍 문제가 반복 발생했다. 코드 5개 파일에 걸쳐 .done.notified/.done.clear 관련 로직이 산재해 있었다.

**Q**: .done(미처리) → .done.acked(처리 완료) 2단계 Pull 모델로 전환하여 프로토콜 복잡도를 제거하고, 아누가 매 세션 시작 시 whisper로 직접 .done을 감지하는 방식이 정상 작동하는가?

**A**: 6개 파일 수정 완료. notify-completion.py에서 wake_anu_session/create_done_notified/--retry/build_prompt를 제거하고 텔레그램 텍스트 알림만 전송하도록 변경. done-watcher.sh를 stale .done 에스컬레이션 전용으로 전면 재작성. whisper-compile.py의 dead code 제거 및 독스트링 업데이트. user-prompt-submit.sh의 .done.notified/.done.clear 참조를 .done.acked 프로토콜로 교체. pytest 90건 전체 통과(0 실패), pyright 에러 0건.

## 변경 파일 목록

**수정 (6건):**
- `scripts/notify-completion.py` — wake_anu_session 함수 제거, create_done_notified 함수 제거, build_prompt 함수 제거, --retry 플래그 제거, 체인 마지막/독립 작업 경로를 send_telegram_notification으로 전환
- `scripts/done-watcher.sh` — 전면 재작성: stale .done 감지(30분+)→에스컬레이션 + .done.acked 24시간 정리
- `scripts/whisper-compile.py` — scan_done_files() dead code(.done.clear 체크) 제거, 독스트링 업데이트
- `~/.claude/hooks/user-prompt-submit.sh` — .done.notified/.done.clear 참조 제거, .done→.done.acked 안내로 교체
- `scripts/completion-handler-instructions.md` — 상단에 DEPRECATED 주석 추가
- `scripts/tests/test_done_protocol.py` — 15개 테스트 제거(구 프로토콜), 7개 신규 추가(Pull 모델)

**수정 (테스트):**
- `scripts/tests/test_notify_completion.py` — TestBuildPrompt 클래스 제거, TestMainWithMock 수정
- `scripts/tests/test_whisper_compile.py` — .done.acked/.done.escalated/.done.notified 제외 테스트 4건 추가

**이동 (1건):**
- `memory/events/task-582.1.done.clear2` → `memory/events/archive/`

## 테스트 결과

```
90 passed in 0.21s
- test_done_protocol.py: 13 passed
- test_notify_completion.py: 6 passed
- test_whisper_compile.py: 71 passed
pyright: 0 errors, 0 warnings, 0 informations
bash -n: done-watcher.sh OK, user-prompt-submit.sh OK
```

## 테스트 요구사항 충족 검증

**notify-completion.py:**
- ✅ 체인 중간 Phase: dispatch.py 직접 호출 동작 확인 (test_chain_middle_dispatches_and_sends_telegram)
- ✅ 체인 마지막 / 독립 작업: 텔레그램 텍스트만 전송, wake_anu_session 미호출 확인 (test_independent_task_sends_telegram_not_wake)
- ✅ .done 파일이 수정/삭제/rename되지 않는지 확인 (test_done_file_not_modified_after_notification, test_done_file_survives_notification)
- ✅ .done.notified 파일이 생성되지 않는지 확인 (test_no_done_notified_created)

**done-watcher.sh:**
- ✅ .done 파일 30분 미만: 아무 동작 없음 (test_stale_done_under_30min_no_action)
- ✅ .done 파일 30분 이상: 에스컬레이션 알림 1회 전송 + .done.escalated 마커 생성 (test_stale_done_escalation)
- ✅ .done.escalated 존재 시: 중복 알림 없음 (test_escalated_marker_prevents_duplicate)
- ✅ .done.acked 24시간 이상: archive 이동 (test_acked_cleanup_after_24h)

**whisper-compile.py:**
- ✅ .done 파일 존재 시 브리핑에 포함 (test_scan_done_files_basic, test_extract_scqa_format_in_briefing)
- ✅ .done.acked, .done.escalated 파일 제외 (test_scan_done_files_excludes_done_acked, _escalated)
- ✅ .done 파일 0건일 때 "없음" 표시 (test_extract_scqa_no_done_files)

## 발견 이슈 및 해결

### 자체 해결 (3건)
1. **wake_anu_session 함수 내 가짜 import** — build_prompt 제거 후 함수가 비정상 참조를 갖게 됨 → 함수 자체를 완전 제거하여 dead code 해소
   - 상세: `scripts/notify-completion.py` — wake_anu_session 함수 전체 삭제 (호출부 없음 확인)
2. **scan_done_files() dead code** — `.done.clear` 체크가 unreachable code (`.endswith(".done")` 필터에서 이미 걸러짐)
   - 상세: `scripts/whisper-compile.py:96-97` 2줄 삭제, 독스트링 갱신
3. **user-prompt-submit.sh 구 프로토콜 참조** — .done.notified/.done.clear 참조가 새 프로토콜과 불일치
   - 상세: `~/.claude/hooks/user-prompt-submit.sh:63-68` 분기 제거, `.done → .done.acked` 안내로 교체

## 새 상태 전이 (확인)

```
팀 완료 → .done 파일 생성 (기존과 동일)
  ├─ 체인 중간: dispatch.py 직접 호출 (기존 유지, 변경 없음)
  └─ 체인 마지막 / 독립 작업: 텔레그램 텍스트 알림만 전송 (아누 세션 깨우기 X)

아누 세션 시작 → whisper-compile.py가 *.done 스캔 → "task-X 완료" 브리핑
아누가 보고서 읽고 보고 → .done → .done.acked rename

.done (미처리) / .done.acked (처리 완료) — 2단계만 존재
```

## 셀프 QC

- [x] 1. 영향 파일 확인: finish-task.sh (--retry 없이 호출, 영향 없음), cron (done-watcher.sh 호환)
- [x] 2. 엣지 케이스: .done 0건(빈 for루프), chain 에러(독립 작업으로 fallback), dispatch 실패(에러 로그+에스컬레이션)
- [x] 3. 작업 지시 일치 확인: 6개 수정사항 모두 반영
- [x] 4. 에러 처리/보안: 외부 명령 || true, WARNING 로그, .env.keys 분리
- [x] 5. 테스트 커버리지: 90/90 전체 경로 커버
- [x] 6. 이슈 자체 해결 완료: 3건 모두 해결

## QC 자동 검증

```json
{
  "task_id": "task-616.1",
  "verified_at": "2026-03-16T15:08:51",
  "overall": "6 PASS, 1 FAIL(.done 미생성 - 마무리 전), 3 SKIP",
  "checks": {
    "api_health": "SKIP (서버 작업 아님)",
    "file_check": "FAIL (.done 미존재 — 마무리 전이므로 정상, 나머지 7/8 OK)",
    "data_integrity": "PASS (task-timers running, 미완료 상태 일치)",
    "test_runner": "PASS (837 passed, 47 warnings in 12.46s)",
    "tdd_check": "PASS (테스트 3개 + 구현 3개 모두 존재)",
    "pyright_check": "PASS (0 errors, 0 warnings)",
    "style_check": "PASS (black OK, isort OK)",
    "schema_contract": "SKIP (workers 없음)",
    "scope_check": "SKIP",
    "critical_gap": "PASS"
  }
}
```

## 마아트 독립 검증

**최종 판정: PASS** (10개 검증 포인트 모두 통과, WARN 1건)

- ✅ create_done_notified() 완전 제거 (grep 확인)
- ✅ --retry 플래그 완전 제거 (argparse 확인)
- ✅ build_prompt() 완전 제거 (grep 확인)
- ✅ send_telegram_notification() 정상 호출 (line 205, 221)
- ✅ 메시지 형식 `✅ {task_id} 완료. 보고서: memory/reports/{task_id}.md` 일치 (line 220)
- ✅ .done 파일 미조작 (grep + 테스트 2건 확인)
- ✅ done-watcher.sh 명세와 difflib 완전 일치
- ✅ scan_done_files() .done.acked/.done.escalated 자동 제외 (line 94 + 테스트 3건)
- ✅ user-prompt-submit.sh 구 참조(.done.notified/.done.clear) 완전 제거
- ✅ completion-handler-instructions.md DEPRECATED 주석 정확히 일치
- ⚠️ WARN: end_task_timer() 함수가 main()에서 미호출 (기존 dead code, 본 작업 범위 외)
