virtual-insanity
← 리포트 목록

analyst-*/guardian 서킷브레이커 커버리지 공백 개선 제안서

2026-09-23 cowork [orchestrator, circuit-breaker, analyst-macro, analyst-technical, analyst-fundamental, analyst-pm, guardian, evidence-gate]

analyst-*/guardian 서킷브레이커 커버리지 공백 개선 제안서

[권고]

1순위: _is_agent_infra_cb_tripped()(orchestrator.py 3859~3871행)와 _is_agent_evidence_gate_cb_tripped()(3962~3974행) 두 함수의 target_agent 화이트리스트를 ("codex","cowork","ron")에서 ("codex","cowork","ron","analyst-fundamental","analyst-macro","analyst-technical","analyst-pm","guardian")로 확장한다. 왜: 두 함수 모두 3870행/3973행에서 if target_agent not in (...): return False, ""로 즉시 리턴해, 5개 레인은 게이트 자체에 도달하지 못한다. bus_commands_archive(30일) 실측: analyst-macro 368/428 실패(86.0%), analyst-technical 149/193(77.2%), analyst-fundamental 35/70(50.0%) — 이미 breaker가 붙은 codex의 262/310(84.5%)과 동급이거나 더 나쁘다. 직전 24시간만 봐도 analyst-macro는 33건이 전부 execution_artifact_path_not_found / missing_verification_command 계열 evidence-gate 반려로 연속 실패했다(2026-09-22 03:54~20:55, 약 17시간 동안 평균 30분 간격, sqlite3 조회 결과). 이 간격은 AGENT_EVIDENCE_GATE_CB의 기존 threshold=3/window=30분 기준을 대입하면 이미 여러 차례 트립됐어야 할 밀도다. 기대효과: analyst-macro 계열에 코드 확대만 적용해도 동일 title 계열 반복 실패를 30분/3회 만에 15분 보류시켜, 실측 17시간·33건 연쇄 낭비를 최소 절반 이하(추정 15건 내외)로 줄인다. 카운트: threshold=3 적용 시 09-22 하루치 33건 중 트립 이후 억제됐을 실패 건수는 대략 20건(현재 실패 간격이 평균 30~90분으로 재시도 리듬이 짧다는 점에서, 트립 구간마다 최소 2~3건씩 억제).

