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 in8b47cc7. Round 2 claude grok NOT PASS (test_o2_race_free_lock, test_o1_rebuttal missed), agy codex PASS; fixed inac48cb7. Round 3 (@ac48cb7) 4/4 PASS. Full suite atac48cb7on 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
46 lines
6.3 KiB
Markdown
46 lines
6.3 KiB
Markdown
# 리뷰 리포트 — 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]
|