[Bug] stall_watch 가 herdr 이름 변환 없이 원래 세션 이름으로 pane 을 찾아, 32자 초과·대문자 이름의 세션에서 멈춤 감지가 꺼진다 #66

Closed
opened 2026-10-20 13:20:19 +00:00 by Godopu · 2 comments
Owner

문제

세션 이름이 herdr 의 에이전트 이름 규칙(소문자 [a-z0-9_-], 영문자로 시작, 32자 이하)을 벗어나면, 그 세션에 위임한 잡의 stall_watch 가 pane 을 찾지 못합니다(stall_watch:agent_not_found). 이때 멈춤 감지가 꺼집니다.

  • 확인한 경우: #64 의 워크트리 creator(35자 이름)에 구현 잡을 위임했을 때 progress stall_watch:agent_not_found 알림이 나왔습니다. 잡은 정상 완료되었습니다.
  • 바뀌는 예: creator-agy-fix-issue-99-long-branch(36자)는 herdr 에서 creator-agy-fix-issue-9-aab161d1 로 등록됩니다.

원인

  • herdr 에 등록되는 이름은 lib_py/agents/sanitize.py::sanitize_herdr_agent_name() 의 결과입니다. 32자를 넘으면 앞 23자 + '-' + sha1 8자 가 됩니다.
  • MAM 의 다른 herdr 호출은 이 변환을 거칩니다. 예: lib.sh 의 _sanitize_herdr_agent_name, 턴 대기(lib.sh:2765).
  • stall_watch 만 변환하지 않습니다.
    • 위임 래퍼 start_stall_watch(multi-agent-mux-delegate-job:735)가 원래 세션 이름을 --target "${session#herdr:}" 로 넘깁니다.
    • lib_py/stall_watch.py 는 그 이름 그대로 herdr agent get/read/prompt(:179, :202, :207)와 watcher.wait_once(:326)를 부릅니다.

