needs_evidence 81건 상위 반려 라벨별 재발 방지안 (정책 문구 초안 + codex 위임 제안)
needs_evidence 81건 상위 반려 라벨별 재발 방지안
- 조회: 2026-10-27 11:59~12:20 KST,
sqlite3 -readonly /Users/ron/.hermes/data/ops_multiagent.db - 변경 없음: 상태 변경·삭제 없이 조회와 제안만 했다.
- 집계 재수행 안 함: guardian #42821(done, 10:03)이 만든 에이전트별·라벨별 집계를 쓰고, 아래는 분포 재확인 1회와 대표 CMD 원문 대조만 했다.
- 이미 있는 같은 날 문서(중복 방지용):
261027_hermes_needs_evidence_prevention.md(128줄),261027_claude_needs_evidence_backlog_policy.md(100줄). 이 문서는 두 문서에 없는 부분(규정 대조 결과, 정책 문구 초안, codex 위임)만 담는다.
1. 결론
- 81건 전부
requested_by=orchestrator가 발행한 태스크다. 반려 사유는 4블록 미비(missing_*, exit code, 경로) 계열이다. 차단 사유 필드에 인프라 지연(llm_infra_failure*)이 있는 건은 0건이다. - 가장 큰 덩어리는 두 가지다. (가) 구체 라벨 없이 "결과 확인 보류"로만 덮인 건 33건, (나) exit code 계열(
missing_verification_exit_code23 +invalid_verification_exit_code10) 33건. 겹치는 건이 있어 합이 81을 넘는다. - 기존 규정은 대부분 이미 있다. 규정이 비어 있는 곳은 아래 4가지뿐이다: ① 집계·방지안 작성 태스크의 자기순환, ② 읽기 전용 조회 태스크의 exit code 표기, ③ 경로 뒤에
1006~1015행처럼 공백+설명을 붙이는 표기, ④ 분석가 계열(missing_result_or_verification10건) 규정이 실제 프롬프트에 안 닿는 문제.
2. 현재 분포 (직접 실행)
명령: sqlite3 -readonly ops_multiagent.db "SELECT claimed_by, COUNT(*) FROM bus_commands WHERE status='needs_evidence' GROUP BY claimed_by ORDER BY 2 DESC"
| 에이전트 | 건수 |
|---|---|
| guardian | 58 |
| cowork | 12 |
| analyst-macro | 6 |
| analyst-pm | 4 |
| ron | 1 |
| 합계 | 81 (guardian 집계와 일치) |
차단 사유 필드("차단 사유:"~"보완 필요" 사이) 기준 라벨 수(한 건에 여러 개 가능): 결과 확인 보류 33, 검증 근거 없음 18, missing_verification_exit_code 23, invalid_verification_exit_code 10, missing_verification_command 9, execution_artifact_path_not_found 5, missing_execution_artifact 4, llm_infra 0.
주의: result_note 본문 전체에서 llm_infra를 LIKE로 세면 20건이 나온다. 이 20건은 "인프라 지연 0건"이라는 설명 문장이 본문에 들어 있어서 잡힌 것이다. 차단 사유 필드로만 세면 0건이다.
3. 대표 CMD 원문 대조 (상위 2개 에이전트 × 2건)
반려 유형 구분: missing_*(4블록 미비) vs llm_infra_failure*(인프라 지연). 4건 모두 4블록 미비 쪽이고 인프라 지연은 아니다.
| CMD | 에이전트 | 제목 | 차단 사유 필드 | 판정 |
|---|---|---|---|---|
| 42798 | guardian | needs_evidence 80건 반려 사유별·에이전트별 분포 실측 분류 | 검증 근거 없음, 결과물과 검증 근거가 없음, 결과 확인 보류 | 4블록 미비. 원본 요약이 "결론: …에서 80건 중 인프라 지연 0건"이라고 적었는데 본문이 근거 줄 중간에서 잘림 |
| 42694 | guardian | needs_evidence 반려 75건 라벨·에이전트별 집계 재실행 | missing_execution_artifact, missing_verification_command, missing_verification_exit_code | 4블록 미비. "새 파일 1개에 저장했다"고 했지만 파일 경로가 근거 줄에 안 보임 |
| 42778 | cowork | 상태 메시지에 '근거 섹션 미기재' placeholder 코드 경로 수정 | execution_artifact_path_not_found:/Users/ron/.hermes/workspace/scripts/server.py 1006~1015행, …public_result_formatter.py 417~422행, missing_verification_command, missing_verification_exit_code | 경로 표기 문제. 파일은 실존하는데 경로 뒤에 공백+1006~1015행을 붙여 게이트가 그 전체를 경로로 읽음 |
| 42762 | cowork | needs_evidence 76건 누적 해소 정책안 | execution_artifact_path_not_found:/Users/ron/.hermes/workspace/261026_cowork_needs_evidence_76_resolution_policy.md, missing_verification_command, missing_verification_exit_code | 산출물 md를 워크스페이스 루트 경로로 적었으나 실제 파일은 /Users/ron/knowledge-agent/400-reports/261026_cowork_needs_evidence_76_resolution_policy.md에 있다(find 확인, 워크스페이스 루트에는 ls 결과 No such file). 저장 위치와 인용 경로 불일치 |
공통 관찰: 저장된 result_note의 길이가 전체 81건에서 359~621자(평균 392자)다. 에이전트가 길게 쓴 본문이 "원본 요약"에서 잘려 4블록 뒷부분(검증, 근거파일)이 저장본에 안 남는다. 게이트가 잘린 텍스트로 판정하는지는 미확인이다.
추가로 본 3건(분포 확인용): analyst-macro #42671·#41900은 missing_result_or_verification, ron #40297은 invalid_verification_exit_code(본문이 실패한 스크립트의 "exit code 1"을 보고하는 내용).
4. 기존 규정과 대조 (규정 있음 / 없음)
| 반려 라벨 | 기존 규정 (파일:줄) | 있음/없음 |
|---|---|---|
| 결과 확인 보류 | agent_completion_submission_standard.md:121 "결과 확인 보류"를 다시 결과로 제출하지 않는다, 3-1절 4줄 틀(124~127) |
있음. 단 "보류 사유 라벨을 못 보게 하는 쪽"은 코드 문제 → 6절 |
| missing_verification_exit_code / invalid_verification_exit_code | standard:176~195 (부정형 grep 명령 ! grep -rlq …; echo "exit code $?", exit=0 표기 불가), :245 표 |
있음. 단 grep 부재확인만 다룸. sqlite3 SELECT 조회·집계 태스크의 exit code 표기는 없음 → 5-②. "실패한 대상 스크립트의 exit code 1을 보고하는 태스크"(ron #40297)도 없음 → 5-② |
| execution_artifact_path_not_found | standard:243·248, 9-9절(1006~1036) ls -la 실존 확인 후 인용, 8-2절(361~) |
있음. 단 경로 + 공백 + N행 표기 금지는 없음(standard:115는 <경로>:<줄번호>만 규정) → 5-③ |
| missing_verification_command | standard:14~16 (0절 1번), 130~157 리터럴 토큰 예시 | 있음 |
| missing_result_or_verification (analyst-macro 6·analyst-pm 4) | standard:550~568, 9-4(624~887) analyst 4종 예시. completion_evidence_policy.md:273 | 규정은 있음. 프롬프트 배선은 약함: scripts/analyst_macro_prompt.md 근거파일: 2줄·결론: 1줄, analyst_pm_prompt.md 각 2줄. 9-3 문서가 지적한 "완료보고 형식을 안내하는 지시"가 있는지 이번에 내용은 확인 못 함 → 5-④ |
| 집계·방지안 작성 태스크의 자기순환 | grep 결과: standard에 집계 태스크 재발행 금지 조항 없음. 같은 날 261027_hermes_... 5-4절이 제안만 함(규정화 안 됨) |
없음 → 5-① |
| llm_infra_failure | standard:1038~1097 (10절, 지시문 불변 재발행, 45분 쿨다운) | 있음. 현재 0건이라 신규 작업 없음 |
5. 규정이 없는 부분의 정책 문구 초안 (비코딩)
아래는 agent_completion_submission_standard.md에 붙일 문구 초안이다. 이 문서에서는 표준 문서를 수정하지 않는다(요청 범위 밖).
① 집계·방지안 작성 태스크의 자기순환 (guardian 52/58, cowork 11/12가 제목에 needs_evidence·반려·4블록 포함)
초안: 제목에 needs_evidence, 반려, 4블록이 들어 있는 집계·분류·방지안 태스크를 받으면 다음 순서로 한다.
1. bus_commands에서 같은 계열의 최근 24시간 내 done 건(예: #42821)이 있는지 먼저 조회한다.
2. 있으면 새 집계를 하지 않고, 그 결과 md 경로를 근거 줄에 쓰고 건수 차이만 갱신해 마감한다. 새 건수는 SELECT COUNT(*) 한 번으로 확인한다.
3. 새로 파일을 저장했다면 그 파일의 ls -l·wc -l 결과를 검증 줄에 쓰고, 저장 경로를 "근거파일:"에 쓴다(저장 위치와 인용 경로가 다르면 execution_artifact_path_not_found).
② 읽기 전용 조회·집계 태스크의 검증 줄
초안: sqlite3 조회·집계 태스크의 "검증:" 줄은 검증: <실행한 sqlite3 명령> → <N행 반환>, exit code 0 한 줄에 쓴다. 결과 파일을 저장한 경우 ls -l <경로>와 wc -l <경로> 결과를 같은 줄이나 바로 다음 줄에 쓰고 끝에 exit code 0을 붙인다. 조사 대상 스크립트가 실패한 상태를 보고하는 태스크는 "검증:" 줄에는 이 보고서를 확인하는 명령의 exit code만 쓰고, 대상 스크립트의 실패 종료값은 "결론:"·"근거:" 줄에 "실패(종료값 1)"처럼 풀어 쓴다. (게이트가 "검증:" 줄의 첫 exit code N을 읽는 방식 → scripts/server.py:733, 818~840. 이 표기가 실제로 통과하는지는 실행 시험 안 함: 미확인.)
③ 경로 표기
초안: "근거:"·"근거파일:"·"검증:"에 경로를 쓸 때는 <절대경로>:<줄번호>만 쓴다. 경로 바로 뒤에 공백·한글·N행·N~M행을 붙이지 않는다. 줄 범위는 경로 뒤가 아니라 인용 문장 안에 쓴다. 예: /Users/ron/.hermes/workspace/scripts/server.py:1006 "…원문 1줄…"(올바름), …/server.py 1006~1015행(게이트가 이 전체를 경로로 읽어 execution_artifact_path_not_found).
④ 분석가 계열 missing_result_or_verification (10건)
초안: analyst-macro·analyst-pm의 완료 제출 맨 앞에는 4블록 4줄을 먼저 두고, 긴 설명은 그 뒤에 붙인다. 파일 기반 조회 태스크(예: BAMLC0A0CM.json)는 standard 9-4 신설 조항 5의 예시처럼 "검증:" 줄에 실행 명령, 결과 수치, exit code 0을 한 줄로 쓴다. 지시문 쪽 보강(두 분석가 프롬프트에 4줄 제출 틀을 최상단에 두는 일)은 6절 codex 위임으로 넘긴다.
6. 코드 수정이 필요한 항목 (직접 수정하지 않음, codex 위임 제안)
| # | 대상 파일·함수 | 요지 | 검증 명령 |
|---|---|---|---|
| C1 | scripts/orchestrator.py _is_needs_evidence_reissue_loop_tripped()(4330행 부근)와 이를 호출하는 create_task()(2544~2550행) |
2026-10-19 재발행 루프 차단 게이트가 있는데도 42821(10:03)→42824(11:12)→42826(11:28)→42827(11:43)→42829(11:58)가 15분 간격으로 발행됐다. 서로 다른 에이전트(guardian→cowork→cowork→ron→이 건)로 발행돼 같은 (agent, 제목 계열) 조건에 안 걸린 것으로 보이나 미확인. 에이전트와 무관하게 "제목 계열 + 최근 24시간 내 done 존재"면 발행하지 않는 조건 추가 검토 | python3 -m pytest tests/test_orchestrator_needs_evidence_reissue_loop.py -q(workspace 루트에서 실행, 파일 실존 확인함) → N passed, exit code 0; 사후: sqlite3 -readonly …ops_multiagent.db "SELECT COUNT(*) FROM bus_commands WHERE title LIKE '%needs_evidence%' AND created_at>=datetime('now','-24 hours','localtime')" |
| C2 | scripts/server.py 경로 추출부(_completion_storage_artifact_paths, 740행 부근)와 _STORAGE_REPORTED_PATH_CLEAN_RE(729행) |
경로 뒤 공백+1006~1015행이 경로로 흡수된다. 경로 끝 경계에서 공백 뒤 텍스트를 잘라내거나, 최소한 실존하는 앞부분 경로로 재시도하게 한다 |
python3 -c 단위 시험: 입력 …/scripts/server.py 1006~1015행 → 추출 경로가 …/scripts/server.py, exit code 0 |
| C3 | scripts/shared/public_result_formatter.py의 "결과 확인 보류" 덮어쓰기 부분(차단 사유가 구체 라벨 없이 "결과 확인 보류"만 남는 33건) |
구체 gap 코드를 result_note에 항상 남긴다. 사건 건수 중 15건은 구체 라벨이 없어 원인 분류가 어렵다(261027_hermes_... 6절과 동일 지적) |
grep -n "결과 확인 보류" scripts/shared/public_result_formatter.py → 줄 번호 확인 후 수정; 시험: 반려 시 result_note에 gap 코드 포함 여부 pytest |
| C4 | scripts/analyst_macro_prompt.md, scripts/analyst_pm_prompt.md |
완료 제출 4줄 틀을 최상단 규칙으로 추가(비코딩 문서 수정이지만 실행 프롬프트라 codex가 반영·검증) | grep -c '근거파일:' scripts/analyst_macro_prompt.md → 현재 2, 수정 후 증가 확인 |
| C5 | scripts/shared/agent_task_quality.py 1040~1050행 [자동 보강: 완료보고 4블록 설명형 라벨 보충]와 scripts/orchestrator.py 1146행 부근 |
태스크 본문에 자동 삽입되는 "검증: exit code 0; 통과"가 에이전트에게 복사 가능한 문장이다. 이번 태스크 본문도 같은 문구를 포함. 템플릿이 복사돼 반려되는지(CMD#40276 사례) 확인 필요 | 수정 전후로 sqlite3 … "SELECT COUNT(*) FROM bus_commands WHERE body LIKE '%exit code 0; 통과%'" 비교 |
7. 미확인·한계
- 81건 전체
result_note를 개별로 읽지 않았다. 읽은 것은 #42798, #42694, #42778, #42762, #42768, #42781, #42684, #42332, #42454, #42503, #42671, #41900, #40297와 라벨 집계(SQL)다. - 저장본이 잘려 4블록 뒷부분이 안 보이는 것이 "에이전트가 안 썼다"인지 "저장 시 잘렸다"인지는 구분 못 했다.
server.py의 exit code 판정 로직(818~840행)은 읽었지만, 5-②의 표기가 실제로 통과하는지 실행 시험은 안 했다.- 같은 날 다른 두 문서의 내용과 겹치는 부분(분포, 메타 순환)은 다시 검증하지 않고 건수만 이 조회 결과와 맞췄다.