[Bug] send_keys_safe 가 codex 로의 프롬프트 전달을 실패로 오판 → 리뷰 job 이 agent_blocked error 로 종결되고 이후 판정이 거부되는 문제 #14

Closed
opened 2026-09-12 12:25:37 +00:00 by Godopu · 1 comment
Owner

문제 개요 (Summary)

multi-agent-mux-loop 가 codex 리뷰어에게 리뷰 job 을 보낼 때, 프롬프트가 실제로는 전달되었는데도 send_keys_safe 가 전달 실패로 판정합니다. job 은 즉시 error (agent_blocked) 로 종결되고, codex 가 이후 발행하는 started/completed 이벤트는 terminal 상태라 CAS 에서 거부됩니다. 결과적으로 codex 의 판정(PASS/NOT PASS)은 루프에 한 번도 반영되지 않으며, codex 가 포함된 --all-reviewer 루프는 만장일치에 도달할 수 없습니다.

늦게 도착한 completed 를 거부하는 것 자체는 Issue #6 의 fail-closed 설계이므로 결함이 아닙니다. 결함은 전달 성공을 실패로 오판하는 부분입니다.


재현 (Reproduction) — 3/3

run_loop.sh --creator creator-claude-01 --all-reviewer --max-loop 3 (리뷰어: claude·agy·grok·codex) 실행 중 codex 리뷰 job 이 매 이터레이션마다 동일하게 실패:

job error (agent_blocked) codex started codex completed 레코드 최종 status
98093686 (iter 1) 11:47:41Z 11:47:43Z (+2s) 11:50:23Z — PASS error
120ace35 (iter 2) 12:11:07Z 12:11:10Z (+3s) 12:13:41Z — NOT PASS error
a536fce2 (iter 3) 12:19:39Z 12:19:39Z (+0s) (검토 진행 중에 루프 종료) error
  • 루프 로그: Monitoring job '<id>' for status changes (timeout: 5.0s)... Reviewer 'planner-reviewer-codex-01' job crashed.
  • submit 로그: send_keys_safe: delivery unknown/failed (planner-reviewer-codex-01) / ERROR: 프롬프트 주입 실패 — 세션 'planner-reviewer-codex-01' (프롬프트 잠금 의심)
  • codex pane 에도 Completion event rejected because the job was already terminal error. 가 출력됨
  • 같은 루프의 claude·agy·grok 리뷰어는 정상 (iter 3 에서 3인 PASS). 루프는 codex 한 명 때문에 exit 1 로 종료

세부 원인 분석 (Detailed Root Causes)

  • 위치: .agents/skills/lib.sh send_keys_safe (2330행~), 특히 2400–2446행
  • 동작:
    • 2400행: herdr agent prompt <target> <text> --wait --until working --timeout 5000
    • 실패 시 2431행 sleep 2 후 herdr agent get 의 agent_status 가 working 인지 1회 확인 (2442행)
    • 아니면 2445행 delivery unknown/failed 출력 후 return 4 → 호출 측에서 job 을 error agent_blocked 로 종결
  • 추정 원인: 프롬프트 전송 후 약 7초(5s wait + 2s) 이내에 herdr 가 codex 의 agent_status 를 working 으로 보고하지 않음. codex 는 프롬프트를 정상 수신해 0–3초 내 started 를 발행했으므로, 전달 확인 신호(herdr agent_status)와 실제 전달 사이의 불일치로 보임 (codex 상태 전이 지연/미검출 여부는 미측정)
  • 단일 주입 계약(2429행 주석: 재전송 금지)상 재시도도 하지 않으므로, 오판이 그대로 job 종결로 이어짐

영향 (Impact) — High

  • codex 가 리뷰어로 포함된 모든 --all-reviewer / --reviewer 루프에서 codex 판정이 무시되고 crashed 로 처리 → 만장일치 불가, --max-loop 소진 후 실패
  • codex 가 실제로 수행한 리뷰(수 분 소요)가 낭비되고, 리포트는 남지만 레지스트리 상태와 불일치

제안 해결책 (Proposed Fix)

  • 전달 확인을 herdr agent_status == working 단일 신호에 의존하지 말고, 해당 job 의 started 이벤트 수신(또는 pane 에 프롬프트 에코 확인)도 성공 신호로 인정
  • return 4(delivery unknown) 는 즉시 error 로 종결하지 말고 "unknown" 상태로 두고 started 이벤트를 짧은 유예 시간 동안 기다린 뒤 판정 (단일 주입 계약은 유지 — 재전송 없음)
  • codex 어댑터의 --until working 타임아웃(5000ms)이 충분한지 측정 후 에이전트별 설정값으로 분리
  • 회귀 테스트: agent prompt 가 timeout 을 반환하지만 started 가 도착하는 케이스에서 job 이 error 로 종결되지 않아야 함

환경 정보 (Environment)

  • OS: macOS (Darwin 25.6.0)
  • MAM Version: 4d444ce (main)
  • Agent: codex (planner-reviewer-codex-01, gpt-6-astra high), herdr session multi-agent-mux
  • 비교: agy 의 42dadf59 도 agent_blocked 였으나 이후 started 가 없고 pane 이 이전 작업 후 "Generating..." 에 멈춘 상태여서 본 이슈와 별개로 판단함
