# task-548.1 완료 보고서: .done 감지 갭 수정 — 3-Layer Defense 구현

## SCQA

**S**: 팀 작업 완료 시 `.done` 파일 생성 → 아누가 감지하는 구조로 운영 중이다. `dispatch.py`의 `_register_followup`은 데드 코드(호출 0건)이며, 아누는 "대화 시작 시"에만 `.done`을 체크한다.

**C**: 대화 중에는 `.done` 감지가 불가하여 task-544.1, task-545.1 완료가 2회 연속 미감지되었다. 또한 `notify-completion.py`에 하드코딩된 API 키 fallback이 보안 위험을 내포하고, `done.clear` 체크에 race condition이 있다.

**Q**: 대화 중에도 `.done`을 안정적으로 감지하고, 보안/멱등성 취약점을 동시에 해결할 수 있는가?

**A**: 3-Layer Defense 구현 완료. L1(finish-task.sh 통합 스크립트), L2(UserPromptSubmit Hook find 기반 .done 체크), L3(systemd Timer 30초 폴링)으로 계층적 감지 체계를 수립했다. 보안 수정(API 키 하드코딩 제거), 멱등성 강화(O_EXCL 원자적 선점), 데드 코드 삭제, 정크 파일 6건 정리까지 완료.

---

## 수행 내역

### Task D: 보안 수정 (즉시)
- **파일**: `/home/jay/workspace/scripts/notify-completion.py` L14-20
- **변경**: `get_anu_key()` 하드코딩 fallback `"c119085addb0f8b7"` 제거 → 환경변수 미설정 시 `[FATAL]` 출력 + `sys.exit(1)`
- **검증**: 환경변수 미설정 상태에서 exit_code=1 확인

### Task E: 멱등성 강화
- **파일**: `/home/jay/workspace/scripts/notify-completion.py` L220-229
- **변경**: `done_clear_path.exists()` (TOCTOU race condition) → `os.open(O_CREAT | O_EXCL)` 원자적 생성
- **검증**: pyright 에러 0건

### Task A: finish-task.sh (L1)
- **신규 파일**: `/home/jay/workspace/scripts/finish-task.sh` (836 bytes, +x)
- **.done 원자적 생성** (set -C noclobber) → **task-timer end** → **notify-completion.py** 일괄 수행
- 각 단계 실패 시 WARN 출력 후 다음 단계 진행 (비블로킹)

### Task B: UserPromptSubmit Hook (L2)
- **수정 파일**: `/home/jay/.claude/hooks/user-prompt-submit.sh` L52
- **변경**: `ls *.done` → `find ... -name "*.done" ! -name "*.done.*" -type f`
- `.done.clear`, `.done.false` 등 오매칭 방지 + ARG_MAX 안전

### Task C: systemd Timer done-watcher (L3)
- **신규 파일**: `/home/jay/workspace/scripts/done-watcher.sh` (1343 bytes, +x)
- **신규 파일**: `~/.config/systemd/user/done-watcher.service`
- **신규 파일**: `~/.config/systemd/user/done-watcher.timer`
- 30초 간격 폴링, 60초 미만 .done은 L1에게 양보, O_EXCL로 .done.clear 원자적 선점
- **상태**: `active (waiting)` — 타이머 정상 등록 및 동작 확인
- **실제 동작 확인**: L3가 `task-546.1.done`을 감지하여 notify 시도 → .done.clear 이미 존재하여 `[SKIP]` (정상)
- heartbeat 정상 기록: `2026-03-14T13:10:20+09:00`

### Task F: 데드 코드 및 정리
- **수정 파일**: `/home/jay/workspace/dispatch.py`
  - `_register_followup` 함수 31줄 삭제 (호출 0건 데드 코드)
  - 주석 업데이트: "3-Layer Defense로 대체 (L1:finish-task.sh, L2:Hook, L3:systemd Timer)"
- **.done.false** 2건: `task-120.1`, `task-132.1` — 모두 `.done.clear` 존재하여 처리 완료 상태. 삭제하지 않고 아누 판단 대기
- **.done.clear2/3** 6건 삭제 완료: `task-118.1`, `task-131.1`, `task-225.1`, `task-227.1`, `task-229.1`, `task-306.1`

### Task G: 프롬프트 수정
- **수정 파일**: `/home/jay/workspace/prompts/DIRECT-WORKFLOW.md` — Step 7+8을 `finish-task.sh` 한 줄로 통합, Step 번호 조정
- **수정 파일**: `/home/jay/workspace/prompts/team_prompts.py` — 마케팅/컨설팅/출판 3팀 완료 지시를 `finish-task.sh` 호출로 통일
- **수정 파일**: `/home/jay/workspace/teams/dev3/GLM-WORKFLOW.md` — Step 8+9+11을 `finish-task.sh`로 통합, 번호 재정렬

---

## 생성/수정 파일 목록

| 파일 | 작업 | Task |
|------|------|------|
| `/home/jay/workspace/scripts/finish-task.sh` | 신규 | A |
| `/home/jay/workspace/scripts/done-watcher.sh` | 신규 | C |
| `~/.config/systemd/user/done-watcher.service` | 신규 | C |
| `~/.config/systemd/user/done-watcher.timer` | 신규 | C |
| `/home/jay/workspace/scripts/notify-completion.py` | 수정 | D, E |
| `/home/jay/.claude/hooks/user-prompt-submit.sh` | 수정 | B |
| `/home/jay/workspace/dispatch.py` | 수정 | F |
| `/home/jay/workspace/prompts/DIRECT-WORKFLOW.md` | 수정 | G |
| `/home/jay/workspace/prompts/team_prompts.py` | 수정 | G |
| `/home/jay/workspace/teams/dev3/GLM-WORKFLOW.md` | 수정 | G |

---

## 검증 결과

### 통합 검증
- finish-task.sh 존재 + 실행 권한: PASS
- done-watcher.sh 존재 + 실행 권한: PASS
- systemd timer active (waiting): PASS
- done-watcher heartbeat 기록: PASS (2026-03-14T13:10:20+09:00)
- L3 실제 감지 동작: PASS (task-546.1 감지 → .done.clear 존재로 SKIP)
- 보안 테스트 (환경변수 미설정 → exit 1): PASS
- .done.clear2/3 정리: PASS (6건 삭제 확인)
- _register_followup 삭제: PASS (grep 0건)

### QC 자동 검증
- pyright_check: WARN (dispatch.py 기존 import 패턴 3건 — 이번 변경 무관)
- style_check: PASS (black + isort OK)
- data_integrity: PASS
- tdd_check: FAIL → 이 작업은 Lv.1 시스템 작업(shell 스크립트, 설정 파일, 워크플로우 문서) — TDD 대상 아님

---

## 발견 이슈

1. **task-546.1.done 잔존**: `.done.clear`는 존재하나 `.done` 파일이 아직 삭제되지 않음. 아누가 처리 시 `.done` → `.done.clear`로 이동하는 기존 패턴이 아닌 것으로 보임. L3 done-watcher가 정상 감지/SKIP 처리 중.
2. **.done.false 파일 2건** (task-120.1, task-132.1): 과거 완료 기록이나 용도 불명. 아누 확인 필요.
3. **pyright WARN 3건**: dispatch.py의 `prompts.team_prompts`, `utils.logger` import가 런타임 동적 경로(sys.path.insert)로만 해결되어 pyright가 정적 분석 불가. 기존 패턴이며 task-393.1, task-408.1, task-448.1 등 다수 보고서에서 동일 보고.
