codex 완료보고 자리표시자·검증결과 누락 반복 반려 방지안
codex 완료보고 자리표시자·검증결과 누락 반복 반려 방지안 (2026-09-23)
조사 시각: 2026-09-23 07:10~07:30 KST
원자료: /Users/ron/.hermes/workspace/logs/codex_result_rejected.jsonl 112~114행(전체 114행),
/Users/ron/.hermes/data/ops_multiagent.db bus_commands id 39785/39792/39793,
scripts/agent_queue_worker.py, scripts/shared/agent_task_quality.py, scripts/agent_registry.py,
config/agent_completion_submission_standard.md.
코드 수정은 하지 않았다. 게이트 판정은 워커 모듈을 import해 원본 raw_result에 그대로 재적용한 결과다
(프로브 스크립트 /tmp/gate_probe.py, /tmp/gate_probe2.py, /tmp/gate_probe3.py, /tmp/gate_sim.py).
0. 한 줄 결론
세 건 모두 작업은 실제로 됐다. 반려의 주원인은 codex가 꺾쇠 자리표시자를 복사해서가 아니라,
(a) codex 게이트가 요구하는 "검증 결과:" / "exit code: N" 리터럴 형식을 표준 문서·codex 프롬프트가
가르치지 않고 있고(문서 예시 4개가 전부 codex 게이트에서 탈락), (b) logs/ 상대경로를 ~/.hermes/logs로만
해석하는 경로 판정 결함 두 가지다. <원본로그경로>는 codex 출력이 아니라 워커가 반려 노트를 만들 때
스스로 끼워 넣는 마스킹 토큰이다.
1. [권고]
→ 1순위 (문서, cowork 즉시 가능 / 해리 승인 불필요한 설정 문서): config/agent_completion_submission_standard.md
§3·§3-1·§3-1-1의 "검증:" 예시를 codex 게이트 통과형으로 교체하고, codex 전용 §3-2 절을 신설한다(초안은 §5).
근거: 현재 문서 예시 4개(112-113행, 126행, 149-150행, 668-669행)를 _codex_has_verification_result_field()에
그대로 넣으면 4/4 missing_verification_result. 2026-09-16 이후 codex 반려 48건 중 25건(52%)이
missing_verification_result이고, 그중 23건은 원문에 이미 "exit code 0" 또는 "passed"가 들어 있었다
— 즉 값은 있는데 형식이 게이트와 안 맞는다.
기대효과: 형식 불일치형 반려 23건/주 수준을 0~2건으로(형식만 바꾸면 되는 건이므로 90% 이상 감소 목표).
→ 1순위 (코드, codex 위임): 게이트-문서 정합화 2건.
(1) _CODEX_VERIFICATION_RESULT_FIELD_RE(agent_queue_worker.py 5896-5900행)가 "검증:" 줄 안의
→ exit code 0 / → N passed(콜론 없는 형태)를 인정하도록 확장.
(2) _reported_workspace_paths()(5955-5956행)가 logs/... 상대경로를 ~/.hermes/logs만 보지 말고
~/.hermes/workspace/logs도 존재 확인.
시뮬레이션(원본 코드 미변경, 모듈 로드 후 몽키패치): 09-16 이후 반려 48건 중 통과 0건 → 6건,
이번 대상 3건 중 39792·39793 2건이 통과로 바뀜. 39785는 백틱 인용·PY_COMPILE_EXIT:0 때문에 여전히 반려
(이는 문서 규칙으로 해결할 대상).
→ 2순위 (코드, codex 위임): 자동 보강 문구(scripts/shared/agent_task_quality.py 922-941행)의
검증: py_compile; exit code 0 / 근거파일: 경로:<줄번호>를 "형식 지시문 + 금지 규칙" 문장으로 교체하고
codex용으로는 검증 결과: 줄을 명시. 또 _codex_rejected_raw_excerpt()(6218-6222행)의 마스킹 토큰
<원본로그경로>를 [경로생략:jsonl참조]처럼 자리표시자로 오인되지 않는 표기로 바꾼다.
기대효과: 반려 노트를 읽는 사람/오케스트레이터가 "codex가 자리표시자를 썼다"고 오진하는 사례 0건
(이번 태스크 자체가 그 오진에서 출발했다).
→ 2순위 (코드, codex 위임): codex 역할 프롬프트(scripts/agent_registry.py 268행)의
검증: <실행한 검증 명령> → <실제 결과값/exit code> 한 줄을 검증 결과: <명령> → N passed / exit code 0
형식으로 교체. 현재 codex는 이 프롬프트 형식을 정확히 따랐기 때문에 탈락했다.
2. [현황]
2-1. 세 건 raw 출력 필드별 누락 표 (jsonl 112~114행, 재판정 결과 포함)
| CMD | jsonl 행 / ts | 게이트 반려 사유(원문) | "검증:" 줄 실제 형태 | 검증결과 필드 판정 | 원문확인(파일:줄+인용) | 보고 경로 존재 | 실제 원인 |
|---|---|---|---|---|---|---|---|
| 39785 | 112 / 05:37:32 | 코덱스 완료 증거 부족: missing_original_verification, missing_verification_result |
`python3 -m py_compile scripts/orchestrator.py` → `PY_COMPILE_EXIT:0`, TEST_EXIT:0 |
실패 — "검증 결과:" 라벨 없음, exit code: 형태 없음(PY_COMPILE_EXIT:0은 정규식 밖) |
실패 — 줄번호·파일 있음, 인용이 백틱(`def _is_ron_dedicated...`)이라 _EVIDENCE_QUOTE_RE(큰따옴표/「」만) 불일치 |
orchestrator.py, AGENTS.md 둘 다 존재 | 형식 2건(검증결과 라벨·인용부호) |
| 39792 | 113 / 07:02:02 | 보고된 파일이 실제로 없음: /Users/ron/.hermes/logs/health-check-result-20260923T064512.log (DB 노트엔 "원본 로그에 보존된 경로 1건"으로 마스킹) |
`python3 -m pytest ...` → `1 passed`; `python3 -m py_compile ...` → exit code 0 |
실패(2차 사유) — exit code 0에 콜론이 없어 필드 정규식 불일치 |
통과 — 큰따옴표 인용 있음 | logs/health-check-result-20260923T064512.log를 ~/.hermes/logs/로 해석 → 없음. 실제 파일은 ~/.hermes/workspace/logs/에 550바이트로 존재(ls 확인) |
경로 판정 결함 + 형식 1건 |
| 39793 | 114 / 07:04:47 | 코덱스 완료 증거 부족: missing_verification_result |
verification_command: python3 -m py_compile ... → exit code 0; pytest ... → 2 passed; ... → 6 passed |
실패 — verification_command:는 있으나 "검증 결과:"/exit code: 없음 |
통과 | 5개 경로 전부 존재 | 형식 1건(검증결과 라벨) |
보조 실측: 세 raw 출력 어디에도 <원본로그경로> 없음(grep -c '<원본로그경로>' logs/codex_result_rejected.jsonl → 0).
사용자 요청문이 말한 <원본로그경로>는 DB result_note의 "원본 출력 발췌"에만 있으며, 이는
scripts/agent_queue_worker.py:6221 excerpt = re.sub(r"(?:/Users/ron/|~/|(?:scripts|tests|logs|data|config)/)[\w가-힣./@+~=-]+", "<원본로그경로>", excerpt)가
워커 쪽에서 치환한 결과다. 39785·39793은 "보고된 파일 없음"이 아니라 검증 형식 문제로 반려됐다.
2-2. 자동 보강 예시(<줄번호>)가 codex 출력에 복사되는가
- 세 태스크 body 모두 자동 보강 블록 포함(
instr(body,'<줄번호>')39785=842, 39792=2152, 39793=1457). - 세 codex raw 출력에는
<줄번호>0건 — codex는 실제 줄번호(2186-2193, 3901, 3870/3973 등)를 적었다. - jsonl 전체 114행 중
<줄번호>포함은 1행(109행, 2026-09-22 23:09 "server.py 완료증거 게이트의 logs 상대경로 오판정 버그 수정")뿐이며, 이는 codex가 태스크 본문 전체를 되풀이 출력한 경우다. - 결론: 자리표시자 "복사"는 이번 3건의 원인이 아니다. 다만 자동 보강 블록의
검증: exit code 0,검증: py_compile; exit code 0; 통과문구 자체가 codex 게이트를 통과하지 못하는 형식(재판정:검증: exit code 0→missing_verification_result)이라, codex가 이 예시를 "따라 쓰면" 반려된다는 구조적 함정은 있다. - 참고: 09-22 23:09 건의 제목이 "logs 상대경로 오판정 버그 수정"인데, 오늘 39792가 같은 계열(
logs/해석)로 반려됐다 —server.py쪽만 고쳐지고agent_queue_worker._reported_workspace_paths()는 남아 있는 상태로 보인다(미확인: server.py 수정 반영 여부는 이번에 재확인하지 않음).
2-3. 추세 수치 (2026-09-16 ~ 09-23, codex 반려 48건)
| 사유 | 건수 |
|---|---|
| missing_verification_result | 25 (그중 23건은 원문에 exit code 0/passed 존재) |
| missing_original_verification | 15 |
| 보고된 파일이 실제로 없음 | 11 (10건은 진짜 없는 파일 = 정당 반려, 1건은 39792 경로 오판정) |
| missing_verification_command | 3 |
| missing_verification_exit_code | 3 |
2-4. 문서·프롬프트 예시의 게이트 통과 여부 (재판정)
| 출처 | 예시 | codex 게이트 |
|---|---|---|
| standard.md 112-113행 | 검증: python3 -m pytest ... -q → 12 passed |
탈락 |
| standard.md 126행 형식 | 검증: python3 -m py_compile scripts/a.py → exit code 0 |
탈락 |
| standard.md 149-150행 | 검증: verification_command: grep -n ... → exit code 0, 매치 다수 |
탈락 |
| standard.md 668-669행 | 검증: python3 ... --ticker NVDA → exit code 0, PER=42.1 |
탈락 |
| agent_registry.py 268행(codex 프롬프트) | 검증: <실행한 검증 명령> → <실제 결과값/exit code> |
이 형식대로 쓰면 탈락 |
| 제안 형식 | 검증 결과: python3 -m pytest ... -q → 1 passed / exit code 0 |
통과 |
| 제안 형식 전체 4블록(§5 예시) | _validate_codex_result → (True, 'ok'), gaps [] |
통과 |
3. [리스크]
- 정규식 완화의 오탐 위험:
exit code 0(콜론 없음)을 본문 어디서나 인정하면 "exit code 0이 나와야 한다" 같은 기대치 서술도 통과시킨다. 시뮬레이션은 전역 완화로 돌렸으므로 실제 구현은 "검증:/검증 결과: 줄 안의→뒤"로 범위를 한정해야 한다. 이 제한 없이는_CODEX_BAD_VERIFICATION_RESULT_VALUE_RE(예정/대기/미실행) 우회 경로가 생긴다. - 경로 해석 이원화:
logs/가~/.hermes/logs(부모)와~/.hermes/workspace/logs(워크스페이스) 두 곳에 모두 존재하는 구조 자체가 단일 장애점이다. 둘 중 하나라도 있으면 인정하도록 바꾸되, 두 곳 모두 없으면 여전히 반려해야 정당 반려 10건(진짜 없는 파일)이 새지 않는다. - 게이트 3중화: 스킬 기록상 완료 게이트 함수가 agent_queue_worker/public_result_formatter/server 세 곳에 있다. 한 곳만 고치면 다른 곳에서 재반려된다(09-22 server.py 수정 뒤 오늘 워커 쪽에서 같은 계열 재발한 것이 그 예).
- 문서만 고치고 프롬프트(agent_registry.py 268행)와 자동 보강(agent_task_quality.py 922-941행)을 안 고치면 codex는 계속 옛 형식을 받는다. 세 곳이 한 세트로 바뀌어야 한다.
- 39785형(백틱 인용)은 코드 완화 대상이 아니다: 백틱은 경로 표기에도 쓰여 인용 판정을 백틱까지 넓히면 경로만 적어도 "인용 있음"으로 통과한다. 문서 규칙("원문 인용은 큰따옴표")으로만 해결한다.
4. [검증방법]
- KPI 1: 적용 후 7일간
logs/codex_result_rejected.jsonl에서 reason에missing_verification_result를 포함하면서 raw_result에exit code 0또는passed가 있는 행 수. 기준선 23건(09-16~09-23) → 목표 2건 이하. 측정: 이 보고서 §2-3과 같은 집계 스크립트(/tmp/gate_sim.py의 전반부)를 기간만 바꿔 재실행. - KPI 2:
보고된 파일이 실제로 없음중~/.hermes/workspace/logs/에 실존하는 경로 건수. 기준선 1건 → 0건. 동시에 진짜 없는 파일 반려(기준선 10건/주)는 유지돼야 한다(0으로 떨어지면 게이트가 뚫린 것 → 롤백). - 회귀 테스트(codex 후속 태스크에 포함): jsonl 113·114행 raw_result를 픽스처로
_validate_codex_result()→(True,'ok'); "검증: exit code 0이 나와야 한다(예정)" 픽스처 → 반려 유지;logs/없는파일.log픽스처 → 반려 유지. - 문서 검증: 수정 후 standard.md의 모든 "검증 결과:" 예시 줄을
_codex_has_verification_result_field()에 넣어 전부 True. - 롤백 조건: 적용 후 3일 내 정당 반려(진짜 없는 파일·"예정/미실행" 서술)가 done으로 저장된 사례 1건이라도 나오면 정규식 변경을 되돌린다.
5. config/agent_completion_submission_standard.md 추가안 (§3-2 신설, 초안)
### 3-2. codex 전용 제출 형식 (2026-09-23 신설, CMD#39785/#39792/#39793 재발방지)
codex 완료는 일반 4블록보다 한 줄 더 엄격하다. `_codex_has_verification_result_field()`는
"검증 결과:" 라벨 또는 "exit code: N"(콜론/등호 포함) 형태만 인정한다.
"→ exit code 0"(콜론 없음), "→ 1 passed", "PY_COMPILE_EXIT:0"은 값이 맞아도 반려된다.
필수 규칙
1. "검증 결과:" 줄을 반드시 1개 이상 쓴다. 형식:
검증 결과: <실제 실행한 명령> → N passed / exit code 0
2. 꺾쇠 자리표시자(<줄번호>, <원본로그경로>, <명령> 등)를 제출문에 남기지 않는다.
태스크 본문의 [자동 보강] 블록은 형식 안내일 뿐 복사 대상이 아니다.
3. 원문 인용은 큰따옴표 "..."로 감싼다. 백틱 `...`은 인용으로 인정되지 않는다.
4. logs/ 경로는 절대경로로 쓴다(/Users/ron/.hermes/workspace/logs/... 또는 /Users/ron/.hermes/logs/...).
상대 logs/는 ~/.hermes/logs로 해석돼 workspace/logs 파일이 "없음" 판정된다.
실행 가능한 예시(실측 통과: _validate_codex_result → (True, 'ok')):
결론: scripts/agent_queue_worker.py의 sanitizer를 수정하고 회귀 테스트를 추가했다.
근거: source_log_path: /Users/ron/.hermes/workspace/tests/test_health_check_completion_note_sanitizer.py, 조회 2026-09-23 07:00 KST
검증: verification_command: python3 -m pytest tests/test_health_check_completion_note_sanitizer.py -q
검증 결과: python3 -m pytest tests/test_health_check_completion_note_sanitizer.py -q → 1 passed / exit code 0
근거파일: scripts/agent_queue_worker.py:3901 "cleaned = _append_verifiable_completion_evidence(cleaned, raw_note)"
같은 문서 112-113행·126행·149-150행 예시에도 "검증 결과: ... → ... / exit code 0" 줄을 한 줄씩 추가해 문서 예시가 codex 게이트를 통과하도록 맞춘다.
6. 자동 보강 문구 수정안 (scripts/shared/agent_task_quality.py 922-941행 대상)
현재:
검증: py_compile; exit code 0; 통과
근거파일: scripts/orchestrator.py:<줄번호>, AGENTS.md:<줄번호>
수정안(꺾쇠 없음, 지시문임을 명시):
[자동 보강: 완료보고 4블록 형식 안내 — 아래 문장은 복사하지 말고 실제 값으로 새로 쓸 것]
결론: 수행한 일과 현재 상태를 완료형 한 문장으로 적는다.
근거: 대상 파일 scripts/orchestrator.py, AGENTS.md 를 읽은 경로와 조회 시각을 적는다.
검증: verification_command: 로 실제 실행한 명령을 적는다.
검증 결과: 실행한 명령 → N passed / exit code 0 형태로 실제 출력값을 한 줄로 적는다(codex 필수).
근거파일: 위 대상 파일의 실제 수정/확인 줄번호와 그 줄 원문을 큰따옴표로 인용한다.
7. codex 후속 태스크 초안 (등록은 하지 않음 — 오케스트레이터/해리 판단)
T1 (high) 제목: agent_queue_worker.py codex 검증결과 정규식이 "검증:" 줄의 "→ exit code 0"/"→ N passed"를 인정하도록 수정
- 대상: scripts/agent_queue_worker.py 5896-5904행 _CODEX_VERIFICATION_RESULT_FIELD_RE, 5981-6004행 _codex_has_verification_result_field
- 조건: "검증:" 또는 "검증 결과:" 줄 안에서 → 뒤의 exit code N(콜론 선택) 또는 N passed(failed 0 또는 미표기)만 인정. 본문 임의 위치 매치 금지. _CODEX_BAD_VERIFICATION_RESULT_VALUE_RE 선검사 유지.
- 테스트: jsonl 114행 raw(39793) → (True,'ok'); "검증: exit code 0이 나와야 함(예정)" → 반려 유지.
- 같은 규칙이 shared/public_result_formatter.py·server.py 게이트에도 있는지 grep 후 동일 반영.
T2 (high) 제목: _reported_workspace_paths의 logs/ 상대경로를 workspace/logs와 ~/.hermes/logs 둘 다 확인
- 대상: scripts/agent_queue_worker.py 5951-5958행
- 조건: 둘 중 존재하는 쪽을 채택, 둘 다 없으면 기존처럼 없는 경로로 반려.
- 테스트: jsonl 113행 raw(39792) → 경로 판정 통과; logs/nonexistent_x.log → 반려 유지.
T3 (normal) 제목: 자동 보강 문구·반려 발췌 마스킹 토큰·codex 프롬프트 형식 정합화
- scripts/shared/agent_task_quality.py 922-941행: §6 수정안 반영(<줄번호> 제거, "검증 결과:" 줄 추가)
- scripts/agent_queue_worker.py 6221행: <원본로그경로> → [경로생략:jsonl참조]
- scripts/agent_registry.py 268행(codex 블록): 검증 결과: <명령> → N passed / exit code 0 형식으로 교체
- 테스트: 기존 tests/test_queue_body_evidence_regressions.py 통과 유지 + 보강 블록에 <줄번호> 0건 단언.