# Agent 미팅: .done 자동 감지 메커니즘 설계

**날짜**: 2026-03-24
**태스크**: task-897.1
**소집 이유**: 팀 작업 완료 시 생성되는 .done 파일을 토큰 소모 없이 빠르게 자동 감지하여 아누에게 통보하는 메커니즘 설계
**참여 페르소나**: 헤르메스(1팀장, 미팅 주관), 로키(보안팀장, DA), 펜리르(보안팀원, DA 보조)
**미팅 모드**: hybrid
**토론 깊이**: thorough
**총 사이클 수**: 3

---

## 현재 시스템 분석 (헤르메스)

### 기존 인프라
1. **finish-task.sh** (L1 Primary Push): .done 생성 → task-timer end → notify-completion.py
2. **notify-completion.py**: `cokacdir --cron --at 1m`으로 아누에게 알림 → **새 Claude 세션 생성 = 토큰 소모** (핵심 문제)
3. **done-watcher.sh** (systemd 30초 타이머): stale .done 30분 후 에스컬레이션만 수행
4. **done-watcher.py**: .done 감지 → bot-activity.json idle 전환만 (알림 기능 없음)
5. **activity-watcher.py**: bot-activity.json 3초 폴링 → 완료 감지 → Telegram 알림 기능 있으나 **현재 미실행**

### 핵심 발견
- `ANU_BOT_TOKEN` 환경변수가 `.env.keys`에 존재 → 직접 Telegram API 호출 가능
- `inotifywait` 미설치
- `done-watcher.timer` (systemd) 활성 상태
- `activity-watcher.py` 미실행 → 실시간 감지 공백의 직접 원인

### 이전 미팅 결정 사항 (존중 대상)
- 2026-03-10: done_watcher 신규 데몬 폐기 → 기존 인프라 강화 결정
- 2026-03-14: 3-Layer Defense 채택
- 2026-03-16: Push(cokacdir --cron 새 세션) 폐기, Pull 단일화, .done/.done.acked 2단계

---

## Cycle 1 — 방안 제안 + 장단점 분석

### 검토 방안 5가지

| 방안 | 설명 | 감지 속도 | 토큰 비용 | 구현 난이도 |
|------|------|-----------|-----------|-------------|
| A. inotifywait 데몬 | 파일시스템 이벤트 감시 | <1초 | 0 | 중 (미설치) |
| B. Systemd Timer 폴링 강화 | done-watcher.sh 수정 | 30초 | 0 | 하 |
| C. 직접 Telegram API | notify-completion.py 수정 | 즉시 | 0 | 하 |
| D. Systemd Path Unit | PathChanged 트리거 | <1초 | 0 | 중 |
| E. activity-watcher 복구 | 기존 3초 폴링 복구 | 3초 | 0 | 하 |

### 헤르메스 초안: C + B 하이브리드
- Primary(C): notify-completion.py에서 cokacdir --cron을 직접 Telegram API(requests.post)로 교체
- Fallback(B): done-watcher.sh에 미알림 .done 발견 시 직접 Telegram 알림 추가

---

## Cycle 2 — 로키/펜리르 반론 + 리스크 시나리오

### 로키 (DA) 반론

**방안 A (inotifywait): 기각**
- 보안 등급: High
- inotifywait 미설치 → 패키지 의존성 추가
- 2026-03-10 "신규 데몬 폐기" 결정 위반
- 데몬 크래시 시 재시도 메커니즘 없음, 이벤트 소비 후 처리 실패 시 영구 누락

**방안 B (폴링 강화): 조건부 수용**
- 보안 등급: Medium
- done-watcher.sh의 `touch $escalated_file`이 비원자적 → O_EXCL 복구 필수
- `EnvironmentFile`로 35개 키 전체 로드 → 최소 권한 위반
- 조건: O_EXCL 복구, EnvironmentFile 범위 제한

