# task-1194.1 완료 보고서: Task ID 번호 점프 수정 + 채번 로직 방어 코드 추가

## SCQA

**S**: task-timers.json 기반 task ID 채번 시스템이 `max(모든 ID) + 1` 방식으로 운영 중이며, 현재까지 1,192건의 task가 정상 채번되었다.

**C**: task-1182.1(dev5팀) 검증 테스트에서 task-9991~9993을 task-timers.json에 생성하여 max가 9993으로 점프. 이후 정상 작업 11건이 task-9994~10002로 채번됨 (정상 범위: 1183~1194).

**Q**: 비정상 ID 점프를 복구하고, 동일 사고를 재발 방지할 수 있는가?

**A**: 4-Phase 수정 완료. Phase 1: 10개 task를 1183~1192로 리넘버링 (91개 파일/엔트리 변경, 에러 0건). Phase 2: dispatch.py를 카운터 파일 기반 채번으로 전환하고 이상치 필터링 방어 로직 추가. Phase 3: task-id-convention.md 문서화. Phase 4: 테스트 13건 추가, 전체 111건 통과.

---

## 산출물

### 생성 파일
- `/home/jay/workspace/teams/dev1/renumber_task_ids.py` — 리넘버링 스크립트 (일회성)
- `/home/jay/workspace/memory/.task-counter` — 카운터 파일 (값: 1195)
- `/home/jay/workspace/memory/specs/task-id-convention.md` — 채번 규칙 문서

### 수정 파일
- `/home/jay/workspace/dispatch.py` — generate_task_id() 카운터 기반 전환 + _compute_next_id_from_timers() 추가 (264~298행, 300~347행)
- `/home/jay/workspace/tests/test_dispatch.py` — TestCounterBasedTaskId, TestOutlierFiltering, TestCounterFileEdgeCases 3개 클래스 13개 테스트 추가
- `/home/jay/workspace/memory/task-timers.json` — 10개 키 리넘버링 (9991~10000 → 1183~1192)
- `/home/jay/workspace/memory/daily/2026-03-28.md` — 7개 task ID 참조 치환

