virtual-insanity
← 리포트 목록

needs_evidence 37건 반려 사유·에이전트별 분류와 재발 방지안 (guardian #41515 실패 대체)

2026-10-12 hermes [needs_evidence, completion-gate, cowork, triage, 제안서]

needs_evidence 37건 반려 사유·에이전트별 분류와 재발 방지안

조회: 2026-10-12 13:36~13:45 KST, sqlite3 -readonly /Users/ron/.hermes/data/ops_multiagent.db와 logs/completion_evidence_blocked.jsonl(37건 전부 id 매칭, surface는 모두 server.close_bus_command). 코드·DB·크론은 수정하지 않았다.

0. 먼저 알아둘 정정

  • 태스크 제목은 "최근 24시간 37건"이지만, status='needs_evidence' 전체가 37건이고 id 40276~41504, 생성일은 2026-09-28~10-12(14일)에 걸쳐 있다. 실제 최근 24시간(created_at >= 10-11 13:36)은 6건(41435, 41485, 41494, 41495, 41498, 41504)이다. 이하 집계는 37건 전체 기준이며 6건은 별도 표기한다.
  • guardian #41515가 failed로 끝난 직접 원인: 그 result_note의 차단 사유가 verification_command_unverifiable과 execution_artifact_path_not_found:/Users/ron/.hermes/workspace/shared/fred_client.py였다. 이 경로는 실존하지 않는다(ls → No such file). 실존 파일은 scripts/shared/fred_client.py다. 즉 인용 경로 오타성 증거 실패다.

[권고]

1순위 (codex 위임, 코드): 서버 저장 게이트의 exit code 정규식이 라벨 이름 속 exit_code를 종료코드로 읽는 문제를 고친다. scripts/server.py:733-736 _STORAGE_EXIT_CODE_RE와 scripts/agent_queue_worker.py:7030 _CODEX_VERIFICATION_EXIT_CODE_RE에 앞쪽 단어 경계((?<![A-Za-z0-9_]))를 추가한다. 근거: 'missing_verification_exit_code 15건' → exit_code 15로 매치됨을 직접 실행으로 확인했다. 기대효과: 집계·분류 보고서가 자기 반려 라벨을 설명하다 걸리는 invalid_verification_exit_code 7건(18.9%) 중 분류형 재발 차단.

2순위 (codex 위임, 문구): scripts/orchestrator.py:812의 검증 예시 → exit 0을 → exit code 0으로 바꾼다. 근거: 'python3 scripts/health_check.py → exit 0'은 게이트 정규식에 매치 None(직접 실행). 같은 줄이 guardian 점검 태스크 body에 주입되고, 같은 점검형 guardian 건들이 missing_verification_exit_code로 반려됐다(40276, 40346, 40633, 40994, 41323). 기대효과: 점검·헬스형 반려 재발 차단.

3순위 (운영, ron/orchestrator): "needs_evidence N건 집계·분류" 메타 태스크의 자동 재발행을 1건으로 합친다. 25건/37건(67.6%)이 이 유형이고 전부 반려됐다. 건수가 늘 때마다(32→33→…→37) 새 태스크가 발행되고, 새 태스크가 다시 반려 목록을 늘려 자기증식한다.

4순위 (codex 위임, 관측성): 반려 시 원본 result_note를 보존한다. 현재 bus_commands.result_note는 "결과 확인 보류" 템플릿으로 덮이고 jsonl note_preview는 약 240자에서 잘린다. 이 때문에 6건(analyst-pm/macro)은 어느 줄이 빠졌는지 확정할 수 없다. 기대효과: 다음 분류부터 건별 확정 가능.

[현황]

1. 반려 라벨별 건수 (jsonl reasons 기준, 한 건에 라벨 여러 개 가능)

라벨 건수
missing_verification_exit_code 11
결과 확인 보류 (일반 템플릿) 11
invalid_verification_exit_code 7
missing_result_or_verification 7
검증 근거 없음 5
결과물과 검증 근거가 없음 5
missing_verification_command 3
missing_execution_artifact 2
verification_command_unverifiable 1
completion_result_note_forces_rework 1
execution_artifact_path_not_found (jobs.json) 1
missing_source / missing_execution_value / missing_verification_value / missing_source_log_path 0
llm_infra_failure 계열 0

llm_infra_failure가 차단 라벨인 건은 37건 중 0건이다(jsonl 37건 전수 확인). 전부 증거 게이트 반려이며 인프라 지연이 아니다. 단 앞선 guardian 보고(#41485 등)가 llm_infra_failure를 5건으로 센 것은 jsonl 라벨과 맞지 않는다. 원인은 확정하지 못했다.

2. 에이전트별 건수

에이전트 건수 비율
guardian 26 70.3%
cowork 4 10.8%
analyst-pm 4 10.8%
analyst-macro 2 5.4%
ron 1 2.7%
합계 37 100%

3. 에이전트 × 대표 사유 (건당 1개, 배타)

사유 guardian cowork pm macro ron 합
missing_verification_exit_code 단독 (40276,40346,40633,40854,40902,40994,41274,41498) 8 0 0 0 0 8
invalid_verification_exit_code (40869,41295,41377,41385,41420 / 41348 / 40297) 5 1 0 0 1 7
일반 "결과 확인 보류" 템플릿 (40825,41101,41151,41233,41316,41387,41435,41485,41494,41504 / 41495) 10 1 0 0 0 11
산출물·검증명령·exit code 3중 누락 (40842,41431,41323) 3 0 0 0 0 3
missing_result_or_verification (40874,40960,41035,41067 / 40408,40518) 0 0 4 2 0 6
verification_command_unverifiable (40691) / forces_rework (40954) 0 2 0 0 0 2
합계 26 4 4 2 1 37

최근 24시간 6건: guardian 5(41435, 41485, 41494, 41498, 41504) + cowork 1(41495). 전부 "결과 확인 보류" 또는 exit code 계열이다.

상위 3개 패턴 (제목 유형 기준)

패턴 A. 반려·needs_evidence 집계/분류/방지안 메타 태스크 — 25건 (67.6%, guardian 21 + cowork 4)

  • 라벨: exit code 계열과 일반 "결과 확인 보류"가 대부분이다(40842·41431은 산출물·명령·exit code 3중 누락으로 패턴 B와 겹쳐 여기에 포함).
  • 구분: 4블록 미준수 + 게이트 오탐 혼합이다. 인프라 지연은 0건.
  • 근거 1(오탐, 코드): 보고서가 라벨 이름을 설명하면 missing_verification_exit_code 15건이 exit_code 15로 읽힌다(직접 실행). _completion_block_reasons의 확인 보류 패턴(scripts/agent_queue_worker.py:4005)도 인용된 라벨 문구를 잡는다는 재현이 261012_claude_guardian_needs_evidence_4block_cause.md에 있다(그 재현은 이번에 재실행하지 않았고 인용이다).
  • 근거 2(지시문): config/agent_completion_submission_standard.md:187-195는 exit=0만 금지하고 exit 0·종료코드 0·라벨 뒤 숫자는 다루지 않는다.
  • 상세 방지안은 261012_claude_needs_evidence_exitcode_방지안.md에 이미 있어 여기서는 반복하지 않는다.

패턴 B. 헬스·점검·실행형 guardian/ron 태스크 — 6건 (16.2%, 패턴 A와 중복 없이 분리)

  • 건: 40276(워커 패치 반영 확인), 40346(옛 경로 프로세스 조회), 40633·40994(지식사랑방 실패 원인 분류), 41323(크론 사전점검), ron 40297(ETF 예열). A+B+C = 25+6+6 = 37.
  • 라벨: missing_verification_exit_code 중심(ron 40297만 invalid). 41323은 workspace/jobs.json 인용인데 실존하지 않는다(ls → No such file, 실제 크론 장부는 /Users/ron/.hermes/cron/jobs.json).
  • 구분: 지시문·프롬프트 문제가 주원인. scripts/orchestrator.py:812가 → exit 0을 권장하고(게이트는 exit code N만 인정), guardian 프롬프트(scripts/agent_registry.py:333)는 exit code <숫자>를 안내하지만 body 쪽 예시와 충돌한다. ron 40297은 대상 스크립트 실패(exit code 1)를 보고하면서 그 종료값이 검증 값으로 읽힌 케이스(invalid)이며 run-cycle·헬스체크 핸들러가 아니라 LLM 작성 보고다.

패턴 C. 미국 IG/HY OAS 분석 (analyst-pm 4 + analyst-macro 2) — 6건 (16.2%)

  • 라벨: 전부 missing_result_or_verification (scripts/server.py:887, completion_report_has_result_and_verification 실패).
  • 구분: 4블록 미준수 추정(검증 줄 부재). 확정은 못 했다: 원본이 템플릿으로 덮이고 note_preview가 "결론/근거"까지만 남아 검증 줄 유무를 볼 수 없다.
  • 간접 근거: 같은 유형 #41512(analyst-macro, 10-12 12:25)는 검증: python3 /tmp/oas_calc.py → … exit code 0, 통과와 근거파일: 줄을 갖춰 done이다. 마지막 반려는 #41067(10-07 05:45)이고 그 뒤 pm/macro 반려는 없다. 이미 해소된 패턴일 가능성이 높다.
  • 별도 위험: #41512의 "다음 행동"이 명령을 반복해 적었을 뿐 조치가 아니다. 반려는 안 됐지만 형식 충족용 문장이다.

2026-09-06 run-cycle/헬스체크 4블록 패치와의 겹침

겹침 0건. 그 패치는 agent_queue_worker.py의 ron 결정적 핸들러(run-cycle 성공/실패, 헬스체크 성공/실패 4곳) 반환문이었다(AGENTS.md v6 절). 이번 37건은 ron 1건(#40297, ETF 예열, run-cycle 아님)을 빼면 모두 LLM이 쓴 보고이고, 핸들러 반환문에서 나온 건이 아니다. 헬스·점검형 guardian 건(40276, 40346, 41323)은 제목이 점검이어도 핸들러가 아니라 guardian LLM 보고다. 따라서 제외 표시 대상은 없고, "패치 미반영" 가설은 이번 자료로 지지되지 않는다.

codex 위임용 제안 (코드는 수정하지 않음)

# 파일·함수 재현 근거 제안
C1 scripts/server.py:733-736 _STORAGE_EXIT_CODE_RE, scripts/agent_queue_worker.py:7030 _CODEX_VERIFICATION_EXIT_CODE_RE 'missing_verification_exit_code 15건' → code=15 (이번 세션 직접 실행) 앞쪽에 (?<![A-Za-z0-9_]) 추가, 라벨 토큰 선제거
C2 scripts/agent_queue_worker.py:3995 _completion_block_reasons (패턴 4005행) 인용된 라벨 문구가 반려 사유가 됨 (261012_claude_guardian_needs_evidence_4block_cause.md 재현 인용, 미재실행) 백틱·인용부호·"라벨 N건" 문맥은 스캔 제외
C3 scripts/orchestrator.py:812 grep -n "exit 0" → 812행 → exit 0, 정규식 매치 None exit code 0으로 교체
C4 반려 라우팅 (server.close_bus_command → jsonl 기록부) note_preview가 약 240자에서 잘림(#40518, #41067 확인) 원본 전문을 별도 보존
C5 guardian #41515류 인용 경로 workspace/shared/fred_client.py 부재, 실제 scripts/shared/fred_client.py 증거 경로 인용 전 ls 검증을 guardian 프롬프트에 명시

[리스크]

  • 단일 장애점: 서버 저장 게이트(server.close_bus_command)가 37건 전부의 반려 지점이다. 정규식 하나의 오독이 에이전트 5종 모두에 영향을 준다.
  • 자기증식: 분류 태스크가 반려되면 다음 분류 태스크가 발행되어 건수가 늘고, 그 건수 자체가 새 분류 대상이 된다. 이 시점에도 41515(failed)·41516 이후 신규 발행이 이어질 수 있다.
  • 분석 한계: 원본 result_note 소실로 패턴 C와 일부 일반 보류 건의 원인은 추정이다.
  • 이번 세션이 직접 확인하지 못한 것: C2 재현, guardian #41485의 llm_infra_failure 5건 집계 근거.

[검증방법]

  • 지표: needs_evidence 신규 발생 건수/일, exit code 계열 비율(현재 18/37=48.6%), 메타 집계 태스크 반려율(현재 25/25).
  • 명령: sqlite3 -readonly /Users/ron/.hermes/data/ops_multiagent.db "select claimed_by,count(*) from bus_commands where status='needs_evidence' and created_at>=datetime('now','localtime','-24 hours') group by 1"
  • 기대값: C1·C3 반영 후 24시간 내 exit code 계열 신규 반려 0건, 메타 집계 태스크 1건 이하.
  • 롤백 조건: C1 적용 후 정상 노트가 새로 반려되거나 pytest 회귀가 나오면 정규식 변경을 되돌린다.