**방안 C (직접 API): 조건부 수용**
- 보안 등급: Critical (finish-task.sh에서 직접 호출 시) / Medium (notify-completion.py 내에서 호출 시)
- curl 히스토리에 토큰 노출, ps aux로 프로세스 목록 노출
- finish-task.sh가 아닌 notify-completion.py 내에서만 호출 (기존 구조 유지)
- 조건: Python requests 사용, 타임아웃+재시도, notify-completion.py 내부에서만

**방안 D (Path Unit): 기각**
- 보안 등급: Medium
- events 디렉토리에 bot-activity.json 등 노이즈 파일 다수 → 불필요한 트리거 폭주
- 재부팅 전 생성된 .done은 "변경" 이벤트 없으므로 감지 불가
- 결국 Timer 백업 필요 → B와 중복

**방안 E (activity-watcher): 버그 수정 후 수용**
- 보안 등급: Medium (복구 대상)
- ★ **핵심 버그 발견**: `find_done_file`이 팀과 무관하게 첫 번째 .done 반환 → 잘못된 작업 ID로 알림
- ★ **BOT_TEAM_MAP에 dev4-dev8 누락** → dev8 11시간 유휴의 직접 원인
- 환경변수 평문 로드 (35개 전체), PID 파일 TOCTOU, systemd 미등록 (재시작 불가)
- 조건: find_done_file 버그 수정, BOT_TEAM_MAP 확장, systemd user service 등록

**로키 추천: E(버그수정+systemd) + B(O_EXCL 복구) + C(notify-completion.py 내 직접 API)**

### 펜리르 (DA 보조) 침투 시나리오

**8대 위협 시나리오 분석:**

1. **동시 완료 경쟁** (발생 높음, 영향 High): 8팀 동시 완료 → 순차 API 호출 → rate limit 초과 일부 실패 → 배치 알림으로 방어

2. **마커 파일 폭발** (발생 높음, 영향 Medium): 100태스크 × 4마커 = 400파일 → 24시간 아카이브 정리로 관리

3. **세션 비정상 종료** (발생 중간, 영향 High): finish-task.sh 미호출 → .done 미생성 → fallback(B)이 필수인 이유

4. **서버 재부팅** (발생 중간, 영향 Critical): activity-watcher 미실행 상태 재현 → systemd enable 필수

5. **Telegram API 장애** (발생 중간, 영향 High): rate limit, 네트워크 단절 → 재시도+로컬 큐+지수 백오프

6. **가짜 .done 생성** (발생 중간, 영향 High): 심볼릭 링크 공격, 테스트 잔류 → symlink 거부, 내용 검증

7. **확장성 16팀** (발생 높음, 영향 High): 순차 처리 32초 > 타이머 30초 → 중복 실행 → flock으로 방어

8. **TOCTOU 경합** (발생 중간, 영향 Critical): done-watcher.sh + activity-watcher.py 동시 감지 → mv 기반 원자적 소유권 필수

**펜리르 핵심 원칙**: "`mv`는 atomic이다. 모든 상태 전환은 mv로, 모든 감지 루프는 mv로 소유권을 먼저 획득한 후 처리하라."

**펜리르 추천: D(Path Unit) + C(직접API) + 하드닝**

---

## Cycle 3 — 반론 반영 수정안 + 합의

### 로키 vs 펜리르 쟁점

| 쟁점 | 로키 | 펜리르 | 헤르메스 판정 |
|------|------|--------|--------------|
| 방안 D (Path Unit) | 기각 (노이즈, 기존 결정 위반) | 채택 (이벤트 기반 우월) | **로키 수용** — events 디렉토리 노이즈 문제 실재 |
| TOCTOU 방어 | 언급은 했으나 설계 미반영 | mv 기반 원자적 소유권 강력 주장 | **펜리르 수용** — mv 패턴 필수 반영 |
| 배치 알림 | 미언급 | 16팀 동시 완료 대비 필수 | **펜리르 수용** — 확장성 위해 반영 |
| activity-watcher 위상 | 주요 감지 경로로 강화 | 보조 역할 (Path Unit 하위) | **로키 수용** — 기존 인프라 강화가 원칙 |

