# PR #70 (Issue #66) 리뷰 — head bb496fd - 리뷰어: planner-reviewer-claude-01 (macOS, bash 3.2, /usr/bin/python3 3.9.6) - 검증 경로: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261025T023502Z-d6f876/1` - identity 확인: HEAD bb496fde785133ad1dbec288aa7431766efb6eb5, tree 15a72c9a1933c64018a2f2d9aa9707348905bb4d, `git status --porcelain --ignored` 비어 있음, `.mam` 없음 (시작·종료 시 모두). main HEAD 0461a63 그대로. - 범위: base 0461a63..bb496fd (커밋 1개). 바뀐 파일은 세 개다: `.agents/skills/lib_py/stall_watch.py`, `tests/conftest.py`, `tests/test_issue66_stall_watch_sanitized_name.py`. ## 1. 확인한 것과 근거 ### 1) 완료 조건 herdr 를 부르는 곳은 모두 변환된 이름을 쓴다. - `HerdrSource.__init__` 이 `self.name = sanitize_herdr_agent_name(target)` 를 만든다 (`stall_watch.py:162`). - 이 이름을 쓰는 곳: - `agent get` (:183) - `agent read` (:206) - `agent prompt` (:211) - `watcher.wait_once(self.herdr_name, …)` (:331, 값은 :229) - `pane process-info` 와 `pane read` (:187, :193)는 `agent get` 이 돌려준 pane_id 를 쓰므로 이름과 상관이 없다. - `--herdr-session` 은 서버 이름으로만 쓰인다. `self.session` (:159) 과 `session=self.args.herdr_session` (:331) 이고, 변환되지 않는다. 둘을 섞어 쓴 곳은 없다. 로그와 알림은 원래 이름을 쓴다. - 로그 :373 (blocked), :397 (입력창 비어 있지 않음), :406 (idle) 은 모두 `self.args.target` 이다. - 알림 상세(`stalled:idle`, `stalled:blocked …`)에는 이름이 들어가지 않는다. - 회귀 테스트는 `agent {target} idle for` 와 `agent {target} is blocked` 가 원래 이름으로 나오는지 확인한다 (test :85, :106). 변환이 필요 없는 이름(`creator-claude-t`)은 그대로이고, 그 경우의 테스트도 통과한다 (test :68 의 PLAIN). ### 2) 회귀 테스트: base 에서 실패, head 에서 통과 - head: 7 passed. - base(0461a63) 사본에 head 의 새 테스트와 conftest 를 넣고 돌리면 5 failed, 2 passed 다. - 실패: LONG, UPPER 두 이름 각각의 idle nudge 와 blocked 보고 (4개), 긴 codex 이름의 종류 판정 (1개). - 통과: strict mock 자체를 확인하는 테스트와, 변환이 필요 없는 PLAIN. ### 3) 변환 함수가 lib.sh 와 같은 결과를 내는가 lib.sh `_sanitize_herdr_agent_name` (:293-316) 과 `lib_py.agents.sanitize.sanitize_herdr_agent_name` 에 같은 이름 10개를 넣어 비교했다. - 비교한 이름: 그대로 둘 이름, 대문자, 32자 초과(루프 세션 이름 포함), 정확히 32자, 33자, 숫자로 시작, `.`·공백·`@`, 비 ASCII `Ü`, `_` 로 시작. - 결과: 10개 모두 같고, 두 번 변환해도 바뀌지 않는다. - 그래서 호출자가 이미 변환된 이름을 넘겨도 안전하다. - 호출자는 원래 세션 이름을 넘긴다: `multi-agent-mux-delegate-job:431`, `:615` → `start_stall_watch "$AGENT_SESSION"` 와 `"$current_session"`. ### 4) resolve_agent 를 원래 이름으로 하는 것이 맞는가 맞다. - 긴 이름은 변환되면 끝이 해시로 바뀐다. 예: `mam-wt-issue-66-very-long-creator-codex` → `…-`. 그래서 종류는 원래 접미사에서 읽어야 한다. - `HerdrSource` (:163) 과 `StallWatch` (:230) 둘 다 원래 이름을 쓴다. - 테스트 :111-129 가 `--agent ""` 일 때 codex 로 정해져 nudge 가 가는 것을 확인한다. - 종류를 변환된 이름에서 읽도록 바꾼 변이(m3)는 이 테스트에 잡힌다. ### 5) conftest `strict_agent_names` - 기본(키 없음)일 때 `_match_agent` 는 예전과 똑같이 네 가지 비교를 한다 (`conftest.py` 수정분 :473-476). get/read 의 실패 출력도 예전 문구 그대로다. 그래서 기존 테스트의 동작은 바뀌지 않는다. - 켜면 등록된 이름과 정확히 같을 때만 답하고, 아니면 `{"error":{"code":"agent_not_found"}}` 를 stderr 에 쓰고 exit 1 한다. 실제 herdr 처럼 등록 이름(변환된 이름)으로만 찾는다. - 테스트 :51-65 가 get, read, wait, prompt 네 명령 모두 원래 이름에는 agent_not_found 를, 변환된 이름에는 rc 0 을 내는지 확인한다. ### 6) macOS 호환 - `/usr/bin/python3` 3.9.6 으로 `lib_py.stall_watch` import 와 `resolve_agent` 호출이 된다. - 새 코드에 `X | Y`, `match`, tomllib 가 없다. 셸은 바뀌지 않았다. ### 7) test_issue17_item4_decisions::test_c_finalize_ends_with_an_unreaped_wrapper[broker_unavailable-3-0] 이 변경과 무관하다. - 이 테스트는 래퍼의 finalize 를 자체 shim(`PY=`)으로 돌린다. stall watcher 는 argv 를 기록하는 대역이다 (`tests/test_issue17_item4_decisions.py:218`). - conftest 의 mock herdr 와 `lib_py.stall_watch` 를 쓰지 않는다. - 판정 조건은 `took < 4.5` 와 terminate 뒤 레코드가 그대로인지 (:598-601) 로, 시간과 정리 단계에 의존한다. - 이 PR 이 바꾼 것(stall_watch 의 이름 변환, 기본 꺼짐인 mock 옵션)은 이 경로에 닿지 않는다. - 이 호스트에서도 통과했다(아래 표). ## 2. 실행한 테스트 모두 `env -i`, 임시 HOME/XDG, `PYTHONDONTWRITEBYTECODE=1 -p no:cacheprovider --basetemp=` 로 돌렸다. .mam.env 를 export 하지 않았다. | 대상 | 결과 | |---|---| | 검증 경로 `tests/test_issue66_stall_watch_sanitized_name.py` | 7 passed | | base 사본 + 새 테스트·conftest | 5 failed, 2 passed | | 검증 경로: test_issue30_stall_watch, test_issue30_stall_watch_stop, test_issue17_item4_decisions, test_tier2_component, test_issue63_same_cwd_ids, test_issue50_dispatch_herdr, test_c1_tui_readiness (mock herdr 를 쓰는 인접 테스트) | 457 passed, 1 skipped, 0 failed | 변이 테스트 (head 사본, issue66 테스트): | # | 변이 | 결과 | |---|---|---| | m1 | `wait_once` 를 원래 이름으로 | 잡힘 (5 failed) | | m2 | `agent prompt` 를 원래 이름으로 | 잡힘 (3 failed) | | m3 | 종류를 변환된 이름에서 판정 | 잡힘 (1 failed) | | m4 | blocked 로그를 변환된 이름으로 | 잡힘 (2 failed) | | m5 | `agent read` 를 원래 이름으로 | 잡힘 (3 failed) | 실제 herdr 서버(pid 19169 `herdr server`, 23492 `herdr --session multi-agent-mux server`)는 테스트 전후로 같다. ## 3. 차단 결함 없음. ## 4. 비차단 - **N1**: 변환된 이름을 두 곳에서 따로 만든다(`HerdrSource.name` :162, `StallWatch.herdr_name` :229). 주입된 source 를 쓰는 테스트 때문에 둘 다 필요해 보인다. 결과가 같으므로 동작에는 문제가 없다. - **N2** (기존, 이 PR 과 무관): `--agent` 가 비어 있고 이름이 `…-claude-01` 처럼 숫자로 끝나면 `resolve_agent` 는 종류를 정하지 못한다(None). 실제 호출자는 항상 `--agent "$AGENT"` 를 넘기므로 지금은 영향이 없다. - **N3** (기존, 이 PR 과 무관): lib.sh 에 `_sanitize_herdr_agent_name` 이 두 벌 있다(:36, :293). sha 도구가 없을 때의 대처가 서로 다르다(:36 은 32자로 자르고, :293 은 python3 로 해시). 이 호스트처럼 shasum 이 있으면 두 벌 모두 Python 판과 같다. [VERDICT: PASS]