# 고스트 태스크 근본 수정 (task-483.1 분석 기반)

## 배경
task-1.1, task-4.1이 반복적으로 running 상태로 부활하는 버그. 2팀 분석 완료 (memory/reports/task-483.1.md).

## 수정 항목 (총 6건, 우선순위순)

### 수정 1 [Critical]: _cleanup_task() 호출 시 timer_task_id 사용
- 파일: `/home/jay/workspace/dispatch.py`
- 위치: L416, L463, L469, L481, L497
- 현재: `_cleanup_task(task_id)` → task_id에 점(.)이 없으면 timer에서 못 찾음
- 수정: `_cleanup_task(timer_task_id)` 로 변경
- timer_task_id 계산(L406)을 dispatch() 함수 초반으로 이동하여 모든 cleanup 지점에서 접근 가능하게

### 수정 2 [Critical]: L476-477에 _cleanup_task() 추가
- 파일: `/home/jay/workspace/dispatch.py`, L474-477
- 현재: `if not bot_id or bot_id not in BOT_KEYS: return {"status": "error", ...}` — cleanup 없이 return
- 수정: return 직전에 `_cleanup_task(timer_task_id)` 추가

### 수정 3 [Important]: _save_timers() 원자적 쓰기
- 파일: `/home/jay/workspace/memory/task-timer.py`, L81-93
- 현재: `open("w")`로 즉시 truncate 후 lock → 레이스 컨디션
- 수정: tempfile.NamedTemporaryFile에 쓴 후 os.replace()로 원자적 교체
```python
def _save_timers(self) -> None:
    import tempfile, os
    try:
        self.timer_file.parent.mkdir(parents=True, exist_ok=True)
        with tempfile.NamedTemporaryFile(
            "w", dir=self.timer_file.parent, delete=False,
            suffix=".tmp", encoding="utf-8"
        ) as tmp:
            json.dump(self.timers, tmp, ensure_ascii=False, indent=2)
        os.replace(tmp.name, str(self.timer_file))
    except Exception as e:
        logger.error(f"타이머 파일 저장 실패: {self.timer_file} - {e}")
```

### 수정 4 [Important]: 락 메커니즘 통일
- dispatch.py와 task-timer.py 모두 동일한 락 파일 사용: `WORKSPACE/memory/.task-timers.lock`
- 두 파일의 task-timers.json 읽기/쓰기 상호 배제 보장

### 수정 5 [Recommended]: teams/*/CLAUDE.md에서 task-timer start 수동 호출 지시 제거
- `/home/jay/workspace/teams/dev1/CLAUDE.md` L17
- `/home/jay/workspace/teams/dev2/CLAUDE.md` L17
- `/home/jay/workspace/teams/dev3/CLAUDE.md` L19
- "작업 시작 시 반드시 task-timer 시작" → "dispatch.py가 자동 처리하므로 task-timer를 직접 호출하지 마세요"로 교체

### 수정 6 [Recommended]: generate_task_id() 하드코딩 기본값 방어
- 파일: `/home/jay/workspace/dispatch.py`, L173
- 현재: 파일 읽기 실패 시 `next_id = "task-1.1"` 하드코딩
- 수정: 파일 존재하는데 읽기 실패 시 RuntimeError 발생 (손상된 파일에 기본값 쓰기 금지)

## 테스트
- 기존 테스트 전체 PASS 확인
- task-timer.py 관련 테스트 추가:
  - 원자적 쓰기: 동시 저장 시 데이터 유실 없음
  - cleanup 호출: dispatch 실패 시 running 고스트 안 남음
- pyright 에러 0건

## 참고
- 상세 분석 보고서: `/home/jay/workspace/memory/reports/task-483.1.md`

## 주의
- dashboard/ 파일 절대 건드리지 마세요
- 기존 API, 워크플로우 동작 변경 없이 버그만 수정