Files
multi-agent-mux/.agents/reports/planner-reviewer-claude-01/report-af549b13.md
T

9.7 KiB

PR #69 (Issue #63) 리뷰 — head 1614af5

  • 리뷰어: planner-reviewer-claude-01 (macOS, bash 3.2, /usr/bin/python3 3.9.6)
  • 검증 경로: /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261023T035928Z-2ccc02/1
  • identity 확인: HEAD 1614af5b67, tree f1af6fdd54, git status --porcelain --ignored 비어 있음, .mam 없음 (시작·종료 시 모두). main HEAD dc886ec 그대로.
  • 범위: base dc886ec..1614af5 전체(커밋 13개).
    • ede9c62 까지는 이전 리뷰(잡 8445af7f, 55f86b49)에서, 8f64174·7cac6f6 은 잡 1c6eca2b 에서 봤다. 그 결론을 다시 확인했다.
    • 이번에는 1614af5 와 세 수정 사이의 정합성을 중점으로 봤다.
  • 참고: 같은 head 를 맡은 잡 906427d1 은 관련 스위트 도중 검증 경로(…a646cb/3)가 사라져 끝내지 못했다. 그 잡에서 얻은 head 결과(issue63 27 passed, 변이 결과)는 같은 tree 의 스크래치 사본에서 나온 것이다. diff -rq 로 이번 검증 경로와 같음을 확인했다.

1. 1614af5 가 바꾼 것

  • .agents/skills/lib_py/agents/id_order.py:223: elif sess == me or not sess: 를 elif not sess: 로 바꿨다.
    • 그래서 호출자 자신의 세션 이름에 남은 죽은 owner 마커도 고아 규칙을 따른다. 이번 시도의 행이 등록되면 지우고(:225), herdr 가 정상 목록으로 "없음"이라 답하면 지우고(:228-229), 그 밖에는 남긴다.
  • _read_and_prune_markers 의 me 인자를 지웠다(:183, :308).
  • blockers 는 ede9c62 부터 m_sess == me 를 건너뛰지 않는다(:136-144). 그래서 남은 자기 이름 마커가 실제로 막는다.

2. 세 수정이 각 지적을 닫는가, 서로 어긋나지 않는가

  1. 8f64174 — 조회 실패를 "없음"으로 읽던 문제
    • herdr_session_state (:58-86) 는 정상 파싱한 agent list 에 이름이 없을 때만 False 를 돌려준다. 그 밖에는 None 이다.
    • prune 은 drop = live is False (:228) 다.
    • 변이 m1(not live)과 m2(rc≠0 → False)가 테스트에 잡혔다(잡 1c6eca2b).
  2. 7cac6f6 — 상한 0 에서 30 초 조회, server_not_running
    • 조회 시간은 deadline - now 다(:288). timeout≤0 이면 None 을 돌려준다(:64-65).
    • 변이 m4(고정 30 s)와 m7(timeout≤0 에도 조회)이 잡혔다.
    • 상한 0 테스트는 0.3 s 안에 끝나는 것을 확인한다(test :1222-1224).
  3. 1614af5 — 같은 이름의 죽은 owner 마커를 확인 없이 지우던 문제
    • 옛 규칙(sess == me 이면 drop)을 되돌린 변이 사본에서는 두 테스트가 실패한다: test_id_order_dead_owner_marker_blocks_while_its_unregistered_herdr_session_is_alive, test_id_order_real_probe_against_mock_herdr_fails_closed.
    • 커밋 메시지가 말한 "재시도의 실패 정리가 살아 있는 pane 을 죽임"도 막힌다. create 의 대기(create_session.sh:287)는 롤백 trap 설치(:367)보다 앞서 있어서, 대기에서 거부(exit 1)되면 cleanup_herdr_on_error 가 돌지 않는다.
  4. 정합성: 세 수정은 모두 _read_and_prune_markers 의 "죽은 owner 마커" 분기 하나를 쓰고, 조회는 bounded_probe 하나를 거친다. 자기 이름 마커만 다른 규칙을 쓰던 예외가 사라져서 규칙이 하나로 모였다. 어긋나는 곳은 찾지 못했다.

