Files
multi-agent-mux/.agents/reports/planner-reviewer-claude-01/report-e8cee19e.md
T
Godopu c3631e2aa1 fix(herdr): resolve shim routing defects, add workspace scoping, and bump to v3.0.1
- Resolve Herdr shim 5 routing & paste defects (ISSUE-1 ~ ISSUE-5):
  * paste-buffer: use pane send-text without auto-enter, propagate rc=3 to send_keys_safe
  * exact-match pane resolution: remove substring matching ('in tn') across all branches
  * workspace scoping: introduce HERDR_WORKSPACE_ID and .mam/herdr_workspace_id persistence
  * unified resolver: single _resolve_herdr_pane_id helper across shim commands
- Resolve dialog token false-positive on 'Yes, try it' tip and isolate fullscreen modal rejection
- Sync mock Herdr CLI contracts in tests/conftest.py
- Add contract tests H-15~H-23 and regression tests D-4~D-7 (412 tests, 100% PASS)
- Add multi-agent loop plans, review reports, and bug report
- Update framework and skill packages to v3.0.1
2026-08-27 21:42:37 +09:00

16 KiB
Raw Blame History

🔍 교차 코드 리뷰 리포트 — Job e8cee19e

  • Job ID: e8cee19e
  • 리뷰어: planner-reviewer-claude-01 (Reviewer)
  • 작성일: 2026-08-27
  • 대상 브랜치/기준 커밋: main @ 4bbd03b
  • 리뷰 범위: 워킹트리 누적 변경분 (git diff) — 4 files, +808 / 92
    • .agents/skills/lib.sh (+289/−…)
    • tests/conftest.py
    • tests/test_herdr_shim_contract.py
    • tests/test_b19_headless_reconcile_fixes.py
  • 근거 문서: bug_report.md (v1.0), .agents/reports/planner-reviewer-claude-01/plan-fae58b93.md

0. 요약 (TL;DR)

계획서(plan-fae58b93.md)에 명시된 F-1 ~ F-4 및 워크스페이스 세션 격리(ISSUE-1/2/3/5) 4개 항목이 모두 코드에 반영되어 있으며, 전체 회귀 테스트가 412 passed (실측 699.09s, exit 0) 로 통과함을 리뷰어 환경에서 재실행하여 직접 확인했다.

린트(구문), 동작성, 유실(회귀) 세 관점 모두에서 머지를 막을 결함(blocker)은 발견되지 않았다. 다만 설계상 의도적으로 남겨진 잔여 스코프 갭 3건을 비차단 후속 과제(Non-blocking) 로 기록한다.


1. 검증 방법

# 검증 항목 방법 결과
V-1 전체 회귀 테스트 .venv/bin/python -m pytest tests/ -q (리뷰어가 직접 재실행) 412 passed in 699.09s, exit 0
V-2 셸 구문 린트 bash -n .agents/skills/lib.sh 통과 (오류 없음)
V-3 생성 shim 구문 린트 bash -n $WORKSPACE_ROOT/.mam/shim/herdr (H-19 테스트 내장) 통과
V-4 Bash 3.2 호환성 로컬 GNU bash 3.2.57 (arm64-apple-darwin25) 에서 local arr=() + "${a[@]+"${a[@]}"}" 패턴 실측 set -euo pipefail 하에서 정상 동작
V-5 정적 교차 검토 diff 전량 + 인접 컨텍스트(lib.sh 380440, 609730, 1926~2070행) 직접 판독 계획서와 구현 일치
V-6 호출자 영향 분석 send_keys_safe 호출부 grep (stop_session.sh:204, delegate-job:527) 신규 rc=3 를 모두 비정상으로 처리

참고: shellcheck 는 본 환경에 미설치되어 실행하지 못했다. 대신 bash -n 2종(원본 + 생성 shim) + Bash 3.2 실측으로 대체했다. 이는 CI 게이트가 아니므로 차단 사유가 아니다.


2. 작업 목표별 반영 확인

