needs_evidence 70건 에이전트·사유별 분류와 재발 방지안
needs_evidence 70건 에이전트·사유별 분류와 재발 방지안
작성: Cowork(다듬) / 조회 2026-10-24 04:41~05:00 KST / 코드·DB·크론 수정 없음(조회 전용, 재기동 미실행)
[권고]
1순위: 실행 중인 워커·서버·오케스트레이터를 재기동해 이미 고쳐 둔 코드를 실제로 올린다. 재기동은 해리 승인 후 ron이 실행한다. - 왜: 프로세스 시작 시각이 파일 수정 시각보다 앞선다. 방금(2026-10-24 04:5x) ps와 stat으로 다시 확인했다. agent_queue_worker.py 워커 7개는 9/29 01:27~02:16 시작(guardian PID 3974는 9/29 02:16), codex PID 39070은 9/29 01:43, server.py PID 15335는 9/28 09:17, orchestrator.py --loop PID 46446은 9/27 07:55 시작이다. 파일 수정은 server.py 10/19 15:06:05, agent_queue_worker.py 10/19 15:06:44, orchestrator.py 10/19 21:01:53이다. 즉 최소 25일, 최대 27일 전 코드로 돌고 있다. - 오케스트레이터 재발행 차단 로그 NEEDS_EVIDENCE_REISSUE_LOOP_BLOCKED는 logs/ 아래 orchestrator 계열 로그 전부 grep -c 0건이다(orchestrator.log 0, orchestrator.launchd.out.log 0, orchestrator.launchd.err.log 0). 게이트 코드는 파일에 있지만 가동 증거가 없다. - 기대효과: 직전 보고서(261023_claude_needs_evidence_69건_상위원인_방지안.md 70행)의 재판정 결과, 현재 파일 코드로는 69건 중 25건(36.2%)이 통과로 바뀐다. 이번 70건 중 69건은 같은 모집단이고 신규 1건(#42454)만 추가다. 나머지 약 44건은 재기동만으로 안 풀려 2·3순위가 필요하다.
2순위: 분석·집계 태스크가 자기 분석 대상 문구 때문에 다시 반려되는 고리를 끊는다(codex 구현 + 표준 문서 1줄 보강). - 왜: 70건 중 57건(81.4%)이 제목에 needs_evidence·반려·failed·원인 분류가 들어간 분석류 태스크다(guardian 49, cowork 8). 라벨 없는 일반 보류 25건은 전부 이 분석류다(25/25). 분석 보고가 "결과 확인 보류", "검증 근거 없음" 같은 하드블록 문구를 서술하다가 걸리고, 그 반려가 다음 집계의 대상이 된다. 반려 건수가 제목에 들어가 47→51→56→64→68→69→70으로 불어나는 것이 그 흔적이다. - 기대효과: 이 계열 신규 유입(id>42103, 10/18 이후 16건 전부 guardian)을 5건 이하로 억제. 하드블록 예외 기준은 직전 보고서 재현으로 25건 중 18건 해소 가능.
3순위: exit code 표기 경직과 guardian 제출 규율 대응(정규식 조사 허용 + guardian 프롬프트 재확인).
- 왜: missing_verification_exit_code 20건(28.6%) 중 직전 분석에서 8건이 "exit code는 0입니다"처럼 조사가 끼어 정규식이 못 읽은 유형이다. 정규식은 server.py 733~736행 _STORAGE_EXIT_CODE_RE와 agent_queue_worker.py 7120행 _CODEX_VERIFICATION_EXIT_CODE_RE에 같은 모양으로 있다.
- 기대효과: 조사형 8건 즉시 해소(전체의 11.4%).
4순위(신규 발견): 반려 시 저장되는 result_note가 원문 220자만 남겨 사후 분류가 불가능한 문제를 고친다.
- 왜: server.py 3088행 raw_excerpt = ...[:220], 3094행 )[:900]. 70건 전부 result_note가 "원본 요약:" 뒤 220자에서 잘려 있어(실측 70/70, 모두 900자 미만) 검증 줄이 실제로 있었는지 DB만으로 알 수 없다. 이 때문에 guardian이 집계할 때마다 "4블록 미비"라고 일괄 결론을 내렸다(예: #41902).
- 기대효과: 원문 전체를 별도 파일 또는 컬럼에 보존하면 사후 재분류 오류 0건화, 집계 태스크 재작업 감소.
[현황]
1. 직접 집계 (sqlite3 -readonly, 조회 2026-10-24 04:41 KST)
- 합계 70건 일치(
SELECT count(*) ... status='needs_evidence'→ 70). 상태 분포: needs_evidence 70, failed 4, done 3, claimed 1. - 기간: id 40276~42454, updated_at 2026-09-28~2026-10-23(25개 날짜, 하루 1~5건). 조회 시각 기준 최근 24시간 안에 갱신된 건은 1건(#42454)뿐이다. 요청서의 "최근 24시간 70건"은 누적 잔량이며 24시간 신규 유입이 아니다.
- 최근 7일(10/17~10/23) 유입: 10/17 5, 10/18 2, 10/19 3, 10/20 4, 10/21 5, 10/22 4, 10/23 2 = 25건. 하루 약 3.6건 꾸준히 쌓인다.
- 에이전트별(claimed_by): guardian 52건(74.3%), cowork 8(11.4%), analyst-macro 5(7.1%), analyst-pm 4(5.7%), ron 1(1.4%). 합 70.
2. 반려 사유별 (result_note의 "차단 사유:" 구간 기준, 상호배타 분류)
| 사유 | 건수 | 비율 | 에이전트 |
|---|---|---|---|
| 라벨 없는 일반 보류(결과 확인 보류/검증 근거 없음) | 25 | 35.7% | guardian 22, cowork 3 |
| missing_verification_exit_code | 20 | 28.6% | guardian 19, cowork 1 |
| missing_result_or_verification | 13 | 18.6% | analyst-macro 5, analyst-pm 4, guardian 3, cowork 1 |
| invalid_verification_exit_code | 9 | 12.9% | guardian 6, cowork 2, ron 1 |
| verification_command_unverifiable | 3 | 4.3% | guardian 2, cowork 1 |
| 합 25+20+13+9+3=70 일치. 한 건에 라벨이 여럿이면 missing_verification_exit_code → invalid_verification_exit_code → missing_result_or_verification → verification_command_unverifiable 순으로 먼저 걸리는 하나에 배정했고, 차단 사유 구간에 라벨이 없으면 라벨 없음으로 뒀다. |
- 한 건에 라벨이 여러 개인 경우(중복 허용 구간 기준): missing_verification_exit_code 20, missing_result_or_verification 13, invalid_verification_exit_code 9, missing_verification_command 6, completion_result_note_forces_rework 4, verification_command_unverifiable 3, missing_execution_artifact 3, execution_artifact_path_not_found 3. 라벨 2개 이상 10건(2개 4건, 3개 6건).
- 요청서가 예로 든 라벨의 구간 기준 건수: missing_source_log_path 0, missing_verification_value 0, missing_original_verification 0, missing_execution_value 0, execution_artifact_path_not_found 3. 결과 노트 전체 문자열 검색으로는 missing_source_log_path 2, execution_artifact_path_not_found 4가 잡히지만 서술 속에 단어만 나온 건이 섞여 있어 사유로 세지 않았다. 상위 3개 사유에는 해당 없음.
3. 상위 3개 사유별 실제 사례 (result_note 원문 한 줄, DB 원문 그대로)
사유 A. 라벨 없는 일반 보류 25건
- CMD#41902(guardian, "needs_evidence 47건 원인별 분류"): 근거: 결과물과 검증 근거가 없음. 차단 사유: 검증 근거 없음, 결과물과 검증 근거가 없음, 결과 확인 보류. 보완 필요: 결과물 경로, 원문 확인, 검증 명령·결과.
- CMD#42310(guardian, "needs_evidence 64건 적체 원인별 분류"): 같은 차단 사유 문장. 원본 요약 첫머리가 "needs_evidence 64건과 failed 4건, 합계 68건을 에이전트별·반려 라벨별로 집계했고 코드는 수정하지 않았다"로, 정상 보고처럼 보이나 서술에 하드블록 문구가 들어 있다.
사유 B. missing_verification_exit_code 20건
- CMD#40346(guardian, "옛 경로 mcp_health_server.py·stealth-browser 중복 기동 조회"): 근거: 결과물과 검증 근거가 없음. 차단 사유: missing_verification_exit_code. 원본 요약에는 산출물 경로(guardian_legacy_mcp_dup_20260929.md)가 있었는데도 exit code만 막혔다.
- CMD#40854(guardian, "needs_evidence 9건·failed 3건 반려 사유 분류"): 같은 차단 사유. 원본 요약이 "12건 모두 4블록 미비·검증 증거 부족으로 막힌 제출 규율 문제"라고 스스로 쓴 건인데, 정작 그 보고 자체가 exit code 누락으로 반려됐다.
사유 C. missing_result_or_verification 13건
- CMD#40408(analyst-macro, "미국 IG 등급별 OAS 격차 산출"): 차단 사유: missing_result_or_verification. 원본 요약 첫 줄은 "us-ig-weekly-latest.json을 직접 파싱해 AAA/AA/A/BBB OAS와 BBB-AA(39bp)... 격차를 계산했다"로 수치와 파일이 있다.
- CMD#41769(analyst-macro, "미국 IG·HY OAS 최신값 및 5영업일 변화 판독"): 같은 사유. 원본 요약 "BAMLC0A0CM과 BAMLH0A0HYM2의 최신값... JSON 파일에서 직접 계산해 3줄 요약까지 마쳤습니다".
4. 원인 구분: 4블록 미준수 vs llm_infra_failure 계열 vs 게이트 쪽 문제
- llm_infra_failure 계열이 실제 차단 사유인 건: 0건/70건. "차단 사유:" 구간에 infra 문자열이 있는 건 0개. 결과 노트 전체 문자열에
llm_infra가 들어간 17건은 모두 guardian이 "llm_infra_failure는 0건"이라고 서술한 문장이다(예: #40842 "llm_infra_failure는 0건이고 8건 전부 완료 보고 4블록 미비"). 이 17이라는 숫자를 반려 사유로 인용하면 오해다. 직전 보고서(261023, 43행)도 같은 결론이다. - 에이전트 제출 규율 문제(4블록 라벨 또는 검증 줄 누락·불량이 실제로 확인되는 건): 직전 보고서의 원문 복원 재판정 기준으로 exit code 계열 29건 중 약 12건(검증 줄 밖에만 있거나 표기 전무 4건, 조사형·기타 포함 시 정규식 문제와 겹침)이 해당한다. 이번 조회로 새로 확정한 숫자는 아니며 직전 분석에서 가져온 값이다(미재검증).
- 게이트(정규식·하드블록) 쪽 문제: 라벨 없는 일반 보류 25건 중 18건은 현재 코드로도 재차단(직전 보고서 52행), 조사형 exit code 약 8건. 이쪽이 "규칙 공백"에 해당한다.
- 코드 미반영(프로세스가 옛 코드): 현재 코드로는 통과하지만 실행 중 프로세스에는 반영되지 않은 건 25건(직전 재판정).
- analyst 9건(macro 5, pm 4): 10/17 #41900 이후 신규 0건. 현재 id>41900 구간 analyst 반려는 0건이다(
SELECT count(*) FROM bus_commands WHERE status='needs_evidence' AND claimed_by LIKE 'analyst%' AND id>41900→ 0, 이번 70건 목록에서 id 41900 초과 analyst 항목 없음). 당시 어느 게이트가 막았는지는 미확인. - 한계: 위 "미재검증" 비중은 직전 보고서의 게이트 재현 결과를 인용한 것이다. 이번 작업에서는 게이트 함수를 새로 돌리지 않았다. 70건 중 #42454만 신규이고 내용은 guardian의 7일 반려 분류 보고(invalid_verification_exit_code 사유)다.
[리스크]
- 재기동 리스크: 5개 이상 워커와 server.py(3344), orchestrator 재기동은 진행 중 태스크를 끊는다. 해리 승인과 idle 시점 확인이 필요하다. 이번 작업자는 재기동을 실행하지 않았다.
- 단일 장애점·중복: 같은 정규식·하드블록 계열이 agent_queue_worker.py, server.py, shared/public_result_formatter.py 세 곳에 중복돼 있어 한 곳만 고치면 다시 갈라진다.
- 자기참조 적체: needs_evidence에서 나갈 경로가 없어 70건이 누적되고, 집계 태스크가 그 건수를 제목에 넣어 재발행한다. 유사도 0.9 기준(orchestrator.py 4091행 REISSUE_LOOP_SIMILARITY)은 분석 보고처럼 본문이 매번 달라지는 계열에는 작동하지 않는다.
- 하드블록 완화는 가짜 완료 통과 위험이 있다. "구체 근거 앵커 2개 이상 + 검증 줄에 실행 명령과 exit code 0" 조건은 유지해야 한다.
- 정확도 위험: 220자 잘림(server.py 3088행)으로 사후 집계가 본문 서술(예: "4블록 미비")을 그대로 믿게 된다. 집계 간 건수와 분류가 흔들리는 원인이다.
- 미확인: analyst 9건의 당시 차단 주체, 재기동 후 압축 경로 8건 해소 여부.
[검증방법]
KPI(재기동·보강 후 72시간):
1. 신규 유입: 기준선 최근 7일 25건(하루 3.6건) → 72시간 5건 이하. 명령: sqlite3 -readonly /Users/ron/.hermes/data/ops_multiagent.db "SELECT count(*) FROM bus_commands WHERE status='needs_evidence' AND id>42503" 기대값 5 이하.
2. 가동 확인: ps -o lstart= -p <PID> 시작 시각이 stat -f '%Sm' scripts/orchestrator.py 시각(10/19 21:01:53)보다 늦어야 한다. 재기동 후 logs/orchestrator.log에서 NEEDS_EVIDENCE_REISSUE_LOOP_BLOCKED가 1건 이상 나오는지 확인.
3. 재현 테스트: 분석류 원문(41902, 42165, 42171, 42264, 42310, 42412)과 조사형 exit code 원문 8건을 server.py _completion_storage_block_reasons로 재판정 → 14건 중 12건 이상 통과 기대.
4. 합계 정합: 사유별 합 = 전체 건수(현재 70)를 매번 SQL로 대조. "llm_infra" 문자열 검색 건수는 사유가 아니라 서술이므로 차단 사유 구간만 센다.
롤백 조건: 가짜 완료(경로·명령 허구)가 done으로 저장되는 사례가 1건이라도 나오면 예외를 즉시 되돌린다. 재기동 후 워커 기동 실패 시 이전 plist로 복구.
코드 수정 후보 (직접 수정하지 않음, codex 위임용 — 모든 경로·함수 실존 확인)
- scripts/server.py
close_bus_command(3038행 정의, 반려 문구 조립 3088~3094행):[:220]잘림 제거 또는 원문 전체를 별도 보존 위치에 기록(4순위). - scripts/server.py
_COMPLETION_STORAGE_HARD_BLOCK_PATTERNS(687행),_completion_storage_block_reasons(854행): 분석류 보고에서 하드블록 문구가 "라벨 열거" 문맥으로 쓰인 경우 면제(구체 근거 앵커 2개 이상 + exit code 0 조건 유지). - scripts/shared/public_result_formatter.py
strip_quoted_citations(3588행),completion_result_note_forces_rework(3602행): 위 예외와 동일 기준을 canonical에 반영. - scripts/server.py
_STORAGE_EXIT_CODE_RE(733행), scripts/agent_queue_worker.py_CODEX_VERIFICATION_EXIT_CODE_RE(7120행): "exit code는 0" 같은 조사 허용. 단 식별자missing_verification_exit_code 8건을 종료 코드로 오인하는 기존 왼쪽 경계는 유지. - scripts/orchestrator.py
_is_needs_evidence_reissue_loop_tripped(4330행),REISSUE_LOOP_SIMILARITY(4091행): 본문 유사도 대신 "제목 계열 + 최근 반려 건수" 기준 추가. - config/agent_completion_submission_standard.md 121행 부근("결과 확인 보류를 다시 결과로 제출하지 않는다"): 분석 대상 라벨은 snake_case 코드명으로만 쓰고 한국어 하드블록 문구를 서술에 옮기지 말 것, 검증 줄에 "exit code 0" 리터럴 예시 추가(문서 수정은 cowork 가능).
완료 보고 4블록 결론: 최근 needs_evidence 70건(id 40276~42454)을 sqlite3 -readonly로 조회해 에이전트별(guardian 52, cowork 8, analyst-macro 5, analyst-pm 4, ron 1)·사유별(라벨 없음 25, missing_verification_exit_code 20, missing_result_or_verification 13, invalid_verification_exit_code 9, verification_command_unverifiable 3)로 집계하고 llm_infra_failure 차단 사유가 0건임을 확인해 이 문서에 정리했다.