세션 이름이 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 에서는 <변환된 이름>" 을 한 줄 출력합니다.
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 뿐이다.
stall_watch 의 main 에서 한 번 sanitize_herdr_agent_name(target) 을 구하고, herdr 를 부르는 곳(HerdrSource, wait_once)에만 쓴다.
로그와 알림에는 원래 세션 이름을 그대로 쓴다.
에이전트 종류 판정(resolve_agent, :139)은 원래 이름으로 한다. 이 판정은 세션 이름 끝에서 종류를 읽는데, 변환된 이름은 끝이 해시라서 읽을 수 없기 때문이다.
하지 않는 것
--name 길이 제한: 본문 그대로, 쓰지 않는다.
create 경고(선택): 하지 않는다. stall_watch 가 변환된 이름을 쓰면 이름이 달라도 동작에 문제가 없다.
완료 조건 (회귀 테스트로)
32자를 넘는 세션 이름과 대문자가 든 세션 이름으로 위임할 때, stall_watch 가 herdr 의 agent get·agent read·agent prompt·agent wait 를 변환된 이름으로 부른다(mock herdr 호출 기록으로 확인).
그 경우 stall_watch:agent_not_found 가 나오지 않는다. 멈춤 감지(stalled:blocked, stalled:idle)가 동작한다.
로그와 알림에는 원래 세션 이름이 나온다.
--agent 없이도 긴 이름의 에이전트 종류가 맞게 정해진다.
변환이 필요 없는 이름은 동작이 그대로다. 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`.
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 도구가 없을 때의 대처만 다릅니다.
완료 조건을 확인했으므로 이 이슈를 닫습니다.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
문제
세션 이름이 herdr 의 에이전트 이름 규칙(소문자
[a-z0-9_-], 영문자로 시작, 32자 이하)을 벗어나면, 그 세션에 위임한 잡의 stall_watch 가 pane 을 찾지 못합니다(stall_watch:agent_not_found). 이때 멈춤 감지가 꺼집니다.progress stall_watch:agent_not_found알림이 나왔습니다. 잡은 정상 완료되었습니다.creator-agy-fix-issue-99-long-branch(36자)는 herdr 에서creator-agy-fix-issue-9-aab161d1로 등록됩니다.원인
lib_py/agents/sanitize.py::sanitize_herdr_agent_name()의 결과입니다. 32자를 넘으면앞 23자 + '-' + sha1 8자가 됩니다.lib.sh의_sanitize_herdr_agent_name, 턴 대기(lib.sh:2765).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)를 부릅니다.영향
progress stalled:blockedprogress stalled:idle과 재촉 메시지 1회MAM_STALL_HERDR_FAIL_S(기본 120 s) 뒤 herdr 사용 불가로 보고 exit 2 로 끝납니다. 그 뒤 멈춘 잡은 무응답 시간 초과로만 닫힙니다.<상위폴더>-<폴더>-creator-<agent>(흔히 32자 초과).가 들어간--name제안
--name길이 제한은 쓰지 않습니다. 기본 이름이 이미 32자를 넘고, 대문자·특수문자·기존 행·resume 경로가 남기 때문입니다.sanitize_herdr_agent_name(target)을 씁니다(main에서 한 번).agent_not_found가 나오지 않는다.create_session.sh가 이름이 바뀔 때 "herdr 에서는 <변환된 이름>" 을 한 줄 출력합니다.작업 범위 (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-aab161d1Creator-Agy-01→creator-agy-01<상위폴더>-<폴더>-creator-agy는 쉽게 32자를 넘는다.이번에 고치는 것
main에서 한 번sanitize_herdr_agent_name(target)을 구하고, herdr 를 부르는 곳(HerdrSource,wait_once)에만 쓴다.resolve_agent,:139)은 원래 이름으로 한다. 이 판정은 세션 이름 끝에서 종류를 읽는데, 변환된 이름은 끝이 해시라서 읽을 수 없기 때문이다.하지 않는 것
--name길이 제한: 본문 그대로, 쓰지 않는다.완료 조건 (회귀 테스트로)
agent get·agent read·agent prompt·agent wait를 변환된 이름으로 부른다(mock herdr 호출 기록으로 확인).stall_watch:agent_not_found가 나오지 않는다. 멈춤 감지(stalled:blocked,stalled:idle)가 동작한다.--agent없이도 긴 이름의 에이전트 종류가 맞게 정해진다.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_*를 비우고 돌린다.Refs #66.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>접미사가 해시로 바뀌기 때문입니다.strict_agent_names옵션이 생겼습니다. 켜면 실제 herdr 처럼 등록된 이름에만 답합니다. 기본은 꺼져 있습니다.검증
_sanitize_herdr_agent_name과 Python 함수의 결과가 같은 것도 확인했습니다. 리포트는.agents/reports/에 보관했습니다.tests/test_issue66_stall_watch_sanitized_name.py7개 중 5개가 수정 전 코드(v4.10.0)에서 실패하고, 수정 후 모두 통과합니다.test_issue17_item4_decisions.py는 정리 경합이고, 단독으로 돌리면 통과합니다. macOS 에서는 통과했습니다.참고 (비차단, 이 PR 이전부터 있던 것)
lib.sh 에
_sanitize_herdr_agent_name정의가 두 벌(:36, :293) 있습니다. 뒤의 정의가 적용되고, sha 도구가 없을 때의 대처만 다릅니다.완료 조건을 확인했으므로 이 이슈를 닫습니다.