### 리넘버링된 파일 (old → new)
- `/home/jay/workspace/memory/tasks/task-9994.1.md` → `/home/jay/workspace/memory/tasks/task-1186.1.md`
- `/home/jay/workspace/memory/tasks/task-9995.1.md` → `/home/jay/workspace/memory/tasks/task-1187.1.md`
- `/home/jay/workspace/memory/tasks/task-9996.1.md` → `/home/jay/workspace/memory/tasks/task-1188.1.md`
- `/home/jay/workspace/memory/tasks/task-9997.1.md` → `/home/jay/workspace/memory/tasks/task-1189.1.md`
- `/home/jay/workspace/memory/tasks/task-9998.1.md` → `/home/jay/workspace/memory/tasks/task-1190.1.md`
- `/home/jay/workspace/memory/tasks/task-9999.1.md` → `/home/jay/workspace/memory/tasks/task-1191.1.md`
- `/home/jay/workspace/memory/tasks/task-10000.1.md` → `/home/jay/workspace/memory/tasks/task-1192.1.md`
- `/home/jay/workspace/memory/reports/task-9994.1.md` → `/home/jay/workspace/memory/reports/task-1186.1.md`
- `/home/jay/workspace/memory/reports/task-9995.1.md` → `/home/jay/workspace/memory/reports/task-1187.1.md`
- `/home/jay/workspace/memory/reports/task-9996.1.md` → `/home/jay/workspace/memory/reports/task-1188.1.md`
- `/home/jay/workspace/memory/reports/task-9997.1.md` → `/home/jay/workspace/memory/reports/task-1189.1.md`
- `/home/jay/workspace/memory/reports/task-9998.1.md` → `/home/jay/workspace/memory/reports/task-1190.1.md`
- `/home/jay/workspace/memory/reports/task-9999.1.md` → `/home/jay/workspace/memory/reports/task-1191.1.md`
- `/home/jay/workspace/memory/reports/task-10000.1.md` → `/home/jay/workspace/memory/reports/task-1192.1.md`
- `/home/jay/workspace/memory/events/task-9991.1.done.clear` → `/home/jay/workspace/memory/events/task-1183.1.done.clear`
- `/home/jay/workspace/memory/events/task-9992.1.done.clear` → `/home/jay/workspace/memory/events/task-1184.1.done.clear`
- `/home/jay/workspace/memory/events/task-9993.1.done.clear` → `/home/jay/workspace/memory/events/task-1185.1.done.clear`
- `/home/jay/workspace/memory/events/task-9994.1.completion.txt` → `/home/jay/workspace/memory/events/task-1186.1.completion.txt`
- `/home/jay/workspace/memory/events/task-9994.1.done.acked` → `/home/jay/workspace/memory/events/task-1186.1.done.acked`
- `/home/jay/workspace/memory/events/task-9994.1.done.notified` → `/home/jay/workspace/memory/events/task-1186.1.done.notified`
- `/home/jay/workspace/memory/events/task-9995.1.completion.txt` → `/home/jay/workspace/memory/events/task-1187.1.completion.txt`
- `/home/jay/workspace/memory/events/task-9995.1.done.acked` → `/home/jay/workspace/memory/events/task-1187.1.done.acked`
- `/home/jay/workspace/memory/events/task-9995.1.done.notified` → `/home/jay/workspace/memory/events/task-1187.1.done.notified`
- `/home/jay/workspace/memory/events/task-9996.1.completion.txt` → `/home/jay/workspace/memory/events/task-1188.1.completion.txt`
- `/home/jay/workspace/memory/events/task-9996.1.done.acked` → `/home/jay/workspace/memory/events/task-1188.1.done.acked`
- `/home/jay/workspace/memory/events/task-9996.1.done.notified` → `/home/jay/workspace/memory/events/task-1188.1.done.notified`
- `/home/jay/workspace/memory/events/task-9997.1.completion.txt` → `/home/jay/workspace/memory/events/task-1189.1.completion.txt`
- `/home/jay/workspace/memory/events/task-9997.1.done.acked` → `/home/jay/workspace/memory/events/task-1189.1.done.acked`
- `/home/jay/workspace/memory/events/task-9997.1.done.notified` → `/home/jay/workspace/memory/events/task-1189.1.done.notified`
- `/home/jay/workspace/memory/events/task-9998.1.completion.txt` → `/home/jay/workspace/memory/events/task-1190.1.completion.txt`
- `/home/jay/workspace/memory/events/task-9998.1.done.acked` → `/home/jay/workspace/memory/events/task-1190.1.done.acked`
- `/home/jay/workspace/memory/events/task-9998.1.done.notified` → `/home/jay/workspace/memory/events/task-1190.1.done.notified`
- `/home/jay/workspace/memory/events/task-9999.1.completion.txt` → `/home/jay/workspace/memory/events/task-1191.1.completion.txt`
- `/home/jay/workspace/memory/events/task-9999.1.done.acked` → `/home/jay/workspace/memory/events/task-1191.1.done.acked`
- `/home/jay/workspace/memory/events/task-9999.1.done.notified` → `/home/jay/workspace/memory/events/task-1191.1.done.notified`
- `/home/jay/workspace/memory/events/task-10000.1.completion.txt` → `/home/jay/workspace/memory/events/task-1192.1.completion.txt`
- `/home/jay/workspace/memory/events/task-10000.1.done.acked` → `/home/jay/workspace/memory/events/task-1192.1.done.acked`
- `/home/jay/workspace/memory/events/task-10000.1.done.notified` → `/home/jay/workspace/memory/events/task-1192.1.done.notified`
- `/home/jay/workspace/memory/checkpoints/task-9997.1.md` → `/home/jay/workspace/memory/checkpoints/task-1189.1.md`
- `/home/jay/workspace/memory/meetings/task-9997.1-cycle1.md` → `/home/jay/workspace/memory/meetings/task-1189.1-cycle1.md`
- `/home/jay/workspace/memory/meetings/task-9997.1-cycle2.md` → `/home/jay/workspace/memory/meetings/task-1189.1-cycle2.md`
- `/home/jay/workspace/memory/meetings/task-9997.1-cycle3.md` → `/home/jay/workspace/memory/meetings/task-1189.1-cycle3.md`
- `/home/jay/workspace/teams/dev1/task-9997.1-implementation-plan.md` → `/home/jay/workspace/teams/dev1/task-1189.1-implementation-plan.md`
- `/home/jay/workspace/teams/dev1/task-9997.1-design.md` → `/home/jay/workspace/teams/dev1/task-1189.1-design.md`

