# task-1719.1 완료 보고서: task-timers.json Atomic Write 긴급 수정

## SCQA

**S**: dispatch.py의 `_patch_timer_metadata()`와 task-timer.py가 동일한 `task-timers.json` 파일에 쓰기를 수행하며, flock 기반 상호 배제가 적용되어 있다.

**C**: flock 내부에서 `open("w")` + `json.dump()`로 직접 쓰기하는 패턴이 crash-safe하지 않아, 지난 1시간 동안 3회 JSON 파손 발생. 대시보드에 작업중 팀 0개 표시, watchdog 오동작, counter 소실로 dispatch.py 에러 발생 중.

**Q**: 동시 쓰기 환경에서 JSON 파손을 원천 차단하고 기존 동작의 회귀 없이 수정할 수 있는가?

**A**: 모든 JSON 쓰기 위치에 atomic write 패턴(temp file + fsync + os.replace)을 적용하여 파손을 원천 차단. dispatch.py는 기존 `utils/atomic_write.py`의 `atomic_json_write()` 유틸리티를 활용, task-timer.py는 기존 atomic write에 누락된 `flush()`+`fsync()` 추가 및 pipeline-status.json 쓰기를 atomic 패턴으로 교체. 테스트 326건(신규 12 + 기존 314) 전부 통과, 회귀 0건.

## 수정 내역

### 1. dispatch.py `_patch_timer_metadata()` (핵심 수정)
- **dispatch.py:30** — `from utils.atomic_write import atomic_json_write` import 추가
- **dispatch.py:715** — `open("w")` + `json.dump()` → `atomic_json_write(timer_file, data)` 교체
- flock(LOCK_EX) 로직은 그대로 유지 (cross-process coordination)

### 2. task-timer.py `_save_timers()` (보강)
- **task-timer.py:127-128** — `tmp.flush()` + `os.fsync(tmp.fileno())` 추가
- 기존 atomic write(temp+replace)에 fsync를 추가하여 OS 버퍼 미플러시 위험 제거

### 3. task-timer.py `_update_pipeline_status()` (수정)
- **task-timer.py:493-509** — 데이터 파일에 직접 flock+write하던 패턴을 별도 lock 파일(`.pipeline-status.lock`) + `NamedTemporaryFile` + `fsync` + `os.replace` 패턴으로 교체

### 4. session-watchdog.sh (확인 완료 — 수정 불필요)
- 이미 `flock` + `mktemp` + `jq` + `mv` 패턴 사용 중 (lines 164-171)

## 테스트 결과

### 신규 테스트 (tests/test_atomic_timer_write.py) — 12/12 passed (0.36s)
- TC1: 10 스레드 x 5회 동시 패치 → JSON 무결성 확인
- TC2: patch 워커 5 + save 워커 5 동시 실행 → 파손 없음
- TC3: 단일 패치 회귀 (메타데이터 정합성, 다른 task 보존, 존재하지 않는 task_id noop)
- fsync 포함 일관성, temp 파일 정리, inode 변경(os.replace 동작) 검증
- flock 직렬화: 10 스레드 counter/task 전체 보존

### 기존 회귀 테스트
- tests/test_task_timer.py — 141/141 passed (0.46s)
- tests/test_dispatch.py — 173/173 passed (2.62s)
- **총 326건 전부 통과, 회귀 0건**

## 발견 이슈 및 해결

### 자체 해결 (3건)
1. **dispatch.py 비원자적 쓰기** — `atomic_json_write()` 유틸리티 활용으로 교체
2. **task-timer.py _save_timers() fsync 누락** — `flush()` + `fsync()` 2줄 추가
3. **task-timer.py _update_pipeline_status() 비원자적 쓰기** — 별도 lock 파일 + temp+fsync+replace 패턴 적용

### 범위 외 미해결 (0건)
없음.

## 산출물 파일

- /home/jay/workspace/dispatch.py
- /home/jay/workspace/memory/task-timer.py
- /home/jay/workspace/tests/test_atomic_timer_write.py

## 모델 사용 기록

- 팀원: 아르고스(테스터) / 작업: atomic write 테스트 12건 작성 / 모델: sonnet
- 팀원: 불칸(백엔드) / 작업: dispatch.py _patch_timer_metadata atomic write 적용 / 모델: sonnet
- 팀원: 불칸(백엔드) / 작업: task-timer.py _save_timers fsync + _update_pipeline_status atomic write / 모델: sonnet

## QC 증거

```
tests/test_atomic_timer_write.py — 12 passed in 0.36s
tests/test_task_timer.py — 141 passed in 0.46s
tests/test_dispatch.py — 173 passed in 2.62s
pyright: dispatch.py 신규 경고 0건 (기존 import resolution 경고만 존재, sys.path 패턴)
```

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

### 수정 파일 목록
- /home/jay/workspace/tests/test_atomic_timer_write.py: 9회 (Edit, Write)
- bash_cmd: 8회 (Bash)
- /home/jay/workspace/dispatch.py: 3회 (Edit)
- /home/jay/workspace/memory/task-timer.py: 2회 (Edit)
- /home/jay/workspace/memory/reports/task-1719.1.md: 1회 (Write)
- /home/jay/workspace/memory/tasks/task-1719.1.md: 1회 (dispatch)

### 도구 사용 현황
- Edit: 13회
- Bash: 8회
- Write: 2회
- dispatch: 1회