F-1 — Yes, try it 토큰 정리 및 회귀 테스트

  • _MAM_DIALOG_TOKENS 에서 |Yes, try it 제거 확인 (lib.sh:62).
  • handle_startup_dialogs 의 Escape 거부 분기(lib.sh:2048)는 그대로 보존 — 실제 fullscreen 업셀 모달은 여전히 Escape 로 거부된다. 즉 "탐지 완화"가 아니라 책임 분리(대화형 산문 오탐 제거 / 실제 모달 처리 유지)로 올바르게 구현되었다.
  • 회귀 고정: test_prose_yes_try_it_is_not_a_dialog(산문 → DIALOG_CLOSED), test_mam_dialog_tokens_exclude_yes_try_it(토큰 라인 + Escape 분기 동시 검증), test_fullscreen_modal_is_rejected_not_accepted(Escape 전송·Enter 미전송).
  • 판정: 반영 완료. 오탐(산문으로 인한 send_keys_safe rc=2 데드락)과 정탐(모달 거부)이 양방향으로 고정되었다.

F-2b — _herdr_agent_get_scoped 스코핑 단축경로 보완

  • 기존의 스코프 없는 존재 확인(_real_herdr agent get "$x" >/dev/null 2>&1)이 has-session, kill-session, capture-pane, send-keys, paste-buffer, agent 6개 분기에서 전부 제거되고 _herdr_agent_get_scoped / _resolve_herdr_pane_id 로 대체됨.
  • _resolve_herdr_target명시적 env 미스 시 raw 폴스루 차단(HERDR_WORKSPACE_ID 설정 시 return 1)이 추가됨 — 이것이 F-2b 의 핵심이며, agent prompt 가 타 워크스페이스 동명 에이전트로 프롬프트를 배달하는 경로를 실제로 닫는다.
  • 호출부 3곳(prompt/get/read)이 $(... || true) + 빈 문자열 검사 + exit 1실패를 삼키지 않고 상위 전달한다. set -e 하에서 명령 치환 실패로 셸이 죽지 않도록 || true 가 일관되게 붙어 있다 — 계약(주석에 명시)과 구현이 일치.
  • 회귀 고정: test_h21_has_session_agent_get_is_workspace_scoped(w2 → rc=1, w1 → rc=0, unset → 전역 유지), test_h22_agent_prompt_does_not_cross_workspace(out-of-scope 시 agent prompt 호출 자체가 0건임을 mock call log 로 검증).
  • 판정: 반영 완료. 특히 H-22 가 "에러만 났는지"가 아니라 부작용(RPC 호출)이 발생하지 않았음을 검증하는 점이 좋다.

F-3 — H-19 테스트 정밀화

  • test_h19_single_resolver_helper_used_by_all_branches 가 단순 문자열 카운트에서 case arm 단위 파싱(_case_arm) 으로 정밀화됨.
  • 검증 강도: (a) 헬퍼 정의 1회 유일성, (b) 5개 분기 전부 헬퍼 호출, (c) 각 분기에 스코프 없는 agent get … >/dev/null 잔존 금지 정규식, (d) agent arm 의 $sat/$raw 단축경로 제거, (e) 헬퍼 블록 밖 _herdr_agent_get_scoped() 재정의 0건, (f) bash -n 2종.
  • list-panes arm 을 elsewhere 에서 제외한 처리도 타당하다(해당 arm 은 정상적으로 pane list 를 직접 다룬다).
  • 판정: 반영 완료. "헬퍼는 만들었지만 옛 경로가 살아있다"는 회귀를 구조적으로 차단한다.

F-4 — capture-pane 폴백 복원

  • capture-pane arm 이 pane read <pane_id>agent read <sat>agent read <sess> 3단 폴백으로 복원됨. pane_id 해석 실패 시에도 기존 agent-level 경로가 살아있어 유실 없음.
  • 동일 패턴이 send-keys(pane 실패 시 agent 이름 폴백), kill-session(pane close + kill-session 2단)에도 유지된다.
  • 판정: 반영 완료. F-2b 의 엄격화로 인한 기능 유실 위험이 이 폴백으로 상쇄된다.

