# plan-task-123.1: '하기로 한 일을 잊어버리는 문제' 3계층 방어 구조 구현

**작성자**: 헤르메스 (개발1팀장)
**작성일**: 2026-03-02
**선행 분석**: task-119.1 보고서 (memory/reports/task-119.1.md)

---

## 1. 작업 목표

task-119.1 분석 보고서에서 권고한 3계층 방어 구조를 코드로 구현한다.
- 계층 1 (예방): pending-actions.json + pending-actions.py 신설
- 계층 2 (전달): team_prompts.py의 완료 통보 프롬프트에 미이행 약속 자동 삽입
- 계층 3 (확인): user-prompt-submit.sh 아누 hook에 미이행 약속 경고 주입

## 2. 서브태스크 분해 및 팀원 배정

### ST-1: pending-actions.py 모듈 작성 (불칸 - 백엔드)
- pending-actions.json 스키마 설계 (id, description, trigger, status, created_at, resolved_at)
- CRUD API: add_action, resolve_action, get_pending, list_all
- fcntl 기반 파일 락 (기존 event-queue.py 패턴 재사용)
- atomic write (tmpfile → os.replace)
- CLI 인터페이스 (add/resolve/list/pending 서브커맨드)

### ST-2: dispatch.py 수정 (불칸 - 백엔드)
- dispatch() 함수에 `followup_action` 선택 파라미터 추가
- followup_action이 지정되면 pending-actions.py의 add_action 호출
- CLI에 --followup 옵션 추가
- dispatch_result에 followup_action_id 포함

### ST-3: team_prompts.py 완료 통보 프롬프트 강화 (이리스 - 프론트엔드/프롬프트)
- _build_direct_prompt()의 워크플로우 8번(아누 완료 통보) 프롬프트에 pending-actions 조회 로직 삽입
- _build_glm_prompt()의 워크플로우 10번에도 동일 적용
- 통보 프롬프트에 "미이행 약속 N건 있음 → pending-actions.py pending으로 확인 후 처리하라" 문구 자동 삽입

### ST-4: user-prompt-submit.sh 아누 hook 강화 (이리스)
- anu) 케이스에 pending-actions.py pending 호출
- 미이행 약속이 있으면 경고 메시지 주입
- 기존 .done 파일 체크, 이벤트 큐 체크와 동일한 패턴 사용

### ST-5: 테스트 코드 작성 (아르고스 - 테스터)
- pending-actions.py 단위 테스트 (CRUD, 파일 락, 엣지 케이스)
- dispatch.py followup 통합 테스트
- 프롬프트에 pending-actions 문구 삽입 확인 테스트

## 3. 실행 순서

1단계 (병렬): ST-1 (불칸) + ST-3/ST-4 설계 (이리스 - pending-actions 인터페이스 사전 정의 후)
→ ST-1이 인터페이스를 정의하므로, 이리스는 이 인터페이스에 맞춰 프롬프트 수정
2단계 (순차): ST-2 (불칸) - ST-1 완료 후 dispatch.py에 연동
3단계 (병렬): ST-3 + ST-4 (이리스) - ST-1 인터페이스 확정 후
4단계: ST-5 (아르고스) - 전체 통합 테스트

**실제 실행**: ST-1 + ST-2를 불칸에게, ST-3 + ST-4를 이리스에게 병렬 위임. 아르고스는 통합 후 테스트.

## 4. 예상 위험 및 대안

- **위험**: pending-actions.json과 event-queue.json 스키마 충돌 → 별도 파일 + 별도 락으로 격리
- **대안 검토**: event-queue.json에 followup 필드 추가 vs 별도 파일 → 별도 파일 채택 (관심사 분리, 단일 책임)
- **기각 사유**: event-queue.json은 FIFO 이벤트 큐이고, pending-actions는 약속 추적 레지스트리. 목적이 다르므로 합치면 복잡도만 증가.

## 5. 실패 시나리오 체크리스트

### 5-1. 비정상 입력/상태
- pending-actions.json이 깨진 경우: .bak 백업 복구 로직 구현 (event-queue.py 패턴 재사용)
- followup_action이 빈 문자열인 경우: 빈 값은 무시하고 기록하지 않음
- 의존 파일(pending-actions.json) 삭제 시: 자동 재생성 (빈 구조)

### 5-2. 동시성/경쟁 조건
- 여러 dispatch가 동시에 pending-actions.json에 쓰는 경우: fcntl.LOCK_EX 배타 잠금
- 읽기와 쓰기 동시 발생: 읽기 시 LOCK_SH, 쓰기 시 LOCK_EX
- hook에서 읽기 + dispatch에서 쓰기 동시: 읽기는 잠금 없이 진행해도 atomic write로 안전 (os.replace)

### 5-3. 비정상 종료/타임아웃
- add_action 중 프로세스 죽음: atomic write 사용이므로 원본 파일은 안전
- resolve 중 프로세스 죽음: 동일. 임시 파일만 남으며 다음 실행 시 무시됨
- 락 파일 잔존: fcntl은 프로세스 종료 시 자동 해제

### 5-4. 스테일 데이터
- 오래된 미이행 약속이 계속 경고: created_at 필드로 경과일 표시하여 사용자가 판단
- TTL 자동 만료는 구현하지 않음 (약속은 명시적으로 해결해야 함)

### 5-5. 통합 시 충돌
- dispatch.py import 추가: pending-actions.py를 memory/ 디렉토리에 배치, sys.path에 이미 포함
- user-prompt-submit.sh: python3 호출 추가. 실패 시 무시(|| true)하여 기존 기능 영향 없음
- team_prompts.py: 프롬프트 문자열에 조건부 삽입만 추가. 기존 구조 유지.
