# task-1876: 와치독 재위임 폭주(Retry Loop) 수정

## S - Situation
session-watchdog.sh가 systemd timer로 2분마다 실행되어 stalled 봇을 감지하고 재위임하는 역할을 수행 중이다.

## C - Complication
완료된 작업(task-1869_2.2+1)의 재시도 계열(+N)이 독립 task_id로 생성되어, 원본 완료(.done)를 확인하지 못하고 +2→+3→+4→+5→+6까지 연쇄 재위임 폭주가 발생했다. 근본 원인 3가지: (1) +N이 원본 .done을 참조하지 않음, (2) 새 task_id 생성 시 retry_count가 0으로 리셋되어 MAX_RETRY 무력화, (3) 완료 봇의 heartbeat 부재로 STALLED 오판.

## Q - Question
재시도 계열(+N)의 폭주를 방지하면서 정상 stalled 감지 및 재위임 기능은 유지할 수 있는가?

## A - Answer
session-watchdog.sh에 3개 방어 로직을 추가하여 해결 완료. (1) base task .done 체크: +N task가 실행될 때 형제 task의 .done 존재 여부를 glob으로 확인하여 스킵 (84-99행), (2) 글로벌 retry 합산 상한: base task 기준 전체 +N의 retry_count를 합산하여 상한(3)을 초과하면 재위임 거부 (220-236행), (3) base task end_time 체크: 원본 task의 end_time 존재 시 +N도 완료 처리 (182-191행). 스모크테스트 8/8건 통과, bash -n 문법 검사 통과.

## 수정 파일
- `/home/jay/workspace/scripts/session-watchdog.sh` — 3곳 수정 (추가 위주, 기존 로직 변경 없음)
- `/home/jay/workspace/teams/dev1/tests/test_watchdog_retry_loop.sh` — 신규 (스모크테스트)

## 수정 상세

### 수정 1: base task .done 체크 (84-99행)
- `TASK_ID`에서 `+N` 접미사를 제거하여 `BASE_TASK_ID` 추출
- `BASE_TASK_ID != TASK_ID`일 때만 형제 체크 진입 (base task 자체는 기존 78행에서 처리)
- `${EVENTS_DIR}/${BASE_TASK_ID}*.done` glob으로 형제 .done/.done.acked/.done.clear 검색
- 발견 시 `task-timer.py end` 호출 후 continue

### 수정 2: 글로벌 retry_count 합산 (220-236행)
- base task ID로 시작하는 모든 형제 task의 retry_count를 jq로 합산 (각 sibling에 +1)
- GLOBAL_MAX_RETRY=3 초과 시 재위임 거부, STALLED_LIST에 global-retry-limit으로 기록

### 수정 3: base task end_time 체크 (182-191행)
- +N task일 때 원본 base task의 end_time 존재 여부를 jq로 확인
- end_time 존재 시 task-timer.py end 호출 후 continue

## 테스트 결과
스모크테스트 8/8 PASS:
- 시나리오 1: +1 .done 존재 시 +2 형제 완료 감지 (PASS)
- 시나리오 1: +N은 BASE와 다름 → 형제 체크 진입 (PASS)
- 시나리오 1: base task 자체는 형제 체크 스킵 (PASS)
- 시나리오 2: 4 sibling (rc=1,1,1,0) → 합산=7 >= 3 → 거부 (PASS)
- 시나리오 2: 단일 task (rc=0) → 합산=1 < 3 → 허용 (PASS)
- 시나리오 3: base task end_time 존재 → +1 재위임 스킵 (PASS)
- 시나리오 3: base task end_time 없음 → +1 정상 진행 (PASS)
- 시나리오 4: bash -n 문법 검사 통과 (PASS)

## 발견 이슈 및 해결

### 자체 해결 (3건)
1. **shellcheck 미설치** — bash -n으로 대체 검증 (문법 검사 통과)
2. **BASE_TASK_ID 변수명 충돌** — 각 수정 블록에서 고유 변수명 사용 (BASE_TASK_ID, BASE_TASK_ID_END, BASE_TASK_ID_FOR_RETRY)
3. **grep 결과가 빈 경우 set -e 위반 가능** — jq 파이프라인에 `2>/dev/null` 및 빈 문자열 체크 적용

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

## 모델 사용 기록
- 불칸(백엔드) / 작업: 와치독 스크립트 3건 수정 + shellcheck / 사용 모델: sonnet
- 아르고스(테스터) / 작업: 스모크테스트 작성 및 실행 / 사용 모델: sonnet

## QC 검증 결과
```
overall: PASS (보고서/이벤트 생성 후)
data_integrity: PASS
spec_compliance: PASS
tdd_check: WARN (bash 스크립트 — 구현 먼저 작성 후 테스트, Lv.1 시스템 수정이므로 허용)
pyright_check: SKIP (Python 파일 없음)
style_check: SKIP (Python 파일 없음)
```

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

### 수정 파일 목록
- /home/jay/workspace/scripts/session-watchdog.sh: 3회 (Edit)
- bash_cmd: 2회 (Bash)
- /home/jay/workspace/memory/reports/task-1876.md: 1회 (Write)
- /home/jay/workspace/memory/tasks/task-1876.md: 1회 (dispatch)
- /home/jay/workspace/teams/dev1/tests/test_watchdog_retry_loop.sh: 1회 (Write)

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