3. 흔한 사용을 600 초 대기로 막지 않는가

스크래치에서 id_order.wait 를 프로세스 안에서 직접 불렀다. 조회 함수를 주입하고, cap 2 s(일부 0 s)로 돌렸다.

정상 사용 (실패 없음): 막지 않는다.

  • create 마커가 남은 채로, 그 세션이 다음 상태일 때 같은 이름으로 resume 했다:
    • stopped 이고 own id 가 기록됨
    • stopped 이고 id 없음 (herdr-dead stop)
    • reconcile 이 terminated 로 바꿈
  • 세 경우 모두 herdr 가 답하지 못해도(None), cap 0 에서도 rc=0 이었다.
  • blockers 의 pinned_for_attempt 와 ended_after_attempt (:158-171) 가 이 경우들을 걸러낸다.
  • 정상 create/resume 이 끝난 뒤의 마커는 행이 running 인 동안에는 _registered_for_attempt (:177-180) 로 지워진다.

실패 뒤 재시도:

경우 herdr 가 "없음" 응답 (서버 살아 있음) herdr 무응답 (서버 꺼짐 등)
create X 가 행 쓰기 전에 실패(exit 42 롤백) → create X 재시도 rc=0, 0.0 s rc=1, cap 만큼 대기
resume X 가 spawn 에서 실패(행 그대로) → resume X 재시도 rc=0, 0.0 s rc=1, cap 만큼 대기
위 resume 실패 → 같은 cwd 에서 create Y rc=0, 0.0 s rc=1, cap 만큼 대기
  • 7cac6f6 사본으로 같은 시뮬레이션을 돌리면 무응답 열의 위 두 줄(같은 이름 재시도)이 rc=0 이다.
  • 즉 1614af5 는 서버가 살아 있는 흔한 재시도는 그대로 두고, herdr 가 답하지 못하는 재시도만 막는다. 이는 아래 R1 이 같은 이름까지 넓어진 것이다.

4. 그 밖의 확인

브리프 항목 1·2·4·5·6·8(완료 조건 테스트, autopin 재사용, resume·stop, 지운 심볼, issue34 무관)은 1614af5 가 session_ids.py, lib.sh, 셸 스크립트, 문서를 건드리지 않으므로 이전 리뷰의 결론 그대로다.

macOS:

  • /usr/bin/python3 3.9.6 으로 lib_py.agents.id_order import 가 성공한다(잡 1c6eca2b; 1614af5 는 문법 요소를 더하지 않는다).
  • 잠금은 fcntl.flock 이다(:294-295).

실제 herdr 를 건드리지 않았는가:

  • 기존 서버 두 개(pid 3407 herdr server, 8323 herdr --session multi-agent-mux server)는 스위트 전후로 같다(시작 시각 08:21).
  • 스위트 중 13:22 에 herdr --session mam-pylecturenotes server 가 새로 보였다. 하지만 이 프로세스는 실제 HOME 과 WORKSPACE_ROOT=/Users/godopu16/PuKi/lac/curriculum/01_python_getting_started_lecturenotes 로 떠 있고, 사용자의 attach 클라이언트(13:27)가 붙어 있다. 테스트는 HOME 을 스크래치로 바꿔 돌므로 다른 작업 공간의 것이다.

5. 실행한 테스트

모두 env -i, 임시 HOME/XDG, PYTHONDONTWRITEBYTECODE=1 -p no:cacheprovider --basetemp=<scratchpad> 로 돌렸다. 테스트에서 .mam.env 를 export 하지 않았다.

