# task-191.1 보고서: task-timers.json stale 상태 근본 원인 분석 + 재발 방지 구현

## 작업 내용

### 근본 원인 분석

task-timers.json에 22건의 running/reserved 상태 작업이 장기 방치된 원인 3가지:

1. **reserved → 시작 안 됨**: `dispatch.py`의 `generate_task_id()`가 reserved placeholder를 즉시 기록하지만, 이후 `cokacdir --cron` 명령이 실패(봇 수신 실패 등)해도 reserved 엔트리를 정리하지 않음
2. **running → 완료 안 됨**: 팀장이 `task-timer.py start` 호출 후 에러/타임아웃/중단으로 `end`를 호출하지 못함 (가장 빈번)
3. **타임아웃 메커니즘 부재**: 어느 계층(task-timer, dispatch, dashboard)에서도 stale 상태를 자동 감지/정리하는 로직이 없었음

### 재발 방지 구현

**A. task-timer.py cleanup 서브커맨드** (방안 B)
- `TaskTimer.cleanup_stale()` 메서드: running 2시간 초과 / reserved 30분 초과 → `stale` 상태 전환
- CLI: `python3 memory/task-timer.py cleanup [--running-hours N] [--reserved-minutes N] [--dry-run]`
- cron으로 주기적 실행 가능

**B. dispatch.py orphan reserved 방지** (방안 C)
- `_cleanup_reserved(task_id)` 함수: cokacdir --cron 실패 시 reserved 엔트리 즉시 삭제
- 파일 락(fcntl)으로 안전한 동시 접근 보장

**C. dashboard server.py stale 표시 보강** (방안 D)
- `get_team_stats()`: stale_tasks 카운트 추가, running/reserved 중 threshold 초과 시 stale로 분류
- `get_tasks_info()`: is_stale 플래그 추가, 대시보드에서 stale 작업을 시각적으로 구분 가능

## 생성/수정 파일 목록

- `/home/jay/workspace/memory/task-timer.py` — cleanup_stale() 메서드 + cleanup CLI 추가
- `/home/jay/workspace/dispatch.py` — _cleanup_reserved() 함수 + 실패 분기 호출 추가
- `/home/jay/workspace/dashboard/server.py` — stale_tasks 카운팅 + is_stale 플래그 추가
- `/home/jay/workspace/teams/dev1/test_stale_cleanup.py` — 테스트 10건 (신규)

## 테스트 결과

```
10 passed in 0.04s
```

- test_cleanup_stale_running: running 3h → stale 전환 확인
- test_cleanup_stale_reserved: reserved 45m → stale 전환 확인
- test_cleanup_no_false_positive: threshold 이내 running/reserved 미전환 확인
- test_cleanup_completed_untouched: completed 상태 무변경 확인
- test_cleanup_custom_thresholds: 커스텀 threshold 동작 확인
- test_cleanup_reserved_removes_entry: reserved 삭제 확인
- test_cleanup_reserved_skips_non_reserved: non-reserved 건너뛰기 확인
- test_get_team_stats_stale_counting: running 2h 초과 stale 카운트 확인
- test_get_team_stats_reserved_stale_counting: reserved 30m 초과 stale 카운트 확인
- test_get_tasks_info_is_stale_flag: is_stale 플래그 6가지 케이스 확인

## 버그 유무

없음. 모든 테스트 통과, 기존 기능에 영향 없음 확인.

## 비고

- cleanup 서브커맨드를 cron으로 매시간 실행하면 stale 자동 정리 가능: `0 * * * * python3 /home/jay/workspace/memory/task-timer.py cleanup`
- 대시보드 API(`/api/stats`, `/api/tasks`)에서 stale 정보가 실시간 반영됨
- 기존 수동 정리된 22건(done 상태)은 그대로 유지 (역사 보존)
