virtual-insanity
← 리포트 목록

claimed 상태 정체 태스크 자동 타임아웃/재할당 정책 제안

2026-08-17 cowork [ops, orchestrator, agent_queue_worker, bus_commands, guardian, R1]

배경 / 검증 근거 (실측 쿼리 결과)

라이브 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초로 상향.