2순위: analyst-* 5개 레인은 AGENT_INFRA_CB_FALLBACK_MAP에 항목을 추가하지 않고 트립 시 무조건 드롭(재라우팅 없음)으로 처리한다. guardian도 동일하게 드롭. 왜: agent_registry.py 476~498행의 analyst-pm 역할 프롬프트는 "## 입력 우선순위"가 analyst-macro/fundamental/technical의 latest.json을 읽는 것으로 못박혀 있고 "## 금지사항"에 "새로운 원천 데이터를 임의로 만들지 말 것"(495행)이 명시돼 있다. 즉 analyst-pm은 원천 데이터 수집 도구(FRED, yfinance, DART 등)에 대한 역할 권한이 없다 — 라우팅 규칙 위임과 무관하게 애초에 fallback 수신 자격이 없다. codex→cowork 폴백에서 이미 확인된 "대체agent의 도구 목록에 없는 작업을 떠넘기면 다른 gap 코드로 즉시 재실패하는 핑퐁"(2026-09-21 CMD#39594 계열, references/2026-09-21-infra-cb-reroute-bypasses-dedicated-routing-rule.md)과 구조가 완전히 동일하다. guardian도 대칭적으로 처리한다 — 동료 역할이 없고(시스템 헬스체크 전담), 실패해도 데이터 유실이 없어(재확인 주기가 짧음) 드롭이 안전 기본값이다. 실측: guardian 30일 failed=4건(전부 2026-09-05~08, 9일 이상 재발 없음) — 폴백 설계에 투입할 근거 볼륨 자체가 부족하다.

[현황]

agent 30일 failed 30일 total 실패율 직전 24h failed
analyst-macro 368 428+39done+23cancel 86.0% 33
analyst-technical 149 193+23done+22cancel 77.2% 0 (최근 09-20 이후 소강)
analyst-fundamental 35 70+31done+7cancel 50.0% 0 (최근 09-12 이후 소강)
analyst-pm 0 failed 1 cancelled - 0
guardian 4 4+1done+3cancel 50.0% 0 (최근 09-08 이후 소강)
(대조군) codex 262 310 84.5% breaker 이미 적용
  • 조회: sqlite3 -readonly /Users/ron/.hermes/data/ops_multiagent.db "SELECT target_agent, status, COUNT(*) FROM bus_commands_archive WHERE created_at >= datetime('now','-30 days') AND target_agent IN (...) GROUP BY target_agent, status" (조회 2026-09-23 05:05 KST)
  • analyst-macro 실패 사유 분포(09-22 33건 샘플): execution_artifact_path_not_found 계열 다수, missing_verification_command/missing_verification_value 계열 다수 — 2종 gap이 번갈아 반복돼 BUS_CB(해시 시그니처 기반)로는 걸리지 않는 전형적 "문구 분산" 패턴(스킬 Pitfall #7과 동일 구조).
  • analyst-technical 09-19~20 샘플에는 evidence-gate 계열과 llm_infra_failure_retry_deferred(모델 응답 타임아웃)이 섞여 있음 — AGENT_INFRA_CB_확장 시 infra_markers가 이미 두 계열을 모두 포괄(3884~3905행)하므로 별도 마커 추가 없이 커버 가능.
  • AGENT_INFRA_CB_FALLBACK_MAP(3743~3752행) 현재 3항목: codex→cowork, cowork→ron, ron→cowork. analyst-*/guardian 미등록 상태 — tuple만 확장하고 map을 그대로 두면 2404~2406행 else 분기(대체agent 없음, 드롭)로 자동 낙하해 코드 추가 없이 드롭 동작이 확보된다(이것이 2순위 권고를 "map에 항목을 추가하지 않는다"로 정한 이유).

threshold/window/cooldown 기본값 제안 (레인별)

레인 infra-CB threshold/window/cooldown evidence-gate-CB threshold/window/cooldown 근거
analyst-macro 3회/45분/45분 (codex/ron/cowork 현행값 그대로) 3회/30분/15분 (현행값 그대로) 24h 33건·17시간 연쇄가 현행 threshold=3/window=30분 기준으로도 이미 다회 트립될 밀도 — 별도 완화 불필요. 신규 레인이라 우선 현행값으로 시작해 오탐률을 관찰 후 조정(9-06/8-29 히스토리처럼 완화 조정은 사후 데이터 기반으로).
analyst-technical 동일 (3/45/45) 동일 (3/30/15) infra 계열(모델 타임아웃)과 evidence-gate 계열이 혼재하므로 두 게이트 모두 필요. 값 차등 근거 없음 — 우선 codex/ron과 동일 시작점.
analyst-fundamental 동일 (3/45/45) 동일 (3/30/15) 실패율은 50%로 상대적으로 낮으나(35/70) 30일 샘플 자체가 적어 임계 완화는 시기상조. 동일값으로 시작.
analyst-pm 미적용(화이트리스트 제외 유지 권고 재검토 대상 아님) 좌동 30일 failed=0. 트립 이력 자체가 없어 threshold 설계 근거가 없다 — 실패가 실제로 관측되면 그때 편입. 단, 화이트리스트 확장안에는 이름만 넣어두고(향후 실패 발생 시 자동 커버되도록) 별도 튜닝은 보류.
guardian 완화값 권고: 2회/60분/30분 2회/45분/15분 30일 failed=4건뿐이라 표준 threshold=3이면 사실상 트립이 거의 발생하지 않아 게이트가 유명무실해진다. 다만 guardian은 시스템 헬스체크 전담이라 과도한 억제가 모니터링 공백을 만들 위험도 있으므로, threshold를 낮추되(2회) window/cooldown은 표준보다 넉넉히(60분/30분) 잡아 "짧은 폭주만 잡고 정상 재시도는 보존"하는 보수적 절충안으로 제안.

전체 env var는 기존 패턴(ORCH_AGENT_INFRA_CB_THRESHOLD 등)이 전역 단일 값이라 레인별 분리 적용은 코드 구조 변경(agent별 override map 추가)이 필요하다 — 이 제안서는 정책값만 제시하며, 실제 반영 시 "화이트리스트 확장 + 표준값 그대로 재사용"(analyst-fundamental/macro/technical/pm)과 "guardian 전용 override"를 분리 구현할지는 codex 구현 단계에서 결정할 사항으로 남긴다.

[리스크]

  • 구조적 위험: analyst-macro는 CRON_AGENTS(agent_registry.py 175행)에 속해 정기 크론으로 재생성되는 레인이다. breaker가 45분 드롭을 걸어도 다음 크론 사이클에서 동일 제목이 재생성되면 사실상 억제 효과가 짧게 끝날 수 있다 — 크론 주기와 cooldown 값의 상호작용을 반영 전 확인 필요(크론 주기가 45분보다 짧으면 cooldown 무력화).
  • 단일 장애점: 화이트리스트 확장은 create_task() 한 곳(2282행, 2419행)에서만 호출되므로 배포 안전성은 codex/ron과 동일 수준(스킬이 명시한 "put it in create_task(), not in one of its callers" 원칙 준수) — 새로운 단일 장애점을 추가하지 않음.
  • guardian 완화값의 부작용: threshold=2로 낮추면 정상적인 연속 2회 실패(예: 우연한 일시 타임아웃)만으로도 30분간 헬스체크 디스패치가 막힌다 — guardian은 시스템 이상 감지가 본업이라 이 공백이 실제 장애 놓침으로 이어질 수 있음. cooldown을 30분으로 제한(표준 45분보다 짧게)한 것은 이 리스크를 상쇄하기 위한 설계지만, 실제 배포 후 guardian 트립 빈도를 1주일 관찰 후 재조정 필요.
  • analyst-pm 화이트리스트 등재의 의미: 지금 failed=0이라 실질 효과가 없지만, 향후 analyst-pm이 원천 데이터 수집을 시도하다 실패하는 사례가 생기면(예: 오배정) breaker가 그제서야 작동한다 — 근본 원인(오배정) 자체를 막지는 못한다. 라우팅 단계에서 analyst-pm에 원천 데이터 수집형 제목이 가지 않도록 하는 별도 게이트가 이 제안의 범위 밖으로 여전히 필요.
  • fallback 미등록(드롭) 선택의 트레이드오프: 재라우팅 없이 드롭하면 analyst-macro 같은 크론 기반 레인은 해당 사이클의 산출물이 통째로 유실된다(재라우팅 시도조차 안 함). 이는 의도된 선택이지만(2순위 권고 근거 참조), 만약 analyst-macro 실패의 상당수가 진짜 일시적 인프라 문제(모델 타임아웃)라면 드롭보다 "같은 agent에 짧은 재시도"가 나을 수 있다 — 현재 두 breaker 모두 fallback이 없으면 재시도 자체를 안 하므로, 다음 정기 크론까지 완전히 비게 된다. 이 트레이드오프는 검증 단계에서 주간 산출물 완결률로 확인해야 한다.

[검증방법]

  • KPI 1: 화이트리스트 확장 배포 후 7일간 bus_commands_archive에서 analyst-macro/technical/fundamental의 evidence-gate 반복 실패 건수(동일 정규화 제목 계열 3회 초과 연속 발생) 감소율. 기대값: 배포 전 대비 최소 40% 감소(09-22 33건 기준 비교 시 하루 20건 이하로). 검증 명령: sqlite3 -readonly /Users/ron/.hermes/data/ops_multiagent.db "SELECT target_agent, COUNT(*) FROM bus_commands_archive WHERE status='failed' AND target_agent IN ('analyst-macro','analyst-technical','analyst-fundamental') AND created_at >= datetime('now','-7 days') GROUP BY target_agent;"
  • KPI 2: 로그에서 AGENT_INFRA_CB_BLOCKED/AGENT_EVIDENCE_GATE_CB_BLOCKED 라인이 analyst-*/guardian target으로 실제로 찍히는지 확인(현재는 codex/cowork/ron만 찍힘). 기대값: 배포 후 24시간 내 analyst-macro 관련 BLOCKED 로그 최소 1건 이상 발생(현재 17시간 33건 밀도라면 트립 안 되는 게 오히려 이상). 검증 명령: grep -c "AGENT_.*_CB_BLOCKED.*agent=analyst" /Users/ron/.hermes/logs/orchestrator.log (또는 launchd 로그 경로 확인 후 동일 패턴)
  • KPI 3: analyst-macro 크론 정기 산출물(latest.json 갱신 여부)이 breaker 도입 후에도 주간 완결률을 유지하는지 — 위 리스크 "fallback 미등록"이 실제로 산출물 유실을 늘리지 않는지 확인. 검증 명령: ls -la ~/knowledge-agent/*/analyst-macro/latest.json 또는 해당 경로의 mtime을 크론 스케줄(정기 주기)과 대조. 롤백 조건: KPI 3에서 주간 산출물 완결률이 배포 전 대비 하락하면(크론 주기가 cooldown보다 짧아 드롭이 정상 산출까지 막는 경우), guardian과 동일한 완화값(threshold 상향 또는 cooldown 단축)으로 재조정하거나, 화이트리스트 확장을 analyst-macro에 한해 일시 롤백한다.

결론: analyst-fundamental/analyst-macro/analyst-technical/analyst-pm/guardian 5개 레인을 _is_agent_infra_cb_tripped()/_is_agent_evidence_gate_cb_tripped() 화이트리스트에 추가하되(threshold/window/cooldown은 codex/ron과 동일 표준값 재사용, guardian만 2회/60분/30분 완화), AGENT_INFRA_CB_FALLBACK_MAP에는 이 5개 레인을 등록하지 않아 트립 시 재라우팅 없이 드롭(기존 else 분기 그대로 재사용)하는 제안서를 작성했다. 근거: scripts/orchestrator.py _is_agent_infra_cb_tripped()(3859~3871행, 화이트리스트 검사는 3870행) 및 _is_agent_evidence_gate_cb_tripped()(3962~3974행, 화이트리스트 검사는 3973행), AGENT_INFRA_CB_FALLBACK_MAP(3743~3752행, codex/cowork/ron 3항목만 존재) 직접 확인. hermes-orchestrator-circuit-breakers 스킬의 "Pitfall: both agent-scoped breakers ... hardcode their target check to (\"codex\", \"cowork\", \"ron\")" 섹션(analyst-macro 368/428 86.0%, analyst-technical 149/193 77.2%, analyst-fundamental 35/70 50.0% 인용치)과 "analyst-pm ... 입력 우선순위 ... 새로운 원천 데이터를 임의로 만들지 말 것" 인용을 대조해 fallback 비적격 판단의 근거로 사용. scripts/agent_registry.py 476~498행(analyst-pm 역할 프롬프트, 495행 "새로운 원천 데이터를 임의로 만들지 말 것")을 직접 읽어 스킬 인용과 일치함을 재확인(조회 2026-09-23 05:07 KST). 검증: ls -la /Users/ron/knowledge-agent/400-reports/260923_cowork_analyst-guardian-circuit-breaker-coverage-gap-proposal.md → 파일 생성 확인, exit code 0. 근거파일: /Users/ron/knowledge-agent/400-reports/260923_cowork_analyst-guardian-circuit-breaker-coverage-gap-proposal.md