# task-2175 완료 보고서: task-timer running 미종료 버그 조사 및 수정

## SCQA

**S**: dispatch.py가 작업 시작 시 task-timer.py start를 호출하고, finish-task.sh가 완료 시 .done 생성 → task-timer.py end → notify-completion을 순차 수행하는 구조로 운영 중이다.

**C**: task-2160(dev2), task-2161(dev1)이 실제 완료(.done 처리, 보고서 존재)됐는데 task-timers.json에서 status="running"으로 5시간 이상 남아있었음. whisper-briefing에서 "1팀:작업중 / 2팀:작업중"으로 잘못 표시 → 제이회장님에게 오보.

**Q**: timer end 누락의 근본 원인은 무엇이며, 재발 방지를 위해 어떤 안전장치를 추가해야 하는가?

**A**: 2가지 수정을 동시 적용. (1) finish-task.sh에 EXIT trap 추가 → 비정상 종료 시에도 .done 파일이 존재하면 timer end 자동 호출. (2) done-watcher.sh에 safety-net 추가 → cron 주기 실행 시 running인데 done marker가 있는 task를 자동 정리.

## 근본 원인 분석

### 조사 결과

1. **dispatch.py** (라인 2918-2929): 작업 시작 시 `task-timer.py start` 자동 호출 — 정상
2. **finish-task.sh** (라인 644-648): 정상 완료 시 `task-timer.py end` 호출 — 정상
3. **문제**: finish-task.sh는 `set -euo pipefail` (라인 4)로 실행됨 → 중간 단계 실패 시 즉시 exit → timer end 미도달
   - QC FAIL (라인 160, 178): `exit 1` → timer end 미호출
   - 노하우 검증 실패 (라인 120-123): `exit 1` → timer end 미호출
   - 머지 단계 에러: 비정상 종료 → timer end 미호출
4. **추가 경로**: 팀장 봇 세션이 finish-task.sh 호출 전에 종료될 수도 있음 (cron 타임아웃 등)

### 직접 증거 (task-2160, task-2161)

- task-2160: timer start 07:37 → .qc-done 08:35 → .done.clear 08:35 → timer end 수동 13:06 (**5시간 29분 leak**)
- task-2161: timer start 08:04 → .qc-done 08:35 → .done.notified 08:35 → timer end 수동 13:06 (**5시간 1분 leak**)
- 두 task 모두 `.done` 파일 자체가 부재 → finish-task.sh의 .done 생성 단계 이전에 세션 종료되었거나, 다른 경로(notify-completion 등)로 완료 처리된 것으로 추정

## 수정 내용

### 1. finish-task.sh — EXIT trap 추가 (1차 방어)

- **파일**: `/home/jay/workspace/scripts/finish-task.sh`
- **변경**: 라인 12-24에 `cleanup_timer()` 함수 + `trap cleanup_timer EXIT` 추가
- **동작**: 스크립트 비정상 종료 시 `.done` 파일 존재 여부 확인 → 있으면 timer end 호출, 없으면 스킵(QC FAIL 재시도 허용)
- **라인 659**: 정상 timer end 전 `_timer_ended=1` 설정 → EXIT trap의 이중 호출 방지

### 2. done-watcher.sh — Safety-net 로직 추가 (2차 방어)

- **파일**: `/home/jay/workspace/scripts/done-watcher.sh`
- **변경**: 라인 140-180에 safety-net 블록 추가
- **동작**: cron 주기 실행 시 task-timers.json에서 running 상태 task 스캔 → `.done`, `.done.acked`, `.done.clear` 마커 존재 확인 → 마커 있으면 `task-timer.py end` 자동 호출
- **의의**: finish-task.sh trap이 작동하지 않는 극단적 경우(세션 강제 종료, finish-task.sh 미호출 등)에도 leak 정리

## 생성/수정 파일

| 파일 | 변경 유형 | 설명 |
|------|-----------|------|
| `/home/jay/workspace/scripts/finish-task.sh` | 수정 | EXIT trap 추가 (라인 12-24, 659) |
| `/home/jay/workspace/scripts/done-watcher.sh` | 수정 | Safety-net 블록 추가 (라인 140-180) |

## 테스트 결과

- bash -n finish-task.sh: SYNTAX OK
- bash -n done-watcher.sh: SYNTAX OK
- trap 시뮬레이션 (Scenario 1: QC FAIL): `.done` 없음 → timer end 스킵 — 정상
- trap 시뮬레이션 (Scenario 2: post-.done error): `.done` 있음 → timer end 호출 — 정상
- safety-net 단독 실행: 현재 running 5건 중 done marker 보유 0건 → 정리 대상 없음 — 정상 (기존 leak은 수동 정리 완료)

## 발견 이슈 및 해결

1. **task-2160/2161의 `.done` 파일 부재**: `.done.acked`, `.done.clear` 등 파생 마커는 존재하나 원본 `.done`이 없음 → finish-task.sh가 `.done` 생성 전 중단되었거나 다른 경로로 완료 처리됨. safety-net이 이 패턴을 커버함.
2. **finish-task.sh의 `set -euo pipefail` 위험**: QC FAIL 시 exit 1 → timer end 미호출. trap 추가로 해결.
3. **다른 경로 완료 위험**: 팀장 봇이 수동으로 .done을 생성하거나, 세션 종료 시 불완전 상태 발생 가능. done-watcher safety-net으로 보완.

## L1 스모크테스트 결과

- 서버 재시작: 해당없음 (shell script 수정, 서버 코드 아님)
- API 응답 확인: 해당없음
- 스크린샷: 해당없음
- bash -n 문법 검증: 2개 파일 모두 PASS
- trap 시뮬레이션 테스트: 2 시나리오 모두 PASS

## 셀프 QC

- [x] 1. 영향 파일: finish-task.sh, done-watcher.sh (다른 파일 영향 없음)
- [x] 2. 엣지 케이스: QC FAIL 시 timer end 스킵 확인, EXIT trap 이중 호출 방지 확인
- [x] 3. 작업 지시와 일치: timer end 누락 근본 원인 조사 + 수정 완료
- [x] 4. 에러 처리: `|| true` 패턴으로 timer end 실패 시에도 스크립트 중단 방지
- [x] 5. 테스트: bash -n 문법 검증 + trap 시뮬레이션 2 시나리오
- [x] 6. 발견 이슈 3건 모두 해결
- [x] 7. 코드 아키텍처: 기존 패턴 준수 (trap, `|| true` 방어)
- [x] 8. 인터페이스 변경 없음

## 모델 사용 기록

- 비슈누(팀장/Opus): 설계, 근본 원인 분석, 검증, 보고서 작성
- 카르티케야(백엔드/Sonnet): finish-task.sh EXIT trap 구현
- 하누만(테스터/Sonnet): done-watcher.sh safety-net 구현

## 세션 통계
- 총 도구 호출: 0회