ISSUE-1 — 이중 제출(double-submit) 차단

  • paste-buffer 가 존재하지 않는 agent send 대신 pane send-text 삽입 전용으로 교체되었고, Enter/C-m 을 일절 보내지 않는다. 제출 책임은 send_keys_safe 가 단독 소유.
  • pane 미해석 / send-text 실패 시 || true 로 삼키지 않고 exit 1send_keys_saferc=3 반환. 빈 프롬프트 제출 시나리오가 닫혔다.
  • 고속 경로(agent prompt, 원자적 텍스트+제출)와 폴백 경로(send-text → C-m)가 상호 배타적이므로 제출은 정확히 1회.
  • 회귀 고정: test_h15_paste_buffer_inserts_without_enter(send-text 정확히 1건, 제출 계열 호출 0건), test_h16_send_keys_safe_submits_exactly_once(Enter/C-m 정확히 1건), test_d5 / test_send_keys_safe_returns_3_when_paste_buffer_fails(rc=3 + 버퍼 정리 수행 + C-m 미전송), test_paste_buffer_branch_never_submits(소스 레벨 토큰 금지).
  • 판정: 반영 완료. 특히 실패 시에도 delete-buffer 를 먼저 수행한 뒤 rc 를 반환하는 순서가 정확하다(버퍼 누수 없음).

ISSUE-2 — substring 오라우팅 제거

  • _resolve_herdr_target(not name and agent and agent in tn), has-session(not an and a.get("agent") and a.get("agent") in tn) 두 substring 분기가 모두 제거되고 exact match only 로 대체.
  • _resolve_herdr_pane_id 의 pane list 매칭도 labelnameagent정확 일치(원본/sanitized 양쪽 후보)만 수행.
  • 회귀 고정: test_h17_no_substring_cross_pane_routing(reviewer-creator-grok-01agent: "grok" 패인에 매칭되지 않음 + 동종 에이전트 2개 중 정확한 패인으로만 send-keys), test_no_substring_matching_remains_in_lib_sh(소스 레벨 \bin tn\b 잔존 0건).
  • 판정: 반영 완료.

ISSUE-3 — 워크스페이스 세션 격리

  • 3단 스코프 소스: HERDR_WORKSPACE_ID (env, 하드) → $WORKSPACE_ROOT/.mam/herdr_workspace_id (persist) → 없으면 기존 서버 전역 조회.
  • cwd 추론을 하지 않는다는 결정이 주석에 명시되어 있고 구현도 일치 — 정당한 교차 워크스페이스 조회를 조용히 막지 않는다.
  • pane split--env HERDR_WORKSPACE_ID="$existing_ws" 주입, workspace create 경로에서는 응답에서 workspace_id 를 파싱해 export + 파일 영속화.
  • pane list --workspace 서버측 필터 + 파이썬 클라이언트측 재필터(구버전 herdr 가 --workspace 를 무시할 경우 대비) 이중화 — 방어적으로 잘 설계됨.
  • 회귀 고정: test_h18_workspace_scoped_pane_resolution(w1/w2 동명 라벨 분리 라우팅, unset 시 전역 유지), test_h23_persisted_workspace_id_scopes_without_env(env 없이 파일만으로 스코핑 + new-session 이 파일을 실제로 기록).
  • 판정: 반영 완료. 잔여 갭은 §4 참조.

ISSUE-5 — 파서 중복 제거

  • agent get → pane_id 를 파싱하던 인라인 python heredoc 3벌(kill-session, send-keys, 구 capture-pane)이 전부 제거되고 _resolve_herdr_pane_id 단일 진입점으로 수렴.
  • pane_id 정규식이 계획서 §1.2 의 지적대로 ^w[A-Za-z0-9]+:p[A-Za-z0-9]+$ 로 채택됨 — 버그 리포트의 ^w[0-9]+:p[0-9]+$ 를 그대로 썼다면 w1E:p1 형태의 실제 pane_id 를 전량 거부했을 것이다. 이 수정은 정확하며, test_h20_pane_id_regex_accepts_alphanumeric_workspace 로 accept/reject 5케이스가 고정되어 있다.
  • 판정: 반영 완료. 리뷰 과정에서 가장 위험했던 함정을 계획 단계에서 잡아낸 점이 확인된다.