### 헤르메스 최종 설계안

**1. Primary Path (즉시, 토큰 0)**
- notify-completion.py: `cokacdir --cron --at 1m` → `requests.post()` 직접 Telegram API
- finish-task.sh는 수정 없음 (기존 워크플로우 유지)
- 타임아웃 10초, 재시도 3회 (지수 백오프), 실패 시 로컬 큐 파일

**2. Fallback Path (최대 30초, 토큰 0)**
- done-watcher.sh 강화: 미알림 .done 발견 시 직접 Telegram 알림 추가
- `.done.notified` 마커로 중복 방지 (O_EXCL 원자적 생성)
- `flock`으로 동시 인스턴스 실행 방지
- 배치 알림: 다건 동시 발견 시 단일 메시지로 묶기

**3. Bug Fixes (즉시 수행)**
- activity-watcher.py `find_done_file`: 팀 기반 매칭으로 수정
- activity-watcher.py `BOT_TEAM_MAP`: dev4-dev8 추가
- activity-watcher.py: systemd user service 등록 (Restart=always)
- done-watcher.sh: `touch` → O_EXCL 원자적 생성 복구

**4. TOCTOU 방어 (펜리르 원칙 반영)**
- `.done` → `.done.processing` mv로 원자적 소유권 획득
- 성공: `.done.processing` → `.done.notified`
- 실패: `.done.processing` → `.done` 원상 복구 (재시도 허용)

**5. 확장성 (16팀 대비)**
- 배치 알림: 다건 동시 감지 시 단일 Telegram 메시지
- Telegram rate limit 대응: 지수 백오프 + 429 헤더 존중

**6. 채택하지 않은 방안 (사유)**
- A (inotifywait): 미설치, 신규 데몬 = 기존 결정 위반
- D (Systemd Path Unit): events 디렉토리 노이즈 과다, 기존 타이머와 중복

### 최종 투표

- 헤르메스: ✅ 찬성
- 로키: ✅ 찬성 (보안 조건 전제: notify-completion.py 내에서만 직접 API, EnvironmentFile 범위 제한)
- 펜리르: ✅ 찬성 (TOCTOU mv 패턴 + 배치 알림 반영 전제)

**만장일치 합의 달성 (3/3)**

---

## 수정 대상 파일

| # | 파일 | 변경 내용 | 우선순위 |
|---|------|-----------|----------|
| 1 | scripts/notify-completion.py | cokacdir --cron → requests.post 직접 API | P0 |
| 2 | scripts/activity-watcher.py | find_done_file 버그 수정 + BOT_TEAM_MAP 확장 | P0 |
| 3 | scripts/done-watcher.sh | 미알림 .done 직접 알림 + O_EXCL + flock | P1 |
| 4 | ~/.config/systemd/user/activity-watcher.service | 신규 생성 (Restart=always) | P1 |
| 5 | .env.done-watcher (신규) | 최소 키만 포함 (COKACDIR_KEY_ANU, COKACDIR_CHAT_ID) | P2 |

## 미해결 항목

1. `.env.done-watcher` 분리 파일 생성 시점 → 보안팀 후속 작업으로
2. activity-watcher.py 전면 리팩터링 (환경변수 최소 로드, PID 파일 O_EXCL) → 후속 태스크
3. Telegram Bot Token 로테이션 정책 → 장기 과제

## 다음 단계

1. 이 합의를 기반으로 설계 스펙 문서 작성 → `memory/specs/done-polling-spec.md`
2. 구현 태스크를 아누에게 보고 → dispatch 대기
3. 구현 후 펜리르 8대 시나리오 기반 통합 테스트
