# 계획서: task-148.1 — cron 완료 알림 중복 보고 제거

## 작업 요약
팀장(라/Ra)이 작업 완료 후 Anu에게 보내는 cron 완료 알림이 중복으로 발송되는 문제를 수정.

## 근본 원인 분석

### 현재 구조
`prompts/team_prompts.py`의 `_build_direct_prompt`(dev1/dev2팀)와 `_build_glm_prompt`(dev3팀) 양쪽에서,
팀장이 작업 완료 후 아누에게 cron을 보내는 단계에 아래 패턴이 존재:

```
먼저 {task_id}.done.clear가 이미 존재하는지 확인하라.
존재하면 이미 처리된 건이니 스킵하라.
없으면 보고서 읽고 제이회장님께 핵심 요약 보고하라.
보고 완료 후 {task_id}.done 파일을 {task_id}.done.clear로 rename하라.
```

### 문제점 (Race Condition)
1. 팀장 세션이 재시작/재시도되거나 기타 이유로 완료 cron이 **2번 등록**되는 경우:
   - 두 cron이 거의 동시에 실행 → 둘 다 `.done.clear` 없음 확인 → 둘 다 보고 → **중복**
2. Anu가 `.done` 파일을 `.done.clear`로 rename 전 오케스트레이터가 `.done` → `.processed`로 이미 rename한 경우:
   - Anu가 rename 실패 → `.done.clear` 미생성 → 다음 cron이 또 보고 → **중복**
3. Check-then-act 패턴 자체가 **비원자적**: 확인(check)과 생성(act) 사이에 타 프로세스 개입 가능

### 해결 방안 (원자적 중복 방지)
Python의 `open(path, 'x')` (exclusive create) 사용:
- 파일이 없을 때만 성공 (원자적 OS 호출)
- 파일이 있으면 `FileExistsError` 즉시 반환
- Check-and-create를 단일 원자적 연산으로 수행

## 서브태스크 분해 (순차, 단일 GLM)

### 서브태스크 1: 코드 분석 및 수정 (GLM)
- 파일: `/home/jay/workspace/prompts/team_prompts.py`
- 함수: `_build_direct_prompt()` (dev1/dev2팀 step 8)
- 함수: `_build_glm_prompt()` (dev3팀 step 10)
- 변경: 비원자적 check-then-act → 원자적 `open(path,'x')` 방식으로 교체

**변경 전** (both functions):
```
먼저 {done_clear}가 이미 존재하는지 확인하라. 존재하면 이미 처리된 건이니 스킵하라.
없으면 보고서 읽고 제이회장님께 핵심 요약 보고하라.
보고 완료 후 {done_file} 파일을 {done_clear}로 rename하라.
```

**변경 후** (both functions):
```
먼저 아래 파이썬 명령으로 중복 처리를 원자적으로 방지하라:
python3 -c "import pathlib,sys; p=pathlib.Path('{done_clear}'); p.parent.mkdir(parents=True,exist_ok=True); open(str(p),'x').close(); print('proceed')"
명령이 'proceed' 출력 → 보고서 읽고 제이회장님께 핵심 요약 보고.
명령이 FileExistsError로 실패 → 이미 처리됨, 스킵.
```

### 서브태스크 2: 테스트 작성 (GLM)
- 파일: `/home/jay/workspace/teams/dev3/test_task_148_1.py`
- 테스트 항목:
  - `_build_direct_prompt`에서 새 원자적 패턴 포함 확인
  - `_build_glm_prompt`에서 새 원자적 패턴 포함 확인
  - 기존 `.done.clear` 존재 확인 텍스트가 제거되었는지 확인
  - `open(path,'x')` 패턴이 포함되었는지 확인
  - pytest로 검증

### 서브태스크 3: GLM 체크리스트 실행 및 .done 파일 생성 (GLM)
- `python3 memory/glm-checklist.py` 실행
- all_passed: true 확인 후 .done 생성

## 예상 위험 및 대안

| 위험 | 대안 |
|------|------|
| Python `open(path,'x')` 이스케이핑 복잡 (f-string 중첩) | 별도 helper script 생성 |
| 기존 테스트가 변경된 프롬프트 내용에 의존하는 경우 | 기존 테스트 내용 확인 후 수정 |
| rename 제거 후 .done 파일이 영구 잔류 | 선택적 cleanup 추가 또는 허용 |

## 실행 순서
1. team_prompts.py 수정 (both functions)
2. 테스트 작성 및 pytest 실행
3. GLM 체크리스트 실행
4. .done 파일 생성

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

1. **비정상 입력/상태**: `.done.clear` 파일의 부모 디렉토리가 없는 경우
   - 대응: `p.parent.mkdir(parents=True, exist_ok=True)` 로 자동 생성

2. **동시성/경쟁 조건**: 두 cron이 동시에 `open(path,'x')` 시도
   - 대응: OS 레벨 원자적 보장 (O_EXCL flag). 두 번째는 FileExistsError로 실패 → 중복 방지 ✓

3. **비정상 종료/타임아웃**: Anu의 세션이 `open(path,'x')` 성공 후 보고 전 종료
   - 대응: `.done.clear` 파일은 이미 생성됨 → 다음 cron도 스킵 → 보고 미발생
   - 허용 수준: 보고 미발생은 중복보다 낫다 (운영자가 수동으로 `.done.clear` 삭제 후 재시도 가능)

4. **스테일 데이터**: 구 task의 `.done.clear` 파일이 남아있는 경우
   - 대응: task_id가 unique하므로 충돌 없음. 오래된 파일은 정기 cleanup으로 제거 가능.

5. **통합 시 충돌**: 기존 테스트가 `.done.clear` 존재 확인 텍스트 패턴을 assert하는 경우
   - 대응: 테스트 파일 확인 후 패턴 업데이트. `test_team_prompts.py` 검토 필요.
