범위는 #71 의 댓글 884(1–10항)와, 그것을 코드와 맞춰 보며 더한 보충(A–F)이다.
attach 명령 하나 (lib_py/agents/sanitize.pyattach_command)
형태는 herdr --session <server> agent attach <herdr 에 등록된 이름> 이다. default 도 적는다. 값은 shlex.quote 로 감싼다.
create·resume·reconcile 이 모두 이 함수를 쓴다.
lib.sh 래퍼의 herdr agent attach <원래 이름> 도 get/read/prompt 처럼 이름을 바꿔 부른다. 대상 뒤의 옵션(--takeover)은 그대로 넘긴다.
kill_command·start_command 삭제
새 행에 쓰지 않는다. status --json 의 start_command 키도 없어졌다.
래퍼의 new-session/kill-session 가짜 명령은 create·stop·reconcile 이 아직 쓰므로 남겼다.
사용자에게 보여 주던 날 kill-session 안내 두 곳(create exit 43, id_order.py 의 등록 전 종료)은 --herdr-session 을 붙인 stop 스킬 명령으로 바꿨다.
행이 없는 세션의 stop (stop_session.sh)
레지스트리에 행이 없으면 herdr 세션만 닫고 레지스트리는 바꾸지 않는다. --agent 가 없어도 된다.
herdr 가 기록한 그 에이전트의 cwd 가 이 작업 공간 안일 때만 닫는다. 다른 작업 공간의 세션은 exit 5, 서버에 없으면 exit 1, kill-session 뒤에도 살아 있으면 exit 6 이다. 모두 아무것도 바꾸지 않는다.
서버는 --herdr-session, 없으면 환경의 HERDR_SESSION_NAME, 없으면 작업 공간의 서버다(create 와 같은 순서).
레지스트리를 읽지 못하면(YAML 깨짐, DB 손상, DB 테이블 없음) "행 없음" 으로 보지 않고 exit 1 로 멈춘다. 이를 위해 load_state_json strict 를 더했다. 인자 없는 기존 읽기는 바뀌지 않았다.
--purge-conversation 은 행이 필요하므로 행이 없으면 exit 1 이다.
stop SKILL.md 의 종료 코드 표를 고쳤다.
이름 변환 규칙 하나 (lib.sh)
_sanitize_herdr_agent_name 정의를 하나로 합쳤다. 생성되는 shim 은 declare -f 로 같은 함수를 받는다.
has-session 의 lower()[:32] 대체 경로와 현재 폴더 기준 import 를 지웠다. lib.sh 가 계산한 이름을 넘긴다.
shasum·sha1sum·openssl 이 없으면 python3 로 같은 결과를 낸다. python3 도 없으면 오류로 멈추고, 00000000 을 붙인 틀린 이름을 쓰지 않는다. create·spawn 은 진행하지 않고, 조회는 실패를 알린다.
ASCII 가 아닌 이름, -n 같은 이름, 줄바꿈이 든 이름도 Python 함수와 결과가 같다.
레지스트리 형식 버전 2 (lib_py/registry_format.py, lib_py/atomic_yaml.py)
최상위 키 registry_format 을 둔다. 키가 없으면 1, 지금은 2 다.
레지스트리를 쓰는 함수가 잠금(BEGIN IMMEDIATE) 안에서, 호출자의 변경 전에 옛 형식을 바꾼다. 모든 행(stopped·terminated 포함)에서 두 필드를 지우고 attach_command 를 다시 만든다. 이때 YAML 도 반드시 다시 쓴다.
읽기(load_state_json)는 잠금 없는 읽기 전용 그대로다. 첫 쓰기 전까지는 status 에 옛 행이 보일 수 있다.
YAML 교체가 실패해 DB 만 2 가 된 경우, 다음 쓰기가 YAML 을 고친다.
#72 용 진입점: PYTHONPATH=.agents/skills python3 -m lib_py.registry_format --yaml <agent-sessions.yaml> → registry-format: <이전> -> <이후>, rows changed: <n>, 성공·이미 최신 exit 0, 오류는 0 이 아님. 계약은 모듈 docstring 에 있다.
stall_watch: herdr 이름을 StallWatch 에서 한 번만 구해 HerdrSource 에 넘긴다.
문서는 이 변경으로 틀리게 된 SKILL.md 줄만 고쳤고, tests/data/skill_code_blocks.json 의 핀을 따라 고쳤다.
버전 번호와 VERSIONS.md 는 바꾸지 않았다.
릴리스 노트에 넣을 것
레지스트리 행에서 kill_command·start_command 를 지웠다. attach_command 는 herdr --session <server> agent attach <herdr 이름> 이다.
레지스트리에 형식 버전(registry_format: 2)을 더했다. 옛 레지스트리는 첫 쓰기 때 바뀐다.
status --json 에서 start_command 키가 빠졌다.
세션 시작은 create·resume, 종료는 stop 스킬로 한다. attach 만 보기 전용이라 herdr 명령을 직접 쓴다.
병합 방법
merge commit 으로 병합해야 한다(squash 금지).tests/test_issue23_24_startup_path.py 의 S11 은 shim 비교 기준을 이 브랜치의 커밋 0fc162e 로 둔다. squash 하면 그 커밋이 없어 S11 이 건너뛰어진다.
검증
리뷰: --plan-file --all-reviewer --max-loop 3 루프에서 3회차까지 리뷰어 한 명의 NOT PASS 가 남았다(엄격 읽기가 "테이블 없음" 을 넘김). 그것을 커밋 하나(5f60653)로 고친 뒤 --review-only 로 다시 돌려, 리뷰어 4명이 모두 PASS 를 냈다(5f60653).
회귀: tests/test_issue71_herdr_names.py 70개.
create·resume·reconcile 이 쓰는 attach_command(32자 초과·대문자·default 포함), 래퍼 attach 의 변환(mock herdr strict_agent_names), 해시 도구별·도구 없음·python3 없음, 마이그레이션(순수·멱등·YAML 과 DB 일치·진입점 출력·재시도 복구), 행 없는 stop(닫음·다른 작업 공간 거부·없음·읽기 실패 거부), stall_watch 이름 한 곳, 정리 안내.
base(29cc4fd)에서는 68개가 실패한다. 통과하는 2개는 이름 변환 전제를 확인하는 테스트와, 변환이 필요 없는 이름의 래퍼 attach 다.
지운 필드를 확인하던 테스트는 지우지 않고 다른 확인으로 바꿨다.
test_issue50_pane_lock.py: create 가 쓴 행이라는 증거를 start_command 대신 session_id_source 로 본다(모니터 등록 행에는 없다).
test_issue21_worktree_prereqs.py: 제어 루트 경로가 새지 않는지를 attach_command 에서 본다.
test_tier2_component.py: 새 attach 형태와 두 필드가 없음을 본다.
tests/test_issue66_stall_watch_sanitized_name.py 는 바꾸지 않았고 그대로 통과한다.
전체 스위트(Linux, Python 3.14): 5f60653 에서 2211 passed, 20 skipped, 0 failed.
비차단 / 남은 것
macOS(bash 3.2, Python 3.9)에서는 아직 돌리지 않았다. bash 4 전용 문법을 쓰지 않았는지와 Python 3.9 문법만 확인했다.
Refs #71
## 변경
범위는 #71 의 댓글 884(1–10항)와, 그것을 코드와 맞춰 보며 더한 보충(A–F)이다.
- **attach 명령 하나 (`lib_py/agents/sanitize.py` `attach_command`)**
- 형태는 `herdr --session <server> agent attach <herdr 에 등록된 이름>` 이다. `default` 도 적는다. 값은 `shlex.quote` 로 감싼다.
- create·resume·reconcile 이 모두 이 함수를 쓴다.
- lib.sh 래퍼의 `herdr agent attach <원래 이름>` 도 `get/read/prompt` 처럼 이름을 바꿔 부른다. 대상 뒤의 옵션(`--takeover`)은 그대로 넘긴다.
- **`kill_command`·`start_command` 삭제**
- 새 행에 쓰지 않는다. `status --json` 의 `start_command` 키도 없어졌다.
- 래퍼의 `new-session`/`kill-session` 가짜 명령은 create·stop·reconcile 이 아직 쓰므로 남겼다.
- 사용자에게 보여 주던 날 `kill-session` 안내 두 곳(create exit 43, `id_order.py` 의 등록 전 종료)은 `--herdr-session` 을 붙인 stop 스킬 명령으로 바꿨다.
- **행이 없는 세션의 stop (`stop_session.sh`)**
- 레지스트리에 행이 없으면 herdr 세션만 닫고 레지스트리는 바꾸지 않는다. `--agent` 가 없어도 된다.
- herdr 가 기록한 그 에이전트의 cwd 가 이 작업 공간 안일 때만 닫는다. 다른 작업 공간의 세션은 exit 5, 서버에 없으면 exit 1, kill-session 뒤에도 살아 있으면 exit 6 이다. 모두 아무것도 바꾸지 않는다.
- 서버는 `--herdr-session`, 없으면 환경의 `HERDR_SESSION_NAME`, 없으면 작업 공간의 서버다(create 와 같은 순서).
- 레지스트리를 읽지 못하면(YAML 깨짐, DB 손상, DB 테이블 없음) "행 없음" 으로 보지 않고 exit 1 로 멈춘다. 이를 위해 `load_state_json strict` 를 더했다. 인자 없는 기존 읽기는 바뀌지 않았다.
- `--purge-conversation` 은 행이 필요하므로 행이 없으면 exit 1 이다.
- stop SKILL.md 의 종료 코드 표를 고쳤다.
- **이름 변환 규칙 하나 (`lib.sh`)**
- `_sanitize_herdr_agent_name` 정의를 하나로 합쳤다. 생성되는 shim 은 `declare -f` 로 같은 함수를 받는다.
- `has-session` 의 `lower()[:32]` 대체 경로와 현재 폴더 기준 import 를 지웠다. lib.sh 가 계산한 이름을 넘긴다.
- `shasum`·`sha1sum`·`openssl` 이 없으면 python3 로 같은 결과를 낸다. python3 도 없으면 오류로 멈추고, `00000000` 을 붙인 틀린 이름을 쓰지 않는다. create·spawn 은 진행하지 않고, 조회는 실패를 알린다.
- ASCII 가 아닌 이름, `-n` 같은 이름, 줄바꿈이 든 이름도 Python 함수와 결과가 같다.
- **레지스트리 형식 버전 2 (`lib_py/registry_format.py`, `lib_py/atomic_yaml.py`)**
- 최상위 키 `registry_format` 을 둔다. 키가 없으면 1, 지금은 2 다.
- 레지스트리를 쓰는 함수가 잠금(`BEGIN IMMEDIATE`) 안에서, 호출자의 변경 전에 옛 형식을 바꾼다. 모든 행(`stopped`·`terminated` 포함)에서 두 필드를 지우고 `attach_command` 를 다시 만든다. 이때 YAML 도 반드시 다시 쓴다.
- 읽기(`load_state_json`)는 잠금 없는 읽기 전용 그대로다. 첫 쓰기 전까지는 status 에 옛 행이 보일 수 있다.
- YAML 교체가 실패해 DB 만 2 가 된 경우, 다음 쓰기가 YAML 을 고친다.
- #72 용 진입점: `PYTHONPATH=.agents/skills python3 -m lib_py.registry_format --yaml <agent-sessions.yaml>` → `registry-format: <이전> -> <이후>, rows changed: <n>`, 성공·이미 최신 exit 0, 오류는 0 이 아님. 계약은 모듈 docstring 에 있다.
- **stall_watch**: herdr 이름을 `StallWatch` 에서 한 번만 구해 `HerdrSource` 에 넘긴다.
- 문서는 이 변경으로 틀리게 된 SKILL.md 줄만 고쳤고, `tests/data/skill_code_blocks.json` 의 핀을 따라 고쳤다.
- 버전 번호와 VERSIONS.md 는 바꾸지 않았다.
## 릴리스 노트에 넣을 것
- 레지스트리 행에서 `kill_command`·`start_command` 를 지웠다. `attach_command` 는 `herdr --session <server> agent attach <herdr 이름>` 이다.
- 레지스트리에 형식 버전(`registry_format: 2`)을 더했다. 옛 레지스트리는 첫 쓰기 때 바뀐다.
- `status --json` 에서 `start_command` 키가 빠졌다.
- 세션 시작은 create·resume, 종료는 stop 스킬로 한다. attach 만 보기 전용이라 herdr 명령을 직접 쓴다.
## 병합 방법
- **merge commit 으로 병합해야 한다(squash 금지).** `tests/test_issue23_24_startup_path.py` 의 S11 은 shim 비교 기준을 이 브랜치의 커밋 `0fc162e` 로 둔다. squash 하면 그 커밋이 없어 S11 이 건너뛰어진다.
## 검증
- 리뷰: `--plan-file --all-reviewer --max-loop 3` 루프에서 3회차까지 리뷰어 한 명의 NOT PASS 가 남았다(엄격 읽기가 "테이블 없음" 을 넘김). 그것을 커밋 하나(`5f60653`)로 고친 뒤 `--review-only` 로 다시 돌려, 리뷰어 4명이 모두 PASS 를 냈다(`5f60653`).
- 회귀: `tests/test_issue71_herdr_names.py` 70개.
- create·resume·reconcile 이 쓰는 `attach_command`(32자 초과·대문자·`default` 포함), 래퍼 attach 의 변환(mock herdr `strict_agent_names`), 해시 도구별·도구 없음·python3 없음, 마이그레이션(순수·멱등·YAML 과 DB 일치·진입점 출력·재시도 복구), 행 없는 stop(닫음·다른 작업 공간 거부·없음·읽기 실패 거부), stall_watch 이름 한 곳, 정리 안내.
- base(29cc4fd)에서는 68개가 실패한다. 통과하는 2개는 이름 변환 전제를 확인하는 테스트와, 변환이 필요 없는 이름의 래퍼 attach 다.
- 지운 필드를 확인하던 테스트는 지우지 않고 다른 확인으로 바꿨다.
- `test_issue50_pane_lock.py`: create 가 쓴 행이라는 증거를 `start_command` 대신 `session_id_source` 로 본다(모니터 등록 행에는 없다).
- `test_issue21_worktree_prereqs.py`: 제어 루트 경로가 새지 않는지를 `attach_command` 에서 본다.
- `test_tier2_component.py`: 새 attach 형태와 두 필드가 없음을 본다.
- `tests/test_issue66_stall_watch_sanitized_name.py` 는 바꾸지 않았고 그대로 통과한다.
- 전체 스위트(Linux, Python 3.14): `5f60653` 에서 2211 passed, 20 skipped, 0 failed.
## 비차단 / 남은 것
- macOS(bash 3.2, Python 3.9)에서는 아직 돌리지 않았다. bash 4 전용 문법을 쓰지 않았는지와 Python 3.9 문법만 확인했다.
- 업데이트 직후 진입점을 부르는 일은 #72 에서 한다.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- One _sanitize_herdr_agent_name: the shim gets lib.sh's definition through
`declare -f` instead of a second copy. Without shasum/sha1sum/openssl it
hashes with python3 (same result as lib_py.agents.sanitize); with none of
them it fails instead of truncating or appending 00000000.
- Every caller stops on that failure: new-session before any pane is made,
the lookups report failure, and has-session takes the name lib.sh computed
(the cwd-relative import and its lower()[:32] fallback are gone).
- `herdr agent attach <name>` through the shim resolves the target like
get/read/prompt; options after the target are kept.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
StallWatch converts --target once and hands the name to HerdrSource, so
agent get/read/prompt and agent wait cannot call herdr by different names.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- lib_py/registry_format.py: a pure, idempotent migrate() drops
kill_command/start_command and rebuilds attach_command on every row
(stopped/terminated included) and sets the top-level registry_format key.
- atomic_dump_yaml migrates an older registry under its lock, before the
caller's mutation, and then rewrites the YAML as well as the DB (the YAML
write is otherwise skipped when only fields change). load_state_json stays
read-only. New registries are written with the current version.
- Entry point for #72: `python -m lib_py.registry_format --yaml <path>` runs
the migration through the writer and prints
`registry-format: <from> -> <to>, rows changed: <n>`.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- attach_command is `herdr --session <server> agent attach <herdr name>`
(`default` written too), built by lib_py.agents.sanitize.attach_command;
create, resume and reconcile all use it. kill_command and start_command
are no longer written, and status --json drops start_command.
- The two raw kill-session hints (create exit 43, id_order's orphan) print a
stop-skill command with --herdr-session instead.
- stop_session.sh closes a session that has no registry row, herdr only and
without --agent, when herdr runs it inside this workspace; another
workspace's session is refused (exit 5), a missing one is exit 1, one that
survives kill-session is exit 6. The registry is not changed.
- Docs: only the SKILL.md lines these changes made wrong; the skill block
pins follow. Tests that asserted the removed fields keep their intent
(issue50: create's own row; issue21: no control-root path in
attach_command; tier2: the new form and the absent fields). S11 pins the
shim to 4243da5, which changed it on purpose.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tr/sed lowercase differently from str.lower() outside ASCII, so a name
like "İstanbul-creator-claude" was started as x--stanbul-... while the
row's attach_command named i-stanbul-.... A non-ASCII name is now
lowercased and replaced by python3 (fail closed without it), and the
name is read with printf, not echo ("-n" no longer vanishes).
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With no --herdr-session the server is chosen as create_session.sh chose
it (HERDR_SESSION_NAME, else the workspace's), not always derived from
the workspace. The row-less path runs only when the lookup says the row
is missing (exit 7); any other lookup failure stops with exit 1 as
before. Pins of the shifted stop_session.sh lines updated.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The writer commits the migrated DB before it replaces the YAML. If that
replacement failed, the DB said format 2 and the next run did nothing.
When the DB is current the writer now also reads the YAML's format and
rewrites a YAML that is older or missing.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- create with a non-ASCII name: the attach target is the name herdr has;
bash/Python parity for non-ASCII and option-like names; no python3 is
an error for a non-ASCII name.
- row-less stop without --herdr-session uses HERDR_SESSION_NAME; an
unreadable row is not taken for no row.
- a retry (entry point, or any write) repairs a YAML a failed migration
left in format 1.
- tier3: the "cannot infer agent" case registers its row, as tier1 does.
- S11: base re-pinned to 5cd72d2, which changes the shim's sanitize body.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The ASCII branch of _sanitize_herdr_agent_name translates line breaks
before sed (line by line) and $(...) (drops a trailing one) can lose
them: "newline-creator-claude\n" was started as newline-creator-claude
while its attach_command named newline-creator-claude-.
- `load_state_json strict` exits 1 (stderr) when the YAML or DB cannot be
read instead of printing {}; without the argument nothing changes.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
load_state_json printed {} on a YAML/DB read error, so a registered
session was closed row-less (exit 0) and its stop workflow skipped.
stop now reads the registry strictly and exits 1 before any herdr call.
Pins of the shifted stop_session.sh lines updated.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- parity and create with real line breaks in the name;
- stop with malformed YAML (no DB) or a corrupt DB refuses (exit 1);
- test_layout: the shim heredoc anchor follows the { ... } > "$tmp_file"
form (the rule it checks is unchanged);
- S11: base re-pinned to 0fc162e, which changes the shim's sanitize body.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A DB without its sessions table (or without both tables) was read as an
empty registry in strict mode, so stop closed a registered session
row-less and exited 0. Strict mode now fails on any OperationalError;
the non-strict reader is unchanged.
Refs #71
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Refs #71
변경
범위는 #71 의 댓글 884(1–10항)와, 그것을 코드와 맞춰 보며 더한 보충(A–F)이다.
lib_py/agents/sanitize.pyattach_command)herdr --session <server> agent attach <herdr 에 등록된 이름>이다.default도 적는다. 값은shlex.quote로 감싼다.herdr agent attach <원래 이름>도get/read/prompt처럼 이름을 바꿔 부른다. 대상 뒤의 옵션(--takeover)은 그대로 넘긴다.kill_command·start_command삭제status --json의start_command키도 없어졌다.new-session/kill-session가짜 명령은 create·stop·reconcile 이 아직 쓰므로 남겼다.kill-session안내 두 곳(create exit 43,id_order.py의 등록 전 종료)은--herdr-session을 붙인 stop 스킬 명령으로 바꿨다.stop_session.sh)--agent가 없어도 된다.--herdr-session, 없으면 환경의HERDR_SESSION_NAME, 없으면 작업 공간의 서버다(create 와 같은 순서).load_state_json strict를 더했다. 인자 없는 기존 읽기는 바뀌지 않았다.--purge-conversation은 행이 필요하므로 행이 없으면 exit 1 이다.lib.sh)_sanitize_herdr_agent_name정의를 하나로 합쳤다. 생성되는 shim 은declare -f로 같은 함수를 받는다.has-session의lower()[:32]대체 경로와 현재 폴더 기준 import 를 지웠다. lib.sh 가 계산한 이름을 넘긴다.shasum·sha1sum·openssl이 없으면 python3 로 같은 결과를 낸다. python3 도 없으면 오류로 멈추고,00000000을 붙인 틀린 이름을 쓰지 않는다. create·spawn 은 진행하지 않고, 조회는 실패를 알린다.-n같은 이름, 줄바꿈이 든 이름도 Python 함수와 결과가 같다.lib_py/registry_format.py,lib_py/atomic_yaml.py)registry_format을 둔다. 키가 없으면 1, 지금은 2 다.BEGIN IMMEDIATE) 안에서, 호출자의 변경 전에 옛 형식을 바꾼다. 모든 행(stopped·terminated포함)에서 두 필드를 지우고attach_command를 다시 만든다. 이때 YAML 도 반드시 다시 쓴다.load_state_json)는 잠금 없는 읽기 전용 그대로다. 첫 쓰기 전까지는 status 에 옛 행이 보일 수 있다.PYTHONPATH=.agents/skills python3 -m lib_py.registry_format --yaml <agent-sessions.yaml>→registry-format: <이전> -> <이후>, rows changed: <n>, 성공·이미 최신 exit 0, 오류는 0 이 아님. 계약은 모듈 docstring 에 있다.StallWatch에서 한 번만 구해HerdrSource에 넘긴다.tests/data/skill_code_blocks.json의 핀을 따라 고쳤다.릴리스 노트에 넣을 것
kill_command·start_command를 지웠다.attach_command는herdr --session <server> agent attach <herdr 이름>이다.registry_format: 2)을 더했다. 옛 레지스트리는 첫 쓰기 때 바뀐다.status --json에서start_command키가 빠졌다.병합 방법
tests/test_issue23_24_startup_path.py의 S11 은 shim 비교 기준을 이 브랜치의 커밋0fc162e로 둔다. squash 하면 그 커밋이 없어 S11 이 건너뛰어진다.검증
--plan-file --all-reviewer --max-loop 3루프에서 3회차까지 리뷰어 한 명의 NOT PASS 가 남았다(엄격 읽기가 "테이블 없음" 을 넘김). 그것을 커밋 하나(5f60653)로 고친 뒤--review-only로 다시 돌려, 리뷰어 4명이 모두 PASS 를 냈다(5f60653).tests/test_issue71_herdr_names.py70개.attach_command(32자 초과·대문자·default포함), 래퍼 attach 의 변환(mock herdrstrict_agent_names), 해시 도구별·도구 없음·python3 없음, 마이그레이션(순수·멱등·YAML 과 DB 일치·진입점 출력·재시도 복구), 행 없는 stop(닫음·다른 작업 공간 거부·없음·읽기 실패 거부), stall_watch 이름 한 곳, 정리 안내.29cc4fd)에서는 68개가 실패한다. 통과하는 2개는 이름 변환 전제를 확인하는 테스트와, 변환이 필요 없는 이름의 래퍼 attach 다.test_issue50_pane_lock.py: create 가 쓴 행이라는 증거를start_command대신session_id_source로 본다(모니터 등록 행에는 없다).test_issue21_worktree_prereqs.py: 제어 루트 경로가 새지 않는지를attach_command에서 본다.test_tier2_component.py: 새 attach 형태와 두 필드가 없음을 본다.tests/test_issue66_stall_watch_sanitized_name.py는 바꾸지 않았고 그대로 통과한다.5f60653에서 2211 passed, 20 skipped, 0 failed.비차단 / 남은 것
🤖 Generated with Claude Code
tr/sed lowercase differently from str.lower() outside ASCII, so a name like "İstanbul-creator-claude" was started as x--stanbul-... while the row's attach_command named i-stanbul-.... A non-ASCII name is now lowercased and replaced by python3 (fail closed without it), and the name is read with printf, not echo ("-n" no longer vanishes). Refs #71 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>- The ASCII branch of _sanitize_herdr_agent_name translates line breaks before sed (line by line) and $(...) (drops a trailing one) can lose them: "newline-creator-claude\n" was started as newline-creator-claude while its attach_command named newline-creator-claude-. - `load_state_json strict` exits 1 (stderr) when the YAML or DB cannot be read instead of printing {}; without the argument nothing changes. Refs #71 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>load_state_json printed {} on a YAML/DB read error, so a registered session was closed row-less (exit 0) and its stop workflow skipped. stop now reads the registry strictly and exits 1 before any herdr call. Pins of the shifted stop_session.sh lines updated. Refs #71 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>- parity and create with real line breaks in the name; - stop with malformed YAML (no DB) or a corrupt DB refuses (exit 1); - test_layout: the shim heredoc anchor follows the { ... } > "$tmp_file" form (the rule it checks is unchanged); - S11: base re-pinned to0fc162e, which changes the shim's sanitize body. Refs #71 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>