3. 테스트 하네스(conftest.py) 변경 검토

mock herdr 변경이 "테스트를 통과시키기 위한 눈속임"이 아니라 실제 herdr CLI 계약에 더 가깝게 교정하는 방향인지를 중점 확인했다.

변경 평가
agent send 서브커맨드 제거 + 미지원 서브커맨드 exit 1 정확한 교정. 실제 herdr agent --helpsend 가 없다. 기존 mock 이 존재하지 않는 명령을 성공시켜 ISSUE-1 을 은폐하고 있었다.
agent prompt 가 미매칭 시 exit 1 (기존: 항상 ok) 정확한 교정. 무조건 성공하던 mock 이 F-2b 검증을 불가능하게 만들고 있었다.
pane send-text / pane read / pane rename 추가 신규 코드 경로가 실제로 사용하는 명령이며, agents/panes 양쪽 저장소를 모두 조회하는 구현이 shim 의 폴백 구조와 대칭이다.
pane list 를 agents panes 병합 + pane_id 중복 제거 로 변경 필요한 수정. 기존 if not panes_list: 조건부는 agent 가 하나라도 있으면 라벨 전용 패인을 통째로 감췄다 — H-16/H-18/H-23 이 검증하려는 시나리오 자체를 표현할 수 없었다.
save_state 가 동일 pane_id 를 append 대신 in-place 갱신 버그 수정. 기존 로직은 갱신을 무시(첫 항목 고정)했다. 기존 병렬 상태 경합 테스트(10-agent)도 여전히 통과한다.
monkeypatch.delenv("HERDR_WORKSPACE_ID") 필수. 호스트 환경 오염으로 인한 위양성/위음성 차단.

유실 검토: agent send 제거는 프로덕션 코드에서 해당 호출이 완전히 사라진 뒤에 이뤄졌으며(grep 결과 잔존 0건), 412 테스트 전량 통과가 이를 뒷받침한다. 기능 유실 없음.


4. 비차단 후속 과제 (Non-blocking / 관찰 사항)

머지를 막지 않으며, 별도 티켓으로 추적할 것을 권고한다.

N-1 (Low) — 영속 파일은 herdr 워크스페이스를 1개만 기억한다

_herdr_persist_ws_idnew-session 마다 파일을 덮어쓴다. 레이아웃 오버플로(W2b)로 하나의 MAM 워크스페이스가 herdr 워크스페이스 2개 이상을 소유하게 되면, 파일은 마지막 것만 가리킨다. 이 경우 _herdr_ws_scope 를 쓰는 pane list 폴백은 앞선 워크스페이스의 라벨 전용 패인을 찾지 못할 수 있다.

  • 완화 요인: agent get 경로(env-only 스코프)가 먼저 시도되므로 정상 등록된 에이전트는 영향받지 않는다. 영향 범위는 "다중 herdr 워크스페이스 + 라벨 전용 패인" 교집합으로 좁다.
  • 구현자가 이 트레이드오프를 _herdr_agent_get_scoped 주석에 명시적으로 문서화한 점은 적절하다.
  • 권고: 향후 단일 id 대신 id 목록(append + dedupe)으로 확장.

N-2 (Low) — workspace create 경로 패인에는 HERDR_WORKSPACE_ID 가 주입되지 않는다

pane split 에는 --env HERDR_WORKSPACE_ID= 가 추가되었으나, workspace create 는 생성 시점에 id 를 알 수 없어 주입이 불가능하다. 해당 패인에서 실행되는 에이전트는 env 없이 파일 스코프에만 의존한다.

  • WORKSPACE_ROOT 가 MAM 워크스페이스 단위이므로 일반적인 경우 올바르게 동작한다. 다만 N-1 과 결합하면 스코프가 흔들릴 수 있다.
  • 권고: workspace create 직후 pane set-env(지원 시)로 사후 주입.

