Files
multi-agent-mux/.agents/reports/planner-reviewer-claude-01/report-cd288bf2.md
T
GodopuandClaude Opus 5.5 e0181ea9be release(v4.8.8): Issue #17 follow-up - archive the review reports and bump the lockstep version
Merge-workspace review loop (--all-reviewer): round 1 (@d198dd5) claude
agy PASS, grok codex NOT PASS (the same inherited WORKSPACE_ROOT in eleven
more modules; test_orc_onboard's import-time env); fixed in 8b47cc7.
Round 2 claude grok NOT PASS (test_o2_race_free_lock, test_o1_rebuttal
missed), agy codex PASS; fixed in ac48cb7. Round 3 (@ac48cb7) 4/4 PASS.
Full suite at ac48cb7 on macOS / Python 3.9 / herdr 0.9.3 with
WORKSPACE_ROOT set to an empty sentinel: 1751 passed / 0 failed / 38
skipped; the sentinel stayed empty and the main checkout's shim was not
touched.

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

6.3 KiB

리뷰 리포트 — Job cd288bf2 (Issue #17 후속 2회차: 상속 WORKSPACE_ROOT, 6b00b6e..8b47cc7)

  • 리뷰어: planner-reviewer-claude-01 (claude)
  • 리뷰 identity: loop-20261008T133858Z-9e7f5b / base 6b00b6e / head 8b47cc7 / tree bfe5fcb — 검증 경로(…/2)에서 git rev-parse HEAD 'HEAD^{tree}' 일치, 미커밋 변경 없음
  • 범위: 커밋 2개(d198dd5 = 1회차, 8b47cc7 = grok·codex 지적 반영). conftest.py 의 own_workspace_root fixture + 테스트 파일 14개 + 새 tests/test_issue17_workspace_root_isolation.py(W1·W2). 제품 코드(.agents/skills)·버전·VERSIONS 변경 없음(브리프대로).

결론 요약

설계(opt-in fixture own_workspace_root, W1 가 모듈별 대표 노드를 체크아웃 사본에서 돌려 .mam 미생성을 고정, W2 가 test_orc_onboard 의 import 시점 root 전파를 고정)는 적절하고, 수정된 14개 파일·회귀 테스트·(a)(b) 실행은 모두 요구대로다. 그러나 조사(2)가 모듈 하나를 놓쳤다: tests/test_o2_race_free_lock.py 의 test_o2_12_run_loop_exits_on_lock_failure 는 HEAD 에서도 자신이 도는 체크아웃의 .mam/shim/herdr 를 쓴다(§3). 이 커밋의 제목("every test that sources lib.sh does it under its own WORKSPACE_ROOT")과 W1 의 전제("one test per module that sourced lib.sh … with the inherited root")에 어긋나는 같은 결함이며, 브리프가 리뷰어에게 직접 grep 으로 확인하라고 한 항목이다. 수정은 두 줄(§3)이고 재설계는 아니므로 ESCALATE 는 아니다.

1. 할 일 1·3·4 — 요구대로

  • _env(test_issue17_item4_decisions.py:224-233): 1회차 그대로(제외 + tmp_path 지정). lib.sh:26 이 미설정 시 체크아웃을 유도하므로 "지정"이 맞다.
  • 회귀 테스트: 1회차의 test_c_helpers_write_nothing_to_an_inherited_workspace 에 더해 W1·W2(새 파일). 수정 전 코드에서 실패 확인:
    • W1 상당: base(6b00b6e) 트리 사본 안에서 W1 의 NODES 13개를 WORKSPACE_ROOT=<사본> 으로 실행(24 passed) → 사본에 .mam/shim/herdr 생성됨(W1 의 written == [] 단언이 실패하는 조건).
    • W2 상당: base 의 test_orc_onboard 를 WORKSPACE_ROOT=<센티널> 로 import 한 뒤 run_find_uuid(ws, …) 호출 → 센티널에 .mam/shim/herdr 생성, ws 에는 없음(import 시점 root 전파 재현). HEAD 의 _scrubbed_env(root)(test_orc_onboard.py:24-29)는 호출 시점 root 를 쓴다.
  • (a)(b) 실행(검증 경로, 워크트리 .venv Python 3.9.6, env -i 로 HERDR_·MAM_·MQTT_* 제거):
실행 결과
(a) WORKSPACE_ROOT 없이: 수정 14개 파일 + test_issue33_budget, test_issue5_phase1_delegation, test_tier1_unit 643 passed / 0 failed (815 s)
(b) WORKSPACE_ROOT=<워크트리 밖 센티널>: 수정 14개 파일 490 passed / 0 failed (656 s); 실행 뒤 센티널 비어 있음
본 체크아웃 .mam/shim/herdr mtime 전후 동일(1791473441); 실제 .mam/jobs 항목 수 불변
  • 이식성: Python 테스트 코드만(3.9 문법); W1 은 git ls-files 와 nested pytest 로 이 Mac 에서 통과.

2. 할 일 2 — 설계 판단

  • conftest 의 pytest_configure(:139-148)는 다른 체크아웃을 가리키는 WORKSPACE_ROOT 만 지우고 이 체크아웃을 가리키면 남긴다(lib.sh 가 어차피 유도하는 값). 위험은 "이 체크아웃 자신"(에이전트 pane 에서 main 체크아웃으로 스위트를 돌릴 때 = 실제 워크스페이스)이며, 그 근본은 lib.sh:3088 이 source 시점마다 _init_herdr_isolation(:143-146) 으로 $WORKSPACE_ROOT/.mam/shim/herdr 를 쓰는 것이다(직접 확인: source lib.sh && find_workspace_uuid 만으로 센티널에 shim 생성).
  • own_workspace_root 를 autouse 로 두지 않은 이유(docstring: runner.py·mqtt_common 이 in-process 로 WORKSPACE_ROOT 를 읽음)는 타당하고, usefixtures 마크는 autouse 뒤·테스트 인자(mam_sandbox) 앞에 적용되므로 "mam_sandbox 와 테스트 자신의 지정이 이긴다"는 주장도 맞다. unittest.TestCase(test_workspace_scope)는 마크가 적용되지 않아 env 를 직접 지정한 것도 일관된다.
  • test_issue21_worktree_prereqs _mutate(:546-547)와 test_workspace_scope(:30-32)의 명시 지정, test_orc_onboard 의 _scrubbed_env 도 적절.

3. 놓친 모듈 (차단) — tests/test_o2_race_free_lock.py:196-203

196 def test_o2_12_run_loop_exits_on_lock_failure(tmp_path):
200     cmd = ["bash", str(RUN_LOOP), "--creator", "dummy-agent", "--task", "test"]
201     run_env = dict(os.environ)
203     res = subprocess.run(cmd, …, cwd=str(tmp_path), env=run_env)
  • run_loop.sh:17 이 lib.sh 를 source 하고, 이 테스트는 os.environ 을 그대로 물려주며(WORKSPACE_ROOT 미지정, cwd 만 tmp_path), 파일에 own_workspace_root 마크도 mam_sandbox 도 없다(:5 import pytest 는 이미 있음).
  • 재현(W1 과 같은 방법, HEAD 트리 사본): WORKSPACE_ROOT=<사본> 으로 이 테스트 1개 → 사본에 .mam/shim/herdr 생성; WORKSPACE_ROOT 미설정으로도 생성(lib.sh 가 체크아웃을 유도); 파일 전체(22 passed)도 생성. 같은 방법으로 돌린 내 다른 후보 11개 파일 40개 테스트(test_issue30_stall_watch_stop, test_issue36_prompt_transport, test_issue19, test_a4, test_issue21_acceptance, test_issue20, test_issue34, test_issue23_24, test_b4, test_issue15, test_issue10_13)는 모두 깨끗했다 — 놓친 것은 이 모듈뿐이다.
  • 따라서 W1 의 "every module whose shells used to inherit the root" 목록(NODES, test_issue17_workspace_root_isolation.py:26-40)이 불완전하고, 커밋 8b47cc7 의 제목이 참이 아니다.
  • 수정(같은 방식): test_o2_race_free_lock.py 에 pytestmark = pytest.mark.usefixtures("own_workspace_root") 추가(o2_13 의 mam_sandbox 는 그대로 이김), W1 NODES 에 tests/test_o2_race_free_lock.py::test_o2_12_run_loop_exits_on_lock_failure 추가. 그러면 W1 이 이 회귀를 앞으로 잡는다.

4. 비차단

  • W1 은 모듈당 대표 노드 1개만 돌리므로 같은 모듈의 다른 테스트가 새로 lib.sh 를 source 하면 잡지 못한다 — 마크가 모듈 전체에 걸리므로 현재 설계에서는 문제없지만, 목록 유지가 수동이라는 한계는 적어 둔다.
  • 1회차 표의 두 파일(test_b19, test_version_consistency)은 이번에 마크로 덮였다.

[VERDICT: NOT PASS]