## 문제 개요 (Summary) `multi-agent-mux-loop` 가 codex 리뷰어에게 리뷰 job 을 보낼 때, 프롬프트가 **실제로는 전달되었는데도** `send_keys_safe` 가 전달 실패로 판정합니다. job 은 즉시 `error` (`agent_blocked`) 로 종결되고, codex 가 이후 발행하는 `started`/`completed` 이벤트는 terminal 상태라 CAS 에서 거부됩니다. 결과적으로 codex 의 판정(PASS/NOT PASS)은 루프에 **한 번도 반영되지 않으며**, codex 가 포함된 `--all-reviewer` 루프는 만장일치에 도달할 수 없습니다. > 늦게 도착한 `completed` 를 거부하는 것 자체는 Issue #6 의 fail-closed 설계이므로 결함이 아닙니다. 결함은 **전달 성공을 실패로 오판하는 부분**입니다. --- ## 재현 (Reproduction) — 3/3 `run_loop.sh --creator creator-claude-01 --all-reviewer --max-loop 3` (리뷰어: claude·agy·grok·codex) 실행 중 codex 리뷰 job 이 매 이터레이션마다 동일하게 실패: | job | error (agent_blocked) | codex started | codex completed | 레코드 최종 status | |---|---|---|---|---| | `98093686` (iter 1) | 11:47:41Z | 11:47:43Z (+2s) | 11:50:23Z — PASS | `error` | | `120ace35` (iter 2) | 12:11:07Z | 12:11:10Z (+3s) | 12:13:41Z — NOT PASS | `error` | | `a536fce2` (iter 3) | 12:19:39Z | 12:19:39Z (+0s) | (검토 진행 중에 루프 종료) | `error` | - 루프 로그: `Monitoring job '<id>' for status changes (timeout: 5.0s)... Reviewer 'planner-reviewer-codex-01' job crashed.` - submit 로그: `send_keys_safe: delivery unknown/failed (planner-reviewer-codex-01)` / `ERROR: 프롬프트 주입 실패 — 세션 'planner-reviewer-codex-01' (프롬프트 잠금 의심)` - codex pane 에도 `Completion event rejected because the job was already terminal error.` 가 출력됨 - 같은 루프의 claude·agy·grok 리뷰어는 정상 (iter 3 에서 3인 PASS). 루프는 codex 한 명 때문에 `exit 1` 로 종료 --- ## 세부 원인 분석 (Detailed Root Causes) - **위치**: `.agents/skills/lib.sh` `send_keys_safe` (2330행~), 특히 2400–2446행 - **동작**: - 2400행: `herdr agent prompt <target> <text> --wait --until working --timeout 5000` - 실패 시 2431행 `sleep 2` 후 `herdr agent get` 의 `agent_status` 가 `working` 인지 1회 확인 (2442행) - 아니면 2445행 `delivery unknown/failed` 출력 후 `return 4` → 호출 측에서 job 을 `error agent_blocked` 로 종결 - **추정 원인**: 프롬프트 전송 후 약 7초(5s wait + 2s) 이내에 herdr 가 codex 의 `agent_status` 를 `working` 으로 보고하지 않음. codex 는 프롬프트를 정상 수신해 0–3초 내 `started` 를 발행했으므로, **전달 확인 신호(herdr agent_status)와 실제 전달 사이의 불일치**로 보임 (codex 상태 전이 지연/미검출 여부는 미측정) - 단일 주입 계약(2429행 주석: 재전송 금지)상 재시도도 하지 않으므로, 오판이 그대로 job 종결로 이어짐 --- ## 영향 (Impact) — High - codex 가 리뷰어로 포함된 모든 `--all-reviewer` / `--reviewer` 루프에서 codex 판정이 무시되고 `crashed` 로 처리 → 만장일치 불가, `--max-loop` 소진 후 실패 - codex 가 실제로 수행한 리뷰(수 분 소요)가 낭비되고, 리포트는 남지만 레지스트리 상태와 불일치 --- ## 제안 해결책 (Proposed Fix) - 전달 확인을 herdr `agent_status == working` 단일 신호에 의존하지 말고, 해당 job 의 `started` 이벤트 수신(또는 pane 에 프롬프트 에코 확인)도 성공 신호로 인정 - `return 4`(delivery unknown) 는 즉시 `error` 로 종결하지 말고 "unknown" 상태로 두고 `started` 이벤트를 짧은 유예 시간 동안 기다린 뒤 판정 (단일 주입 계약은 유지 — 재전송 없음) - codex 어댑터의 `--until working` 타임아웃(5000ms)이 충분한지 측정 후 에이전트별 설정값으로 분리 - 회귀 테스트: `agent prompt` 가 timeout 을 반환하지만 `started` 가 도착하는 케이스에서 job 이 `error` 로 종결되지 않아야 함 --- ## 환경 정보 (Environment) - OS: macOS (Darwin 25.6.0) - MAM Version: 4d444ce (main) - Agent: codex (`planner-reviewer-codex-01`, gpt-6-astra high), herdr session `multi-agent-mux` - 비교: agy 의 `42dadf59` 도 `agent_blocked` 였으나 이후 `started` 가 없고 pane 이 이전 작업 후 "Generating..." 에 멈춘 상태여서 **본 이슈와 별개**로 판단함
Author
Owner