영향

  • 잡 진행·완료 판정·리뷰 루프에는 영향이 없습니다. stall_watch 는 알리기만 하고 잡을 닫지 않습니다(#30).
  • 잃는 것:
    • 대화상자에 걸렸을 때의 progress stalled:blocked
    • 오래 놀 때의 progress stalled:idle 과 재촉 메시지 1회
  • stall_watch 는 MAM_STALL_HERDR_FAIL_S(기본 120 s) 뒤 herdr 사용 불가로 보고 exit 2 로 끝납니다. 그 뒤 멈춘 잡은 무응답 시간 초과로만 닫힙니다.
  • 이름이 길어지기 쉬운 곳:
    • 워크트리 creator (이슈 번호·브랜치 이름이 붙음)
    • 기본 이름 <상위폴더>-<폴더>-creator-<agent> (흔히 32자 초과)
    • 대문자·. 가 들어간 --name

제안

  • 수정 위치: --name 길이 제한은 쓰지 않습니다. 기본 이름이 이미 32자를 넘고, 대문자·특수문자·기존 행·resume 경로가 남기 때문입니다.
    • 대신 stall_watch 가 herdr 를 부를 때 sanitize_herdr_agent_name(target) 을 씁니다(main 에서 한 번).
    • 로그와 알림에는 원래 세션 이름을 그대로 씁니다.
  • 회귀 테스트:
    • 32자를 넘는 세션 이름, 대문자가 든 세션 이름으로 위임할 때 stall_watch 가 herdr 를 변환된 이름으로 부른다(mock herdr 호출 기록으로 확인).
    • agent_not_found 가 나오지 않는다.
    • 변환이 필요 없는 이름은 그대로다.
  • (선택) create 경고: create_session.sh 가 이름이 바뀔 때 "herdr 에서는 <변환된 이름>" 을 한 줄 출력합니다.
## 문제 세션 이름이 herdr 의 에이전트 이름 규칙(소문자 `[a-z0-9_-]`, 영문자로 시작, 32자 이하)을 벗어나면, 그 세션에 위임한 잡의 stall_watch 가 pane 을 찾지 못합니다(`stall_watch:agent_not_found`). 이때 멈춤 감지가 꺼집니다. - **확인한 경우**: #64 의 워크트리 creator(35자 이름)에 구현 잡을 위임했을 때 `progress stall_watch:agent_not_found` 알림이 나왔습니다. 잡은 정상 완료되었습니다. - **바뀌는 예**: `creator-agy-fix-issue-99-long-branch`(36자)는 herdr 에서 `creator-agy-fix-issue-9-aab161d1` 로 등록됩니다. ## 원인 - herdr 에 등록되는 이름은 `lib_py/agents/sanitize.py::sanitize_herdr_agent_name()` 의 결과입니다. 32자를 넘으면 `앞 23자 + '-' + sha1 8자` 가 됩니다. - MAM 의 다른 herdr 호출은 이 변환을 거칩니다. 예: `lib.sh` 의 `_sanitize_herdr_agent_name`, 턴 대기(`lib.sh:2765`). - stall_watch 만 변환하지 않습니다. - 위임 래퍼 `start_stall_watch`(`multi-agent-mux-delegate-job:735`)가 원래 세션 이름을 `--target "${session#herdr:}"` 로 넘깁니다. - `lib_py/stall_watch.py` 는 그 이름 그대로 `herdr agent get/read/prompt`(`:179`, `:202`, `:207`)와 `watcher.wait_once`(`:326`)를 부릅니다. ## 영향 - 잡 진행·완료 판정·리뷰 루프에는 영향이 없습니다. stall_watch 는 알리기만 하고 잡을 닫지 않습니다(#30). - 잃는 것: - 대화상자에 걸렸을 때의 `progress stalled:blocked` - 오래 놀 때의 `progress stalled:idle` 과 재촉 메시지 1회 - stall_watch 는 `MAM_STALL_HERDR_FAIL_S`(기본 120 s) 뒤 herdr 사용 불가로 보고 exit 2 로 끝납니다. 그 뒤 멈춘 잡은 무응답 시간 초과로만 닫힙니다. - 이름이 길어지기 쉬운 곳: - 워크트리 creator (이슈 번호·브랜치 이름이 붙음) - 기본 이름 `<상위폴더>-<폴더>-creator-<agent>` (흔히 32자 초과) - 대문자·`.` 가 들어간 `--name` ## 제안 - **수정 위치**: `--name` 길이 제한은 쓰지 않습니다. 기본 이름이 이미 32자를 넘고, 대문자·특수문자·기존 행·resume 경로가 남기 때문입니다. - 대신 stall_watch 가 herdr 를 부를 때 `sanitize_herdr_agent_name(target)` 을 씁니다(`main` 에서 한 번). - 로그와 알림에는 원래 세션 이름을 그대로 씁니다. - **회귀 테스트**: - 32자를 넘는 세션 이름, 대문자가 든 세션 이름으로 위임할 때 stall_watch 가 herdr 를 변환된 이름으로 부른다(mock herdr 호출 기록으로 확인). - `agent_not_found` 가 나오지 않는다. - 변환이 필요 없는 이름은 그대로다. - **(선택) create 경고**: `create_session.sh` 가 이름이 바뀔 때 "herdr 에서는 <변환된 이름>" 을 한 줄 출력합니다.
Author
Owner

작업 범위 (v4.10.0 기준 확인 후 확정)

확인 결과

  • 본문 진단이 v4.10.0 에서도 그대로 맞다.
    • 위임 래퍼 start_stall_watch(multi-agent-mux-delegate-job:736)가 원래 세션 이름을 --target 으로 넘긴다.
    • lib_py/stall_watch.py 는 그 이름 그대로 herdr 를 부른다.
      • HerdrSource(:157)의 agent get·agent read·agent prompt(:179, :202, :207)
      • watcher.wait_once(:326). 여기서 AGENT_NOT_FOUND 가 나와 stall_watch:agent_not_found 알림이 된다(:335).
  • 다른 경로는 변환한다. 턴 대기(wait_for_agent_idle)는 _sanitize_herdr_agent_name 을 먼저 부른다. lib.sh, reconcile.sh, status.sh, id_order.py 도 그렇다. Python 쪽에서 herdr 를 변환 없이 부르는 곳은 stall_watch 뿐이다.
  • 변환 예:
    • creator-agy-fix-issue-99-long-branch(36자) → creator-agy-fix-issue-9-aab161d1
    • Creator-Agy-01 → creator-agy-01
    • 기본 이름 형식 <상위폴더>-<폴더>-creator-agy 는 쉽게 32자를 넘는다.

이번에 고치는 것

  1. stall_watch 의 main 에서 한 번 sanitize_herdr_agent_name(target) 을 구하고, herdr 를 부르는 곳(HerdrSource, wait_once)에만 쓴다.
  2. 로그와 알림에는 원래 세션 이름을 그대로 쓴다.
  3. 에이전트 종류 판정(resolve_agent, :139)은 원래 이름으로 한다. 이 판정은 세션 이름 끝에서 종류를 읽는데, 변환된 이름은 끝이 해시라서 읽을 수 없기 때문이다.

하지 않는 것

  • --name 길이 제한: 본문 그대로, 쓰지 않는다.
  • create 경고(선택): 하지 않는다. stall_watch 가 변환된 이름을 쓰면 이름이 달라도 동작에 문제가 없다.

완료 조건 (회귀 테스트로)

  1. 32자를 넘는 세션 이름과 대문자가 든 세션 이름으로 위임할 때, stall_watch 가 herdr 의 agent get·agent read·agent prompt·agent wait 를 변환된 이름으로 부른다(mock herdr 호출 기록으로 확인).
  2. 그 경우 stall_watch:agent_not_found 가 나오지 않는다. 멈춤 감지(stalled:blocked, stalled:idle)가 동작한다.
  3. 로그와 알림에는 원래 세션 이름이 나온다.
  4. --agent 없이도 긴 이름의 에이전트 종류가 맞게 정해진다.
  5. 변환이 필요 없는 이름은 동작이 그대로다. tests/test_issue30_stall_watch.py, tests/test_issue30_stall_watch_stop.py 가 그대로 통과한다.

각 회귀 테스트는 base(v4.10.0) 에서 실패하고 수정 뒤 통과해야 한다.

제약

  • .mam.env 를 export 하지 않는다. 실제 .mam, 모니터, herdr 서버를 건드리지 않는다. 테스트는 mock herdr 로 하고 XDG_* 를 비우고 돌린다.
  • macOS(bash 3.2, Python 3.9)와 Linux 양쪽에서 돌아야 한다.
  • 버전 번호와 VERSIONS.md 는 건드리지 않는다. PR 본문은 Refs #66.
## 작업 범위 (v4.10.0 기준 확인 후 확정) ### 확인 결과 - 본문 진단이 v4.10.0 에서도 그대로 맞다. - 위임 래퍼 `start_stall_watch`(`multi-agent-mux-delegate-job:736`)가 원래 세션 이름을 `--target` 으로 넘긴다. - `lib_py/stall_watch.py` 는 그 이름 그대로 herdr 를 부른다. - `HerdrSource`(`:157`)의 `agent get`·`agent read`·`agent prompt`(`:179`, `:202`, `:207`) - `watcher.wait_once`(`:326`). 여기서 `AGENT_NOT_FOUND` 가 나와 `stall_watch:agent_not_found` 알림이 된다(`:335`). - 다른 경로는 변환한다. 턴 대기(`wait_for_agent_idle`)는 `_sanitize_herdr_agent_name` 을 먼저 부른다. `lib.sh`, `reconcile.sh`, `status.sh`, `id_order.py` 도 그렇다. Python 쪽에서 herdr 를 변환 없이 부르는 곳은 stall_watch 뿐이다. - 변환 예: - `creator-agy-fix-issue-99-long-branch`(36자) → `creator-agy-fix-issue-9-aab161d1` - `Creator-Agy-01` → `creator-agy-01` - 기본 이름 형식 `<상위폴더>-<폴더>-creator-agy` 는 쉽게 32자를 넘는다. ### 이번에 고치는 것 1. stall_watch 의 `main` 에서 한 번 `sanitize_herdr_agent_name(target)` 을 구하고, herdr 를 부르는 곳(`HerdrSource`, `wait_once`)에만 쓴다. 2. 로그와 알림에는 원래 세션 이름을 그대로 쓴다. 3. 에이전트 종류 판정(`resolve_agent`, `:139`)은 원래 이름으로 한다. 이 판정은 세션 이름 끝에서 종류를 읽는데, 변환된 이름은 끝이 해시라서 읽을 수 없기 때문이다. ### 하지 않는 것 - `--name` 길이 제한: 본문 그대로, 쓰지 않는다. - create 경고(선택): 하지 않는다. stall_watch 가 변환된 이름을 쓰면 이름이 달라도 동작에 문제가 없다. ### 완료 조건 (회귀 테스트로) 1. 32자를 넘는 세션 이름과 대문자가 든 세션 이름으로 위임할 때, stall_watch 가 herdr 의 `agent get`·`agent read`·`agent prompt`·`agent wait` 를 변환된 이름으로 부른다(mock herdr 호출 기록으로 확인). 2. 그 경우 `stall_watch:agent_not_found` 가 나오지 않는다. 멈춤 감지(`stalled:blocked`, `stalled:idle`)가 동작한다. 3. 로그와 알림에는 원래 세션 이름이 나온다. 4. `--agent` 없이도 긴 이름의 에이전트 종류가 맞게 정해진다. 5. 변환이 필요 없는 이름은 동작이 그대로다. `tests/test_issue30_stall_watch.py`, `tests/test_issue30_stall_watch_stop.py` 가 그대로 통과한다. 각 회귀 테스트는 base(v4.10.0) 에서 실패하고 수정 뒤 통과해야 한다. ### 제약 - `.mam.env` 를 export 하지 않는다. 실제 `.mam`, 모니터, herdr 서버를 건드리지 않는다. 테스트는 mock herdr 로 하고 `XDG_*` 를 비우고 돌린다. - macOS(bash 3.2, Python 3.9)와 Linux 양쪽에서 돌아야 한다. - 버전 번호와 VERSIONS.md 는 건드리지 않는다. PR 본문은 `Refs #66`.
Author
Owner

PR #70 병합 완료 (v4.10.1)

PR #70 을 리뷰하고 병합했습니다. merge commit 29cc4fd, 릴리스 커밋 04e3221.

바뀐 점

  • lib_py/stall_watch.py: herdr 를 부를 때(agent get·agent read·agent prompt·watcher.wait_once)만 sanitize_herdr_agent_name() 의 결과를 씁니다.
  • 로그·알림과 에이전트 종류 판정(resolve_agent)은 원래 세션 이름을 씁니다. 긴 이름은 변환되면 -<agent> 접미사가 해시로 바뀌기 때문입니다.
  • mock herdr 에 strict_agent_names 옵션이 생겼습니다. 켜면 실제 herdr 처럼 등록된 이름에만 답합니다. 기본은 꺼져 있습니다.

검증

  • 리뷰: 리뷰어 4명(claude·agy·grok·codex)이 1회차에서 모두 PASS 했습니다. lib.sh _sanitize_herdr_agent_name 과 Python 함수의 결과가 같은 것도 확인했습니다. 리포트는 .agents/reports/ 에 보관했습니다.
  • 회귀 테스트: tests/test_issue66_stall_watch_sanitized_name.py 7개 중 5개가 수정 전 코드(v4.10.0)에서 실패하고, 수정 후 모두 통과합니다.
  • macOS 전체 스위트 (Python 3.9.6, @bb496fd): 2105 passed, 56 skipped, 실패 0. 실제 herdr 서버 pane 목록, claude·opencode 데이터 폴더에 테스트가 남긴 것은 없었습니다.
  • Linux 전체 스위트: 작성자 확인 2140 passed, 20 skipped, 1 failed. 실패한 test_issue17_item4_decisions.py 는 정리 경합이고, 단독으로 돌리면 통과합니다. macOS 에서는 통과했습니다.

참고 (비차단, 이 PR 이전부터 있던 것)

lib.sh 에 _sanitize_herdr_agent_name 정의가 두 벌(:36, :293) 있습니다. 뒤의 정의가 적용되고, sha 도구가 없을 때의 대처만 다릅니다.

완료 조건을 확인했으므로 이 이슈를 닫습니다.

## PR #70 병합 완료 (v4.10.1) PR #70 을 리뷰하고 병합했습니다. merge commit `29cc4fd`, 릴리스 커밋 `04e3221`. ### 바뀐 점 - `lib_py/stall_watch.py`: herdr 를 부를 때(`agent get`·`agent read`·`agent prompt`·`watcher.wait_once`)만 `sanitize_herdr_agent_name()` 의 결과를 씁니다. - 로그·알림과 에이전트 종류 판정(`resolve_agent`)은 원래 세션 이름을 씁니다. 긴 이름은 변환되면 `-<agent>` 접미사가 해시로 바뀌기 때문입니다. - mock herdr 에 `strict_agent_names` 옵션이 생겼습니다. 켜면 실제 herdr 처럼 등록된 이름에만 답합니다. 기본은 꺼져 있습니다. ### 검증 - **리뷰**: 리뷰어 4명(claude·agy·grok·codex)이 1회차에서 모두 PASS 했습니다. lib.sh `_sanitize_herdr_agent_name` 과 Python 함수의 결과가 같은 것도 확인했습니다. 리포트는 `.agents/reports/` 에 보관했습니다. - **회귀 테스트**: `tests/test_issue66_stall_watch_sanitized_name.py` 7개 중 5개가 수정 전 코드(v4.10.0)에서 실패하고, 수정 후 모두 통과합니다. - **macOS 전체 스위트** (Python 3.9.6, @bb496fd): 2105 passed, 56 skipped, 실패 0. 실제 herdr 서버 pane 목록, claude·opencode 데이터 폴더에 테스트가 남긴 것은 없었습니다. - **Linux 전체 스위트**: 작성자 확인 2140 passed, 20 skipped, 1 failed. 실패한 `test_issue17_item4_decisions.py` 는 정리 경합이고, 단독으로 돌리면 통과합니다. macOS 에서는 통과했습니다. ### 참고 (비차단, 이 PR 이전부터 있던 것) lib.sh 에 `_sanitize_herdr_agent_name` 정의가 두 벌(:36, :293) 있습니다. 뒤의 정의가 적용되고, sha 도구가 없을 때의 대처만 다릅니다. 완료 조건을 확인했으므로 이 이슈를 닫습니다.
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#66