N-3 (Low) — _resolve_herdr_target 의 agent-list 폴백이 pane_id 를 반환할 수 있다

print(a.get("pane_id") or name)

반환값 $tgt 는 이후 _real_herdr agent prompt "$tgt" 로 전달되는데, agent-level 명령은 통상 이름을 받는다. pane_id 가 반환되면 그 호출이 실패할 수 있다.

  • 본 변경분이 도입한 결함이 아니다 — 변경 전 코드도 print(pane_id or agent) 로 동일했다(기존 동작 보존). 또한 그 앞의 agent get 2단이 성공하는 정상 경로에서는 도달하지 않는다.
  • 권고: name 을 반환하도록 정리.

N-4 (Info) — _herdr_agent_get_scopedpane_id 가 빈 에이전트를 "부재"로 취급한다

헬퍼가 pane_id 비어있음 → return 1 이므로, 등록은 되었으나 pane_id 가 아직/이미 없는 에이전트(기동 중, 종료됨)는 존재하지 않는 것으로 판정된다. HERDR_WORKSPACE_ID 가 설정된 상태에서는 agent promptexit 1 로 끝난다.

  • 실무상 pane 없는 에이전트에 프롬프트를 넣는 것은 어차피 무의미하므로 현재로선 안전한 방향의 실패(fail-safe) 이다. 동작 변화로 기록만 해 둔다.

N-5 (Info) — handle_startup_dialogs 는 여전히 Yes, try it 을 bare grep 한다

F-1 은 _MAM_DIALOG_TOKENS(입력 차단용)에서만 토큰을 제거했다. handle_startup_dialogs 는 기동 창(기본 20s) 동안 산문에 같은 문자열이 있으면 Escape 를 보낼 수 있다.

  • 영향: 기동 직후 유휴 프롬프트에 Escape 1회 → 실질 무해. 또한 이 창은 에이전트가 아직 대화를 시작하기 전이라 산문 노출 확률이 매우 낮다.
  • 의도적 설계이며 테스트(test_fullscreen_modal_is_rejected_not_accepted)로 정탐이 고정되어 있다.

N-6 (Info) — shellcheck 미실행

본 환경에 shellcheck 가 없어 정적 린트를 bash -n(원본 + 생성 shim) 및 Bash 3.2 실측으로 대체했다. CI 게이트가 아니므로 차단하지 않으나, 향후 CI 에 shellcheck 를 추가하면 $env_flags 무인용 확장(SC2086) 등 기존 관용 패턴에 대한 명시적 예외 선언을 함께 정리할 수 있다.


5. 결론

  • 계획서 plan-fae58b93.mdF-1 / F-2b / F-3 / F-4 및 워크스페이스 세션 격리(ISSUE-1/2/3/5) 가 코드에 빠짐없이 반영되었음을 diff 전량 판독으로 확인했다.
  • 각 수정에 대해 동작 검증형 회귀 테스트(mock RPC 호출 로그 기반)와 소스 레벨 회귀 방지 테스트(옛 패턴 잔존 금지)가 쌍으로 추가되어, 향후 되돌림에 대한 방어가 이중으로 걸려 있다.
  • 테스트 하네스 변경은 통과를 위한 완화가 아니라 실제 herdr CLI 계약 쪽으로의 교정이며, 오히려 기존 mock 이 은폐하던 결함(존재하지 않는 agent send 의 무조건 성공)을 드러내는 방향이다.
  • 리뷰어 환경에서 412 passed(exit 0) 를 독립적으로 재현했다.
  • 잔여 항목(N-1 ~ N-6)은 전부 저위험 관찰 사항이며, 설계 변경이나 재작업 수준의 재계획을 요구하지 않는다. 따라서 [ESCALATE: PLANNER] 는 발행하지 않는다.

최종 승인한다.

[VERDICT: PASS]