대상 결과
검증 경로: tests/test_issue63_same_cwd_ids.py + 관련 19개 모듈 (issue40_auto_pin, issue64_ro_connect, issue10_13_purge, issue31_purge_residual, issue42_skill_blocks, tier1_unit, tier2_component, b4_session_created, issue24_resume_dialogs, issue30_stall_watch_stop, issue23_24_startup_path, issue45_restore, issue50_pane_lock, c1_tui_readiness, issue6_fail_closed, issue60_opencode_v2, issue60_linux_fixes, uuid_target, issue17_workspace_root_isolation) 597 passed, 2 skipped, 0 failed (32 분)
같은 tree 스크래치 사본: issue63 단독 27 passed
base 사본 + head 테스트 27 errors (ImportError: id_order). 조건별 base 실패는 1차에서 22 failed + 1 passed 로 확인했다
변이: 1614af5 를 되돌림(자기 이름 마커를 drop) 2 failed (위 두 테스트)

6. 차단 결함

없음.

7. 비차단

R1 (잡 1c6eca2b 의 R1, 범위가 넓어짐): herdr 가 답하지 못하는 고아 마커는 같은 폴더·같은 종류의 create/resume 을 매번 cap 동안 붙잡는다

  • 이제 같은 이름 재시도도 포함된다(위 표).
  • 서버가 꺼진 상태(server_not_running)가 대표적이다.
    • 조회는 서버를 띄우지 않는다(:67).
    • create/resume 은 대기를 통과해야 spawn 으로 서버를 띄운다(create_session.sh:287→:289, resume_session.sh:243→:260).
    • 그래서 다른 무언가가 서버를 켜기 전까지는 기본 600 s 를 기다린 뒤 거부가 반복된다.
  • 회복 경로는 있다: 메시지의 HERDR_SESSION_NAME=<srv> herdr kill-session -t <s> 를 shim 으로 실행하면 서버가 기동된다(잡 1c6eca2b 의 가짜 herdr 재현에서 --session srv-down server 1회).
  • 생기는 조건은 "행 등록 전 실패나 kill"에 "서버가 꺼짐"이 겹치는 경우다. 정상 사용과 서버가 살아 있는 재시도는 막지 않는다(3절).
  • 권고 (둘 중 하나):
    • (a) server_not_running 만은 "없음"으로 읽는다. MAM 서버는 restore 가 꺼져 있어서 꺼진 서버 위에는 살아 있는 pane 이 없다. lib.sh:204-207 의 ISSUE-9 규약과도 맞는다.
    • (b) 그 경우는 cap 을 기다리지 말고 바로 거부한다. 메시지는 "서버가 꺼져 있음 → 위 명령으로 정리"처럼 사실대로 쓴다.
  • fail-closed 를 택한 것은 루프에서 정한 설계 선택이라 차단으로 두지 않는다.

그 밖의 비차단 (잡 1c6eca2b 와 같음)

  • N1: 조회가 MAM_NO_AUTOSTART=1 을 쓴다는 것(:67)을 고정하는 테스트가 없다.
  • N2: sanitize 한 이름 비교(:85)를 고정하는 테스트가 없다.
  • N3: flock(LOCK_EX) 대기(:295)는 시간 제한이 없다. 다른 호출자가 앞 대기의 남은 시간만큼 더 기다릴 수 있다. 상한은 있다.
  • N4: create·resume SKILL.md 의 exit 1 설명이 고아 마커로 거부되는 경우와 그 정리 방법을 말하지 않는다.
  • N5: 이전 라운드의 비차단 항목이 남아 있다: resume mam_id_order_wait 제거가 테스트로 고정되지 않음, c6(b) 의 1.5 s 타이밍 flake, lib.sh --herdr-server 전달이 테스트되지 않음.

8. 결론

  • 1614af5 는 codex 의 3차 지적(같은 이름의 죽은 owner 마커를 확인 없이 지움)을 닫는다. 8f64174·7cac6f6 과 같은 고아 규칙 하나로 모였다.
  • 정상 create/resume 과 서버가 살아 있는 재시도는 막지 않는다.
  • herdr 가 답하지 못할 때 cap 동안 기다리는 비용(R1)은 회복 경로가 있는 설계 선택이므로 비차단이다.

[VERDICT: PASS]