claimed 상태 정체 태스크 자동 타임아웃/재할당 정책 제안
배경 / 검증 근거 (실측 쿼리 결과)
라이브 DB: /Users/ron/.hermes/data/ops_multiagent.db (실행 확인 완료, ~/.hermes/workspace/ops_multiagent.db 및 ~/ops_multiagent.db 등은 stale 사본)
1) claimed→완료 실측 소요시간 (최근 완료 15건, id 36129~36145)
id agent status claimed_at completed_at dur_sec
36142 analyst-technical failed 2026-08-17 16:04:09 2026-08-17 16:05:42 93
36145 cowork failed 2026-08-17 16:03:10 2026-08-17 16:05:32 142
36144 analyst-fundamental failed 2026-08-17 16:03:10 2026-08-17 16:05:14 124
36141 analyst-technical failed 2026-08-17 16:03:10 2026-08-17 16:04:07 57
36140 analyst-technical failed 2026-08-17 15:59:00 2026-08-17 15:59:58 58
36138 codex failed 2026-08-17 15:54:19 2026-08-17 15:55:49 90
36136 analyst-technical failed 2026-08-17 15:53:30 2026-08-17 15:55:32 122
36137 analyst-macro failed 2026-08-17 15:52:07 2026-08-17 15:54:52 165
36135 codex failed 2026-08-17 15:52:07 2026-08-17 15:53:37 90
36134 analyst-technical failed 2026-08-17 15:51:55 2026-08-17 15:53:28 93
36132 analyst-fundamental failed 2026-08-17 15:50:06 2026-08-17 15:52:08 122
36133 cowork failed 2026-08-17 15:50:07 2026-08-17 15:52:08 121
36131 codex failed 2026-08-17 15:50:06 2026-08-17 15:51:41 95
36130 analyst-macro failed 2026-08-17 15:47:41 2026-08-17 15:49:44 123
36129 analyst-technical failed 2026-08-17 15:47:42 2026-08-17 15:49:42 120
24시간 집계 (에이전트별 평균/최대):
target_agent n avg_sec max_sec
analyst-fundamental 4 119.5 193.0
analyst-macro 4 178.7 214.0
analyst-technical 6 92.7 122.0
codex 8 149.3 365.0
cowork 3 241.7 304.0
ron 2 1.5 2.0
관측 최댓값: codex 365초. 정상 처리 범위 전체 P100 = 365초.
2) 현재 구조 확인 결과
- orchestrator.py 1347행
check_cowork_stall_and_rescue()— cowork 대상 stale(90초)/stuck(180초) 감지 후 codex/ron 대체 태스크 생성 로직이 이미 존재하나, 2552행에서# rescues = check_cowork_stall_and_rescue(state)로 주석 처리,rescues = 0고정. 2026-03-08 비활성화 기록. - agent_queue_worker.py 3038행
STALE_CLAIM_SECONDS = 300—_pick_command_local()(1288~1401행)에서 동일 agent가 재기동해 자신의 claim을 재회수하는 self-reclaim만 구현. 타 agent가 claim한 채 죽었을 때 회수할 제3자 로직 없음. - guardian: launchd에는
com.openclaw.agent-queue-guardian(PID 81155, KeepAlive=true, running) 존재하나,/api/bus/agents응답 9개 항목(analyst-fundamental/macro/technical, codex, cowork, data-analyst, drift-recovery, evidence-sentinel, ron)에 guardian 자체가 누락 — 대시보드 관점에서 "OFF"로 보임. 로그 40줄 전량{"status":"idle","handled":0}— target_agent='guardian' 태스크가 큐에 없어 실질적으로 아무 것도 안 함. - agent_registry.py 21~25행
ACTIVE_AGENT_NAMES에 guardian 미포함 → create_task() 화이트리스트 가드(1266행BLOCKED_DEAD_AGENT)에 걸려 guardian은 애초에 태스크를 받을 수 없는 구조. - ops_todos 테이블 확인:
~/.hermes/data/ops_multiagent.db에 존재. status(todo/doing/done 등), source 컬럼 보유 — 워닝 등록 즉시 활용 가능. - CYCLE_INTERVAL_SEC = 120초 (idle_streak 누적 시 최대 300초까지 증가). LLM_BUDGET_SEC 워커측 기본 90초, guardian plist override 240초. TOOL_USE_CMD_TIMEOUT=20초.
[권고]
1순위: orchestrator.py run_cycle_locked()에 전체 에이전트 대상 claimed 스윕 함수(check_claimed_stale_and_rescue)를 신규 추가한다.
- WARN 300초: 기존 STALE_CLAIM_SECONDS와 동일 기준선 재사용, 로그만 남기고 조치 없음(관측 단계).
- CRITICAL 900초(15분): status='claimed'→'failed' 강제 전환, result_note에 "guardian-timeout-reassign, claimed_by=X, claimed_at=Y" 기록 후 동일 target_agent/title/body로 status='queued' 재투입([자동재시도 #N] 헤더 카운터 증가).
- 재시도 3회 초과 시: 재생성 대신 target_agent='ron'으로 에스컬레이션 + ops_todos에 source='claimed-timeout-guard', status='todo' 등록, harry DM 알림.
- 근거: 실측 24h 정상 완료 케이스 최댓값 365초(codex). 900초는 이 최댓값의 약 2.5배, 중앙값(약 120초) 대비로는 7.5배 — 정상 지연(예: cowork 304초, codex 365초)을 오탐 실패시키지 않으면서 방치 시간을 15분으로 제한.
2순위: 해리 원안 30분(1800초)보다 900초(15분)를 권고. 이유: 30분은 관측 최댓값(365초)의 약 5배가 아니라 실측 P100 대비 지나치게 넉넉해, 실제 정체 상황에서 최대 30분간 방치되는 감지 지연 리스크가 존재. 다만 오탐 발생 시 조정 여지를 두기 위해 최초 배포 시 1800초로 시작 후 1주일 데이터로 900초까지 단계적으로 낮추는 방식도 대안으로 병기.
3순위(guardian 대체): guardian LaunchAgent를 즉시 unload하기보다, ACTIVE_AGENT_NAMES에 편입하지 않는 대신 orchestrator.py 상시 루프(120초 주기)가 이 감시 역할을 흡수하는 구조로 전환한다. orchestrator는 이미 매 사이클 get_queue_status()로 전체 commands를 조회하므로 별도 프로세스 없이 동일 사이클에서 claimed 스윕이 가능해 단일 장애점을 하나 줄인다(guardian 프로세스 생존 여부에 의존하지 않음). guardian LaunchAgent 자체의 unload/제거는 해리 승인 필요 항목이라 이 제안서에서는 조사만 하고 실행하지 않는다.
[현황] (요약 — 상세는 위 실측 로그 참조)
claimed 정체 현재 0건(라이브 DB 기준, 확인 시각 2026-08-17 16:05). 최근 15건 완료 소요 57~365초. self-reclaim만 존재, 제3자 회수 로직 없음. guardian은 launchd 기동 중이나 화이트리스트 미포함으로 사실상 무동작.
[리스크]
- 무한 재시도 루프: 3회 상한 없이는 rate-limit 등 근본원인 미해소 시 claimed→failed→queued 반복으로 큐 잼 정책(상한 6/에이전트당 2)과 충돌.
- 오탐 강제 실패: 임계값을 300초 등으로 너무 짧게 잡으면 cowork(최대 304~365초대) 정상 지연 케이스가 오탐 처리될 위험 — 900초 CRITICAL로 완충.
- 단일 장애점: orchestrator.py 프로세스 자체가 죽으면 신규 스윕도 guardian과 동일하게 무력화된다. orchestrator의 launchd KeepAlive/워치독은 이 제안과 별개로 점검 필요.
[검증방법]
- KPI:
sqlite3 ~/.hermes/data/ops_multiagent.db "SELECT MAX((strftime('%s','now','localtime')-strftime('%s',claimed_at))) FROM bus_commands WHERE status='claimed'"로 P100 < 900초 상시 확인. - 1주 경과 후:
SELECT COUNT(*) FROM bus_commands WHERE result_note LIKE '%guardian-timeout-reassign%' AND claimed_at > datetime('now','-7 days')건수가 동기간 전체 태스크 대비 5% 미만인지 집계. - 기대값: 강제 재할당 발생률 5% 미만, 정체 태스크 15분 내 100% 해소.
- 롤백 조건: 강제 전환 후 원래 워커가 45초 이내 완료 응답을 보내는 오탐 사례가 전체 강제전환 건의 10% 이상이면 CRITICAL 임계값을 900초→1800초로 상향.