브랜치 fix/issue-9-14 에서 해결 (main 4d444ce 기준, 병합 전).

원인 실측: herdr 0.9.0 은 codex 에 프롬프트를 정상 전달한 뒤 agent prompt --wait --until working --timeout 5000 에 {"code":"timeout"} 을 돌려주고, codex 의 agent_status 는 작업 중에도 계속 idle 로 보고됨.

수정 내용

  • send_keys_safe: timeout/agent_prompt_stalled(= 입력은 전달됐고 상태 관측만 실패)이면 SKS_DELIVERY_GRACE_S(기본 15초) 동안 working 상태, 제출 전엔 없던 pane busy 토큰(esc to interrupt), 제출 전 스냅샷 대비 pane 변화 중 하나를 전달 확인 신호로 인정. 신호가 없으면 종전대로 rc 4 fail-closed, transport_error 등은 종전 의미 유지, 단일 주입 계약 유지 (497633f)
  • 래퍼 _inject_acknowledged: 전달 미확인 시 MAM_INJECT_ACK_GRACE_S(기본 10초) 동안 레지스트리를 관측해 pending 을 벗어났으면(에이전트의 started) agent_blocked 로 닫지 않고 진행 (497633f)
  • 래퍼 R1 유예 _agent_still_working: herdr working 외에 pane busy 토큰 인정 (eaa49aa); _recent_disk_heartbeat: events.log 의 최근 heartbeat 도 생존 근거로 인정하고 근거마다 idle 창을 재개방, 벽시계 START_TIME+TIMEOUT 에서 확정 종료 (d5a191c, 952657e)
  • publish_event: 이벤트를 브로커 발행 전에 로컬 events.log 에 기록 (ebe58f6)

검증

  • tests/test_issue14_delivery_ack.py 등 신규 테스트, 전체 스위트 819/819 통과
  • 실측: codex 위임 job d04ebcb5 의 started/completed 가 agent_blocked 없이 수락; codex 포함 --all-reviewer 루프가 만장일치 PASS 로 종료
  • 리뷰 루프 claude·agy·grok·codex 만장일치 PASS (.agents/reports/*/report-{2d3f24e4,47a845e0,d7e66053,0ad7cb06}.md)
  • v4.4.2 락스텝 반영 (0918917)
브랜치 `fix/issue-9-14` 에서 해결 (main `4d444ce` 기준, 병합 전). **원인 실측**: herdr 0.9.0 은 codex 에 프롬프트를 정상 전달한 뒤 `agent prompt --wait --until working --timeout 5000` 에 `{"code":"timeout"}` 을 돌려주고, codex 의 `agent_status` 는 작업 중에도 계속 `idle` 로 보고됨. **수정 내용** - `send_keys_safe`: `timeout`/`agent_prompt_stalled`(= 입력은 전달됐고 상태 관측만 실패)이면 `SKS_DELIVERY_GRACE_S`(기본 15초) 동안 `working` 상태, 제출 전엔 없던 pane busy 토큰(`esc to interrupt`), 제출 전 스냅샷 대비 pane 변화 중 하나를 전달 확인 신호로 인정. 신호가 없으면 종전대로 rc 4 fail-closed, `transport_error` 등은 종전 의미 유지, 단일 주입 계약 유지 (`497633f`) - 래퍼 `_inject_acknowledged`: 전달 미확인 시 `MAM_INJECT_ACK_GRACE_S`(기본 10초) 동안 레지스트리를 관측해 `pending` 을 벗어났으면(에이전트의 `started`) `agent_blocked` 로 닫지 않고 진행 (`497633f`) - 래퍼 R1 유예 `_agent_still_working`: herdr `working` 외에 pane busy 토큰 인정 (`eaa49aa`); `_recent_disk_heartbeat`: `events.log` 의 최근 heartbeat 도 생존 근거로 인정하고 근거마다 idle 창을 재개방, 벽시계 `START_TIME+TIMEOUT` 에서 확정 종료 (`d5a191c`, `952657e`) - `publish_event`: 이벤트를 브로커 발행 **전에** 로컬 `events.log` 에 기록 (`ebe58f6`) **검증** - `tests/test_issue14_delivery_ack.py` 등 신규 테스트, 전체 스위트 819/819 통과 - 실측: codex 위임 job `d04ebcb5` 의 `started`/`completed` 가 `agent_blocked` 없이 수락; codex 포함 `--all-reviewer` 루프가 만장일치 PASS 로 종료 - 리뷰 루프 claude·agy·grok·codex 만장일치 PASS (`.agents/reports/*/report-{2d3f24e4,47a845e0,d7e66053,0ad7cb06}.md`) - v4.4.2 락스텝 반영 (`0918917`)
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tmpl/multi-agent-mux#14