---

## 테스트 결과

**전체 dispatch 테스트: 111건 통과, 0건 실패**

관련 테스트 세부:
- TestGenerateTaskId: 6건 통과 (기존, 회귀 없음)
- TestGenerateTaskIdErrorHandling: 5건 통과 (기존, 회귀 수정 포함)
- TestCounterBasedTaskId: 5건 통과 (신규)
- TestOutlierFiltering: 5건 통과 (신규)
- TestCounterFileEdgeCases: 3건 통과 (신규)

pyright: 0 errors, 0 warnings (check-files 대상)
black: 포맷 적용 완료

---

## 발견 이슈 및 해결

### 자체 해결 (4건)
1. **갭 임계값 불일치** — `> 1000` → `>= 1000` 수정. 스펙 "1000 이상이면 무시" 준수.
   - 수정: dispatch.py:293
2. **음수 카운터 방어 부재** — `next_num <= 0` 체크 추가, fallback 처리.
   - 수정: dispatch.py:316-317
3. **기존 테스트 회귀** — `test_corrupted_json_raises_runtime_error` 실패. `_compute_next_id_from_timers`에서 JSON 손상 시 fallback 대신 RuntimeError 발생하도록 복원.
   - 수정: dispatch.py:271-272
4. **black 포맷** — tests/test_dispatch.py 포맷 불일치 수정.

### 범위 외 미해결 (2건)
1. **task-1193.1 수동 리넘버링** — 범위 외 사유: dev3팀 작업 완료 후 수동으로 task-1193.1로 변경 필요. 현재 completed 상태이나, 리넘버링 스크립트 실행 시점에는 running이었으므로 안전하게 skip.
2. **task-1194.1 수동 리넘버링** — 범위 외 사유: 현재 실행 중인 작업(이 task 자체). 완료 후 task-1194.1로 수동 변경 필요.

---

## QC 자동 검증

```
pytest: 111 passed (dispatch 전체)
pyright: 0 errors, 0 warnings
black: 포맷 적용 완료
```

---

## 기술 상세

### dispatch.py 변경 요약
- `_compute_next_id_from_timers()` 헬퍼 함수 신규 (264~297행): 이상치 필터링 적용 후 다음 ID 계산
- `generate_task_id()` 개편 (300~347행): 카운터 파일(`.task-counter`) 우선 → fallback으로 timers 계산
- 이상치 판정: 정렬된 ID 간 갭 >= 1000이면 그 위는 이상치로 간주
- 카운터 파일 손상/음수 시 task-timers.json 기반 복구
- 기존 fcntl.flock 락 메커니즘 유지

---

## 마아트 독립 검증 결과

**전체 판정: PASS (조건부)**

- qc_verify.py: 7 PASS, 1 FAIL(.done 미존재 — 작업 진행 중 정상), 4 SKIP
- dispatch.py generate_task_id(): 카운터 기반 전환 확인 PASS
- _compute_next_id_from_timers(): 이상치 필터링 확인 PASS
- .task-counter: 존재 확인, 값 1196 (1195에서 신규 task 1건 소비로 증가, 정상 동작)
- task-id-convention.md: 존재 확인 PASS
- pytest 재실행: 111 passed, 0 failed PASS
- task-timers.json 리넘버링: 9991~10000 키 제거, 1183~1192 키 생성, 10001/10002 보존 PASS

미결 관찰: task-1193.1이 completed 상태임에도 task-1193.1로 미리넘버링. 향후 수동 정리 권고.
