Files
multi-agent-mux/.agents/reports/planner-reviewer-claude-01/report-b48be8a6.md
T
GodopuandClaude Opus 5.5 7cf728e9f8 release(v4.9.4): the audit log follows a moved registry (Issue #57, PR #58) - archive the review reports and bump the lockstep version
Review loop (--review-only, --all-reviewer, focused on this Mac:
macOS, /usr/bin/python3 3.9.6, bash 3.2): round 1 (@63d8164) agy and
grok PASS, claude and codex NOT PASS (F1 paho via the /usr/bin/python3
fallback, F2 logs default path, R1 disk-fallback redispatch
interleaving, R2 symlinked registry), sent as a PR comment and fixed by
the author in four commits; round 2 (@a7cb90e) 4/4 PASS.

Full suite on macOS / Python 3.9.6 @a7cb90e: 1867 passed, 56 skipped,
1 error (the known #55 false positive: WAL/SHM of an agy conversation
running in another workspace). Real herdr panes and ~/.claude/projects
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
2026-10-15 22:52:04 +09:00

8.1 KiB

PR #58 (fix/issue-57) 병합 전 2차 리뷰 (job b48be8a6)

  • 리뷰어: planner-reviewer-claude-01 (Reviewer)
  • 리뷰 identity: loop-20261015T123502Z-1b9df6 / base e32c9574 .. head a7cb90e6 (커밋 15개; 1차 이후 대응 4개: 75c0042 F1, 151af99 F2, 1c598bb R1, a7cb90e R2) / tree 96c5c5f8
  • 검증 경로: /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261015T123502Z-1b9df6/1 — HEAD·tree 일치, git status --porcelain 0 줄, .mam 없음(시작·종료 모두). 본 체크아웃 HEAD e32c957(main) 변동 없음.
  • 환경: macOS, /usr/bin/python3 3.9.6(paho 없음; 이 Mac 의 PATH python3), 체크아웃 .venv 3.9.6(paho 2.1.0), PATH bash = /bin/bash 3.2.57.
  • 실행 안전: 테스트·탐침은 모두 env -i(PATH/HOME/LANG/TMPDIR 만, 필요한 값만 명시)로 브리프의 -u 목록 전부를 비웠고, basetemp 는 scratchpad 아래(이름에 "shim" 없음). 수동 재현은 scratchpad 또는 /tmp/jb48-r2(종료 후 삭제)의 임시 워크스페이스·cwd 에서만 했다. 수정 전 대조군은 git archive HEAD 복사본에 제품 파일만 되돌려 만들었다. 실제 .mam·.mam.env·모니터·herdr 서버·에이전트 홈 미접촉.

1. 1차 지적 4건 — 재현을 다시 돌린 결과

지적 1차 재현 (63d8164) head (a7cb90e) 수정 전 코드에서 회귀 테스트
F1 paho 없는 폴백에서 control_plane·status 실패 AGENT_PYTHON_BIN=/usr/bin/python3 로 mam_control_plane_json rc=1 ModuleNotFoundError: paho; get_job_status 예외 rc=0, 바인딩 JSON 에 로그 루트 포함; status.sh 의 get_job_status 두 복사본 모두 ('abc12345', 'unknown') test_control_plane_binding_works_without_paho, test_status_works_without_paho[json/text] 실패(paho 미존재로 control_plane·service import 실패)
F2 래퍼 logs 기본 경로가 cwd 상대 WORKSPACE_ROOT=ws, cwd=elsewhere 에서 logs --list 가 잡을 못 찾음 logs --list 가 ws 의 잡을 나열, logs <id> 에 registered 이벤트, --registry-dir 를 주면 그 레지스트리를 따름, elsewhere 에 아무것도 안 생김 test_logs_without_registry_dir_follows_the_workspace_from_any_cwd 실패((no logged jobs under …))
R1 디스크 폴백이 이후 디스패치의 terminal 을 이전 시도로 오인 (codex 지적) 감사 상태 채택 직전에 레코드를 다시 읽어 (dispatch_token, attempt_id, transition_seq) 가 처음 읽은 것과 같을 때만 채택 test_disk_fallback_rejects_a_terminal_that_belongs_to_a_later_dispatch 실패(B's completion was attributed to A)
R2 jobs 디렉터리가 심볼릭 링크일 때 submit 과 logs 불일치 (codex 지적) /tmp/jb48-r2/alias/jobs -> actual/jobs 로 submit --dry-run: 출력 경로·감사 로그 모두 actual/delegate_job_logs/<id>; logs --registry-dir alias/jobs 와 registry.py --registry-dir actual/jobs logs --list 가 같은 잡을 찾음 test_a_symlinked_registry_dir_resolves_to_one_audit_log 는 63d8164 에서는 logroot 부재로 ImportError 라 증거가 안 되므로, a7cb90e^ (logroot 있음, abspath 규칙) 로 다시 돌려 실패(…/alias/… ≠ …/actual/delegate_job_logs) 확인

2. 수정이 새 문제를 만들지 않았는가

F1 (모듈 이동)

  • lib_py/delegation/logroot.py 는 stdlib(os, typing)만 쓴다. mqtt_common 이 DEFAULT_REGISTRY_DIR·_workspace_mam_dir·default_registry_dir·get_logs_dir·sibling_logs_dir 를 그대로 재노출하므로 기존 import 경로(mqtt_common.get_logs_dir 등)는 불변이다.
  • from lib_py.delegation.logroot import … 는 패키지 __init__ 을 거쳐 daemon·service·registry·publish_event·publisher 까지 로드한다. 이 Mac 의 /usr/bin/python3 로 직접 import 해 보니 12 개 lib_py 모듈이 모두 올라오고 paho 는 로드되지 않았다. 직접 paho 를 import 하는 곳은 mqtt_common·publisher 둘뿐이고 둘 다 try/except ImportError 로 감쌌으며 from __future__ import annotations 라 -> mqtt.Client 주석도 import 시 평가되지 않는다. 실제로 브로커가 필요하면 make_client 가 명확한 ImportError 를 낸다.
  • eager import: logroot 는 eager.CORE_MODULES 에 없지만 목록에 있는 mqtt_common 이 import 시점에 로드하므로 동결 런타임에 함께 들어간다(아래 비차단 메모).

F2: local -a reg=() + ${reg[@]+"${reg[@]}"} 를 /bin/bash -u 로 직접 확인 — 빈 배열이면 인자 없음, 주어지면 --registry-dir <dir>. 래퍼의 다른 subcommand 는 바뀌지 않았다.

R1 (재읽기)

  • 경합: B 의 terminal 감사 상태는 재디스패치(레코드 토큰·seq 변경)가 커밋된 뒤에만 생긴다. 그러므로 감사 읽기에서 B 의 terminal 이 보였다면 레코드는 이미 그 전에 바뀌었고, 그 뒤의 재읽기가 반드시 차이를 본다. 재읽기 이후의 변경은 이미 읽은 감사 상태와 무관하다.
  • 같은 시도 안에서 정상 전이(A running → A completed)가 두 읽기 사이에 끼면 seq 가 달라져 "deferred" 로 한 라운드 늦어질 뿐이고, 다음 라운드는 레코드 자체의 terminal 을 읽는다.
  • 성능: 감사 상태가 terminal 이고 stale 이 아닐 때만 레코드 하나를 더 읽는다. 무시할 만하다.

R2 (realpath)

  • 기본 경로: WORKSPACE_ROOT=/tmp/...(macOS 에서 /tmp → /private/tmp)일 때 get_logs_dir() 은 이제 /private/tmp/.../.mam/delegate_job_logs 문자열을 돌려준다. 물리적으로는 이전과 같은 디렉터리임을 확인했다. 결과를 문자열로 비교하는 곳은 control_plane.forwarded_keys(이제 양쪽 모두 _abs=realpath)와 루프 러너의 제외 목록(runner.py 가 d.resolve().relative_to(root.resolve()))뿐이라 영향이 없다.
  • forwarded_keys 탐침: /tmp·/private/tmp 혼합 두 방향, 후행 /, 심볼릭 링크 alias 경유 모두 형제로 판정되어 전파하지 않는다. 비형제만 전파한다. 1차에서 비정규 입력이 "전파" 쪽으로 어긋나던 비대칭도 사라졌다.
  • from_env({"WORKSPACE_ROOT": "/tmp/..."}) 의 기본 바인딩은 defaults() 와 같아서, 평소 실행은 pane 에 아무것도 전파하지 않는다.
  • 레지스트리 디렉터리 자체가 심볼릭 링크인 경우에만 감사 로그가 링크 대상 옆으로 간다. 이는 R2 가 의도한 동작이며, 래퍼(pwd -P)와 바인딩(realpath)이 이미 그렇게 보고 있었다.

3. 이 Mac 정합성

  • 변경 py 15 개: ast.parse(feature_version=(3,9)) 와 /usr/bin/python3 -m py_compile 모두 통과. 3.10+ 문법·API 없음.
  • lib.sh·래퍼·status.sh: /bin/bash -n(3.2) 통과.

4. 테스트 (head, 검증 경로)

묶음 결과
A: issue57·15·21_acceptance·21_worktree_prereqs·tier1·20·17_item4·17_workspace_root_isolation·36·14 475 passed, 2 skipped
B: issue18·6_fail_closed·34·33·5_phase1/2a/2b/4_runtime·tier2·12·23_24·21_phase2·b7 493 passed

5_phase4_runtime 의 eager 모듈 검사도 통과했다. 어느 실행도 검증 경로에 .mam 을 남기지 않았고 #55 가드 오탐도 나오지 않았다.

5. 비차단 메모

  • lib_py.delegation.logroot 를 eager.CORE_MODULES 에 명시하면 의도가 분명해진다. 지금도 mqtt_common 을 통해 로드되므로 기능 문제는 없다.
  • paho 없이 publisher 의 브로커 경로를 직접 타면 make_client 의 ImportError 가 먼저 나는 구조다. 다른 진입점이 mqtt. 를 먼저 건드리면 AttributeError: 'NoneType' 로 보일 수 있지만, 브로커가 필요한 경로는 원래 paho 가 필수다.

결론

1차 지적 4건(F1·F2·R1·R2)이 모두 해소됐다. 1차 재현을 다시 돌려 확인했고, 각 회귀 테스트가 수정 전 코드에서 의도한 이유로 실패한다(R2 는 직전 부모 커밋 기준). 모듈 이동·재읽기·realpath 는 기본 경로, 바인딩·전파, 기존 import 경로에 새 문제를 만들지 않으며, 이 Mac 의 Python 3.9·bash 3.2 에서 정합하다.

[VERDICT: PASS]