[HAN-230] CCR 루틴 타임아웃 제한 해결 — 분석 결과
Summary
"300s 타임아웃"은 스캔 주기(EXECUTION_SCAN_SEC) 혼입. 실제 태스크 timeout은 JARVIS_TIMEOUT_SEC(기본 1800s)이며 .env 실제값 확인 후 상향 가능. 장기 태스크는 분할 설계가 근본 해결.
Context
2026-05-21 Nano(process exit 분석), Asurada(wrap-up) 동시 중단. 이슈 제목의 "300s"는 부정확 — 실제 로그에서 asurada는 672s에서 타임아웃. 원인 분석 및 재발 방지 패턴 수립.
---
AC 1: 타임아웃 한도 조정 가능 여부
결론: 조정 가능. 설정 위치 명시.
실제 타임아웃 변수 목록 (`bridge.py`)
| 변수 | 위치 | 기본값 | 역할 |
|---|---|---|---|
| `JARVIS_TIMEOUT_SEC` | `bridge.py:138` | 1800s | Claude subprocess `communicate(timeout=...)` — 이게 태스크 타임아웃 |
| `MONITOR_THREAD_TIMEOUT_SEC` | `bridge.py:87` | 900s | 스레드 비활성 시 모니터 닫기 |
| `EXECUTION_SCAN_SEC` | `agents/execution.py:14` | 300s | Execution Layer 폴링 주기 (태스크 타임아웃 **아님**) |
| `EXECUTION_TIMEOUT_SEC` | `agents/execution.py:15` | 3600s | Execution Layer Claude 호출 timeout |
이슈 제목 "300s" 혼입 원인
EXECUTION_SCAN_SEC=300이 .env.example에 노출되어 "300s 타임아웃"으로 오인됨. 실제로 이 값은 5분마다 APPROVED 티켓을 폴링하는 간격이며 태스크를 중단시키지 않는다.
실제 사고 분석
- 로그
wedged-20260521T101246Z.txt확인: asurada turn 1 **672s** 경과 후in 0 out 0 에러 1건 JARVIS_TIMEOUT_SEC기본값(1800s)보다 낮은 672s 종료 →.env에JARVIS_TIMEOUT_SEC가 실제값으로 오버라이드 되어 있거나 Claude Code CLI 내부 limit 도달 가능성
조정 방법
.env 파일에서:
```
JARVIS_TIMEOUT_SEC=3600 # 1시간으로 상향
MONITOR_THREAD_TIMEOUT_SEC=1800 # 30분으로 상향 (선택)
```
주의: Claude Code CLI(subprocess)가 자체 내부 timeout을 가질 수 있음. bridge.py의 JARVIS_TIMEOUT_SEC를 올려도 CLI 내부 한도(확인 필요)가 먼저 걸릴 수 있다.
---
AC 2: 장기 태스크 처리 전략
결론: 혼합 전략 채택 — 즉시 threshold 상향 + 분할 설계 병행.
즉시 조치 (조정)
1. .env에서 현재 JARVIS_TIMEOUT_SEC 값 확인 (cat .env | grep TIMEOUT)
2. 낮게 설정되어 있으면 3600s로 상향
3. MONITOR_THREAD_TIMEOUT_SEC도 JARVIS_TIMEOUT_SEC보다 크게 설정
근본 해결 (분할)
문제: /wrap-up, 대량 분석 같은 태스크는 본질적으로 10분+ 소요. timeout을 늘려도 20분 태스크가 생기면 재발.
분할 원칙:
| 태스크 유형 | 현재 | 개선 방향 |
|---|---|---|
| `/wrap-up` | 단일 Claude 턴에서 전체 처리 | Phase 1(캡처) → 중간 저장 → Phase 2(라우팅) → Phase 3(sync) 3단계 분리 |
| 대량 분석 (Nano) | 단일 워커에서 전체 처리 | 소스별 Haiku 서브에이전트 병렬화, 결과 집계는 별도 턴 |
| 코드 구현 (Asurada) | 이미 worktree 단위 분리 | 이슈 분할(sub-issue)로 단위 크기 제어 |
권장 구분선
단일 턴 < 5분 → 그대로 진행
5~15분 예상 → JARVIS_TIMEOUT_SEC 여유 있는지 확인 후 진행
15분+ 예상 → 태스크 분할 설계 또는 Nano 병렬화로 내려야 함
---
AC 3: 재발 방지 패턴
패턴 1: 태스크 시작 시 시간 예산 명시
긴 태스크 프롬프트에 추가:
```
Budget: complete within 8 minutes. If approaching time limit, save partial results and stop cleanly.
```
패턴 2: `/wrap-up` 단계 분리
현재 /wrap-up은 단일 에이전트에서 캡처→라우팅→승격→트리거를 모두 처리. 개선안:
1. wrap-phase1: 교훈 캡처 + .learnings.md 기록 (3분 이내)
2. wrap-phase2: 라우팅 결정 + memory 업데이트 (3분 이내)
3. wrap-phase3: git push + 세션 prompt 생성 (2분 이내)
각 phase 완료 후 Slack에 중간 보고 → 다음 phase 트리거.
패턴 3: Nano 대형 태스크 분산
Nano가 "N개 소스 조사" 같은 태스크를 받으면:
- 소스 1개당 Haiku 서브에이전트 1개 병렬 실행
- 각 서브에이전트 작업 < 3분 설계
- Nano 자신은 집계만 담당 (< 2분)
패턴 4: 모니터 알림 → 조기 저장 훅
bridge.py 모니터가 "elapsed > 500s" 시점에 현재 상태를 state/ 파일에 저장하도록 확장 가능 (선택적 구현, HAN 별도 티켓).
---
Decisions
| 결정 | 근거 |
|---|---|
| 즉시: `JARVIS_TIMEOUT_SEC=3600` 상향 권고 | 현재 기본값 1800s인데 672s에 중단 → .env 값 확인 + 여유 확보 |
| 장기: `/wrap-up` 3-phase 분리 | 단일 턴 < 5분 원칙 준수, 재발 방지 근본 해결 |
| "300s 타임아웃" 정정 | `EXECUTION_SCAN_SEC`는 폴링 주기, 태스크를 종료시키지 않음 |
Risks
| 위험 | 영향 | 대응 |
|---|---|---|
| Claude Code CLI 내부 timeout이 실제 원인일 경우 | env 조정해도 재발 | `claude --help` timeout 옵션 확인, `--max-turns` 파라미터 검토 |
| /wrap-up 3-phase 분리 시 중간 단계 실패 | phase 2 이후 미완 메모리 | phase 1 완료 후 Slack 보고 → 사용자가 다음 phase 트리거 |
링크
- Linear: https://linear.app/hangman-lab/issue/HAN-230