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
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-09 05:01:05 +09:00
1 parent ac48cb7861
commit e0181ea9be
32 files changed
+1192 -26

No files matched your search

@@ -0,0 +1,114 @@
# Review — c20f3d1f
## Verdict
PASS. 이번 누적 변경에서 차단할 결함을 찾지 못했다. 이전 리뷰 9bc1f200의 R1(상속 환경으로 lib.sh를 source하는 다른 테스트 누락), R2(onboard의 import 시점 WORKSPACE_ROOT 캐시)는 수정되었다. 이 판정은 아래 정적 검토와 제한 환경 실행에 근거하며 전체 통합 스위트 통과를 뜻하지 않는다. 브리프가 허용한 대로 소켓/프로세스 조회 제한 자체를 NOT PASS 사유로 삼지 않았다.
## Review identity / scope
- loop: `loop-20261008T133858Z-9e7f5b`
- base: `6b00b6e06f55299cb60f156ccef09ede4bae5bdd`
- head: `8b47cc76eed4582b1848b2eec529523a61497320`
- tree: `bfe5fcbbefbde9562334515b4a9803bee96f84fd`
- 검증 cwd: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261008T133858Z-9e7f5b/2`
- 실행 Python: `/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux-wt/issue17-wsroot/.venv/bin/python` (Python 3.9).
- creator 작업 트리에서 실행하거나 소스를 수정하지 않았다. 검증 전후 identity가 일치하고 최종 `git status --porcelain`은 비어 있다. `git diff --check 6b00b6e HEAD` 통과. 변경 15개 Python 파일 AST 파싱 통과. 제품 코드 `.agents/skills`의 base..head diff는 없다.
## 요구사항 및 이전 지적 확인
1. `tests/test_issue17_item4_decisions.py:224`의 `_env`가 WORKSPACE_ROOT를 제외하고 테스트 tmp_path로 지정한다. 단순 unset이면 lib.sh가 checkout을 기본값으로 삼으므로 명시적 임시 경로가 맞다. 마지막 `extra` 적용은 테스트가 의도한 override를 유지한다.
2. `tests/conftest.py:180`의 opt-in `own_workspace_root`와 10개 모듈의 usefixtures 표시는 기존 mam_sandbox를 쓰지 않던 셸 테스트를 격리한다. 전역 autouse가 아니므로 WORKSPACE_ROOT 기본값을 검사하는 다른 Python 테스트를 일괄 변경하지 않는다.
3. 실제 conftest fixture를 등록한 별도 탐침에서 module fixture가 tmp_path/.mam-test-state/workspace를 설정하고, 명시적인 mam_sandbox가 그 뒤 자신의 root로 덮어쓰는 것을 각각 확인했다. 테스트 본문 monkeypatch도 이후 적용된다.
4. `tests/test_orc_onboard.py:19`에서 캐시의 WORKSPACE_ROOT를 제거하고 `:27`의 `_scrubbed_env`가 호출 시점의 root를 적용한다. run_onboard/run_find_uuid/run_verify_uuid/dump_state 및 inline 호출이 이 경로로 전환되었다. import 시점 sentinel을 이후 fixture root로 바꾸는 W2 탐침이 통과했다.
5. `tests/test_workspace_scope.py:31`은 unittest 경로를 자신의 ws_dir로 고정한다. `tests/test_issue21_worktree_prereqs.py:544`의 `_mutate`도 자신의 tmp root를 사용한다. 후자는 실제 mam_sandbox와 별도 sentinel을 사용한 탐침으로 검증했다.
6. 새 `tests/test_issue17_workspace_root_isolation.py:54` W1은 checkout 복사본과 real conftest를 사용하는 nested pytest로 이전 fallback-to-checkout 문제를 검사한다. nested pytest의 성공/통과 수를 요구하므로 환경 실패를 격리 성공으로 오인하지 않는다. W1 자체는 로컬 브로커가 필요하여 이 샌드박스에서 완주하지 않았으며 아래 표의 실행 결과에 포함하지 않았다.
7. 추가된 코드는 Python 3.9 AST 파싱 및 실제 실행을 통과했다. Bash 제품 로직이나 Bash 버전 의존 문법은 변경하지 않았다.
## 실행 결과와 한계
실험 전 HERDR_*, MAM_*, MQTT_*, SKS_*, WORKSPACE_ROOT 및 control-plane 경로 환경을 제거하고 HOME을 테스트별 임시 디렉터리로 설정했다. 모든 pytest 실행은 bytecode/cache 쓰기를 끄고 별도 임시 basetemp를 썼다. 실제 .mam.env 값을 읽어 export하거나 출력하지 않았다.
정상 conftest의 session-autouse local MQTT broker는 sandbox의 socket bind 제한 때문에 사용할 수 없다. `/tmp/c20f3d1f-run.py`는 검증 트리의 실제 conftest를 import하고 **local_mqtt_broker fixture만 메모리에서 제외**한 뒤 `pytest.main(..., --noconftest, plugins=[module])`를 실행한다. 나머지 fixture, 환경 처리 hook, 상태 guard는 유지했다. 이는 수정하지 않은 전체 스위트 실행과 다르다.
| 실행 | 결과 | sentinel |
|---|---|---|
| WORKSPACE_ROOT unset, 주 검증 묶음 | 135 passed, 21 failed, 107.10s | 0 entries |
| WORKSPACE_ROOT=기존 sentinel, 동일 묶음 | 135 passed, 21 failed, 107.53s | 0 entries |
| 추가 검증 묶음, unset | 84 passed, 69.36s | 0 entries |
| fixture 순서 및 `_mutate` 직접 탐침 | 3 passed, 0.24s | 0 entries |
주 검증 묶음은 다음 파일 전체와 두 회귀 node다:
- test_b19_headless_reconcile_fixes, test_b8_send_keys_verification, test_loop_cli, test_version_consistency, test_workspace_scope, test_orc_onboard, test_o3_scoped_guard, test_issue5_phase3_loop, test_issue5_phase4_runtime, test_issue25_plan_reuse, test_issue33_budget.
- test_issue17_workspace_root_isolation::test_w2_onboard_does_not_carry_its_import_time_root.
- test_issue17_item4_decisions::test_c_helpers_write_nothing_to_an_inherited_workspace.
두 환경의 실패 21건은 동일하다:
- O3 guard 12건: `ps` 실행 시 PermissionError / Operation not permitted.
- onboard O18/O28/O29 3건: 프로세스 command/parent를 `ps`로 읽는 autodetection 불가로 exit 3. `orc_onboard.sh:108,185`의 조회와 해당 환경 의존 테스트 경로를 확인했다. explicit UUID 및 나머지 onboard 검증은 통과했다.
- issue33 budget 6건: local_broker_env()가 실제 로컬 브로커를 요구하여 실패. 제외한 broker fixture에 따른 실행 제약이다. 나머지 budget 13건은 통과했다.
추가 묶음 84건에는 test_tier1_unit 전체, phase1 delegation C01/C02/C04/C05 및 event/exit mapping 두 contract node, fail_closed의 T1-25와 T3-1/T3-2, worktree_prereqs T2-8이 포함된다. 해당 phase1 node의 파라미터 케이스를 모두 포함한다.
따라서 수정 파일 전체와 phase1 delegation 전체의 두 환경 통합 실행을 모두 통과했다고 주장하지 않는다. 특히 W1 nested pytest와 실제 broker/process-inspection 경로의 전체 확인은 브리프에 따라 오케스트레이터의 제한 없는 실행으로 남긴다.
임시 로그 및 재현 드라이버:
- `/tmp/c20f3d1f-run.py`
- `/tmp/c20f3d1f-unset.log`
- `/tmp/c20f3d1f-sentinel.log`
- `/tmp/c20f3d1f-extra.log`
- `/tmp/c20f3d1f-probe-tests/test_order.py`
실행 후 확인한 sentinel:
- `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/c20f3d1f-unset-ffhmus4t/sentinel`
- `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/c20f3d1f-sentinel-bi_df5cb/sentinel`
모두 비어 있으며 검증 checkout의 `.mam` 아래에도 파일/하위 디렉터리가 없다. 별도 탐침의 첫 시도는 /tmp 상위 수집 중 접근 제한 디렉터리 때문에 collection 오류였고, 전용 probe 디렉터리와 rootdir를 지정한 재실행에서 3건 통과했다. 소스 변경은 하지 않았다.
## 회귀 negative control
`/tmp/c20f3d1f-negative.py`로 현재 검증 트리에서 base 코드를 `git show`로 읽어 메모리에만 로드했다. 실제 저장소/작업 트리를 되돌리지 않았다.
| 탐침 | 수정 전 base | 현재 head |
|---|---|---|
| W2와 같은 import-time onboard root 시나리오 | sentinel 3 entries (`.mam/shim/herdr`), own shim 없음 | sentinel 0 entries, own shim 존재 |
| 현재 decisions 회귀 테스트에 base `_env`만 교체 | `AssertionError: written into the sentinel` | 동일 테스트 통과 |
절차: 기존 빈 sentinel을 WORKSPACE_ROOT로 설정 → onboard 모듈 import → 환경을 fixture-ws로 변경 → run_find_uuid(fixture-ws, 'claude'). 두 번째 탐침은 현재 회귀 함수에 base `_env` 함수 AST를 넣고 실행한 다음 head 함수로 복원해 재실행했다. 기대 결과는 sentinel 불변 및 자기 root에만 shim 생성이다. 현재 코드는 두 시나리오 모두 기대와 일치한다.
산출물: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/c20f3d1f-negative-opdzrib1`.
## 같은 결함 후보 재조사 / 수정하지 않은 후보
`rg`로 환경 복사, lib.sh source, wrapper/run_loop 실행 지점을 다시 조사하고 fixture 또는 명시적 root 경로를 대조했다. 아래는 변경하지 않은 주요 후보의 제외 근거다. 단순히 환경을 복사한다는 이유만으로 안전하다고 판단하지 않았다.
| 후보 파일:라인 | 제외 근거 |
|---|---|
| tests/test_issue14_delivery_ack.py:33 | `_env(cwd)`가 WORKSPACE_ROOT=cwd를 지정한다. |
| tests/test_issue18_liveness_contract.py:54 | `_env(cwd)`가 WORKSPACE_ROOT=cwd를 지정한다. |
| tests/test_issue33_budget.py:43 | 독립 `_env`가 테스트 root를 지정한다. |
| tests/test_issue34_job_tree.py:50,587 | `_env(home)`은 root를 고정하고 `_run_lib` 호출은 mam_sandbox를 사용한다. |
| tests/test_issue36_prompt_transport.py:47,532 | `_env(home)` 및 shell-loop 실행이 명시적인 임시 control root를 쓴다. |
| tests/test_issue26_ints.py:124 | HOME과 WORKSPACE_ROOT를 같은 테스트 home으로 설정한다. |
| tests/test_c1_tui_readiness.py:12 | helper 내부 mkdtemp를 WORKSPACE_ROOT로 설정한 뒤 source한다. |
| tests/test_layout.py:310 | generated-shim 테스트가 임시 ws_dir를 source 전에 export한다. |
| tests/test_issue6_turn_handshake.py:24,43 | cwd를 준 helper는 root/home을 그 경로로 바꾸며 mock_herdr 경로는 mam_sandbox에 의존한다. |
| tests/test_issue5_phase1_delegation.py:49 | lib helper 호출은 mam_sandbox에서 실행되고 root는 fixture의 임시 경로다. Python-only 계약 검사는 shim bootstrap이 없다. |
| tests/test_tier1_unit.py:14,464 | 셸 helper 호출은 mam_sandbox 사용. :464의 별도 환경은 Python workspace_uuid만 실행하며 lib.sh를 source하지 않는다. |
| tests/test_uuid_target.py:11 | mutation helper와 셸 호출이 mam_sandbox를 사용한다. |
| tests/test_o2_race_free_lock.py:16 | 상태 helper 호출은 mam_sandbox fixture를 사용한다. |
| tests/test_issue20_state_isolation.py:150,199 | 격리 회귀 목적으로 자체 임시 repo/root를 명시한다. |
| tests/test_b7_diff_untracked.py:11 | diff_collect는 lib.sh shim bootstrap 경로가 아니다. |
| tests/test_issue8_update_state.py:24 | 설치/업데이트 대상은 별도 임시 workspace이며 lib.sh source 결함과 다르다. |
| tests/test_issue5_phase2a_loop.py:754 | 해당 source 문자열은 static guard 검사용 텍스트이며 실제 셸 실행이 아니다. |
이번에 수정된 누락 후보(b19/b8/loop CLI/phase3/phase4/O3/version/issue25/fail_closed)는 own_workspace_root에 opt-in했다. unittest workspace_scope와 worktree_prereqs mutation은 직접 고정하고, import-time 캐시를 쓰던 onboard는 runtime root 적용으로 별도 해결했다. 추가 동일 결함은 확인하지 못했다.
## Lifecycle
요청한 started 명령을 먼저 실행했으나 MQTT 연결이 sandbox의 Operation not permitted로 실패하여 exit 2였다. 리뷰 결과 파일을 쓴 뒤 요청된 completed 명령도 실행했다. 3회 연결 시도 후 같은 Operation not permitted로 exit 2를 반환했다. 따라서 MQTT 전달 성공은 확인하지 못했다. 보고서의 PASS와 MQTT 전달 성공 여부는 별개다.
[VERDICT: PASS]