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,121 @@
# Review — 05537aa1
## 판정
PASS. 이전 라운드에서 빠진 O1/O2의 run_loop 실행 경로에 격리가 추가되었으며, 새로운 차단 결함은 확인하지 못했다. 브리프가 허용한 정적 검토와 제한 환경 실행으로 판정했다. 전체 통합 스위트 통과를 주장하지 않는다.
## Identity 및 변경 범위
- loop: `loop-20261008T133858Z-9e7f5b`
- base: `6b00b6e06f55299cb60f156ccef09ede4bae5bdd`
- head: `ac48cb78617af88584db529b5766acf02f4af73c`
- tree: `b043034eda891bd83b547dcb34d7422a6977b89d`
- 검증 cwd: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261008T133858Z-9e7f5b/3`
- Python: `/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux-wt/issue17-wsroot/.venv/bin/python` (3.9).
위 identity를 확인했다. 검증 전후 git status가 비어 있고 `git diff --check 6b00b6e HEAD` 및 변경된 Python 17개 파일 AST 파싱이 통과했다. 제품 코드 변경은 없다. creator 작업 트리에서는 실행/수정하지 않았고 검증 소스도 수정하지 않았다.
이전 검토 head `8b47cc76eed4582b1848b2eec529523a61497320` 이후 diff는 다음 세 파일뿐이다:
1. `tests/test_o1_rebuttal.py:10` — 모듈에 own_workspace_root fixture opt-in 추가.
2. `tests/test_o2_race_free_lock.py:196` — run_loop를 실행하는 O2-12에만 fixture opt-in 추가.
3. `tests/test_issue17_workspace_root_isolation.py:41` — W1의 nested pytest 목록에 O1-V3와 O2-12 추가.
O2 모듈 전체에 fixture를 적용하지 않은 것은 적절하다. `test_o2_7_no_leftover_temp_files`는 tmp_path가 비어 있어야 하므로 새 workspace 디렉터리가 만들어지면 불필요한 실패가 된다. O2-7은 이번 두 실행에서 모두 통과했다. 나머지 O2 잠금 함수 테스트는 lib.sh가 아닌 loop_lock.sh를 source한다.
## 이전 보고서 정정 및 누적 검토
이전 c20f3d1f 보고서의 O2 제외 근거는 일부 상태 helper에만 해당했으며, `test_o2_12_run_loop_exits_on_lock_failure`의 직접 run_loop 실행까지 포괄하지 못했다. 그 제외 설명과 '추가 동일 결함 없음'이라는 결론은 범위가 너무 넓었다. 이번에는 O1-V3와 O2-12의 이전 코드가 실제 sentinel에 shim을 생성하는 것을 확인했고, 현재 추가된 fixture로 격리되는 것을 확인했다.
기존 누적 수정은 이전 head와 동일하다:
- `test_issue17_item4_decisions.py:224`: `_env`에서 상속 WORKSPACE_ROOT를 제외하고 tmp_path로 고정. unset만 하면 lib.sh가 checkout을 기본값으로 쓰므로 명시적 임시 root가 맞다.
- `conftest.py:180`: opt-in own_workspace_root. 기존 mam_sandbox와 테스트 본문의 명시적인 root 설정이 나중에 적용되는 구조를 유지한다.
- `test_orc_onboard.py:19,27`: import 시점 캐시에서 WORKSPACE_ROOT를 제거하고 호출 시점의 root를 적용한다.
- `test_workspace_scope.py:31`, `test_issue21_worktree_prereqs.py:544`: fixture opt-in 대신 해당 helper의 임시 root를 직접 지정한다.
- b19/b8/loop CLI/phase3/phase4/O3/version/issue25/fail_closed 모듈의 셸 실행은 own_workspace_root를 사용한다.
이전 head에 대한 상세 fixture 우선순위 검증과 135 passed × 2, 추가 84 passed, 별도 3 passed 결과는 다음 이전 보고서에 있다. 이를 현재 head에서 새로 실행한 결과로 세지 않았다:
`/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.mam/jobs/c20f3d1f/codex-reports/report-final.md`
## 이번 실행
환경에서 HERDR_*, MAM_*, MQTT_*, SKS_*, WORKSPACE_ROOT 및 control-plane 경로 변수를 제거하고 HOME을 임시 경로로 지정했다. sentinel은 미리 생성한 빈 디렉터리다. 모든 산출물과 basetemp는 검증 트리 밖에 두고 bytecode/cache 쓰기를 껐다. 실제 .mam.env를 export하거나 출력하지 않았다.
샌드박스는 MQTT 연결/로컬 broker socket bind 및 ps 실행을 제한한다. 따라서 `/tmp/05537aa1-run.py`는 현재 검증 트리의 실제 conftest를 import하여 local_mqtt_broker fixture만 메모리에서 제외하고, `--noconftest`, `-p no:cacheprovider`, 임시 basetemp와 `plugins=[module]`로 실행했다. 나머지 fixture/hook/상태 guard는 그대로 등록했다. 소스 파일 변경이나 권한 우회는 하지 않았다.
실행 대상:
- `tests/test_o1_rebuttal.py` 전체.
- `tests/test_o2_race_free_lock.py` 전체.
- `test_issue17_workspace_root_isolation.py::test_w2_onboard_does_not_carry_its_import_time_root`.
- `test_issue17_item4_decisions.py::test_c_helpers_write_nothing_to_an_inherited_workspace`.
| 조건 | 결과 | sentinel 상태 |
|---|---|---|
| WORKSPACE_ROOT unset | 24 passed, 10 failed, 6.54s | 0 entries |
| WORKSPACE_ROOT=sentinel | 24 passed, 10 failed, 6.56s | 0 entries |
O1의 10개 테스트와 두 기존 격리 회귀 테스트는 모두 통과했다. 실패한 O2 테스트는 두 조건에서 동일하게 O2-2/3/4/11/12/16/17/18/19/20이다. `loop_lock.sh:39` 부근에서 자신의 ps lstart를 얻지 못하면 holder state가 unknown이 되고 `:108` 부근에서 rc 4를 반환한다. 따라서 live/stale 판정을 기대하는 테스트가 실패한다. O2-12 로그도 명확히 `Cannot determine whether another loop is running (ps unavailable?)`를 출력한다. 이는 이번 WORKSPACE_ROOT 수정으로 잠금 동작이 바뀐 것이 아니다.
기능 assert가 ps 제한으로 실패한 O2-12도 lib.sh bootstrap은 실행된다. 실행 후 O1-V3와 O2-12 각각의 `.mam-test-state/workspace/.mam/shim/herdr`가 존재하고 외부 sentinel이 비어 있음을 두 조건에서 직접 확인했다. 검증 checkout의 `.mam` 아래에도 항목이 없다.
로그/드라이버:
- `/tmp/05537aa1-run.py`
- `/tmp/05537aa1-unset.log`
- `/tmp/05537aa1-sentinel.log`
- unset root: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/05537aa1-unset-ecvw8t06`
- sentinel root는 `/tmp/05537aa1-sentinel.log` 첫 ROOT 행에 기록되어 있다.
## 수정 전 실패 확인
`/tmp/05537aa1-negative.py`가 `git show`로 읽은 이전 코드를 메모리에 로드했다. __file__은 현재 검증 트리 경로로 지정하고, 실행되는 제품 코드는 현재 검증 트리의 변경 없는 코드다. 검증 트리를 checkout/reset하거나 수정하지 않았다.
| 시나리오 | 수정 전 실제 결과 | 현재 실제 결과 |
|---|---|---|
| base `_env`를 현재 decisions 회귀 함수에 적용 | `AssertionError: written into the sentinel` | 동일 회귀 함수 통과 |
| onboard를 sentinel root에서 import한 후 fixture root로 변경하고 run_find_uuid 호출 | base: sentinel 3 entries, own shim 없음 | head: sentinel 0 entries, own shim 있음 |
| 이전 head의 O1-V3 함수 직접 실행 | 함수 자체는 성공하지만 sentinel에 `.mam/shim/herdr` 생성 | pytest fixture 적용 시 own root에만 shim 생성 |
| 이전 head의 O2-12 함수 직접 실행 | ps assert 실패 전 sentinel에 `.mam/shim/herdr` 생성 | 같은 ps 제약하에서도 own root에만 shim 생성 |
기대 결과는 모두 외부 sentinel 불변이다. 새 opt-in이 없던 O1/O2는 이 기대를 위반하고, 현재 pytest 실행에서는 만족한다. O1/O2 negative control은 함수를 직접 호출한 탐침이며 W1 전체 nested pytest의 성공/실패 결과라고 표현하지 않는다.
negative log: `/tmp/05537aa1-negative.log`
negative root: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/05537aa1-negative-_c2j_av4`
W1은 actual conftest/broker를 사용하는 nested pytest이므로 이 샌드박스에서 완주하지 않았다. 새 두 node가 실제 수집 가능한 함수명과 일치하며, subprocess 성공 및 통과 수 검사 뒤 copied checkout의 `.mam` 비어 있음을 검사하는 구조를 정적으로 확인했다.
## 같은 결함 후보 재조사
환경 복사만 검색하지 않고 `run_loop.sh`, `lib.sh`, WRAPPER, source, subprocess 실행도 교차 검색했다. 아래는 이번에 재확인한 미수정 후보의 제외 이유다. 이전 보고서의 O2 포괄 제외는 이 표로 대체한다.
| 파일:라인 | 미수정 이유 |
|---|---|
| tests/test_o2_race_free_lock.py:14,23 | 일반 lock helper는 loop_lock.sh만 실행. 직접 run_loop를 실행하는 :199는 이번에 수정됨. |
| tests/test_herdr_shim_contract.py:10,139 | lib.sh를 실행하는 계약 테스트/공유 helper 호출은 mam_sandbox/mock fixture를 사용한다. |
| tests/test_sanitize_and_mock_errors.py:28 | bash parity test가 mam_sandbox를 사용한다. |
| tests/test_issue7_workspace_packing.py:49 | 셸 helper 호출이 mam_sandbox 기반이다. |
| tests/test_issue21_acceptance.py:280 | run_loop 실행 환경에 임시 main root를 명시한다. |
| tests/test_issue26_envfile.py:73 | `_env(home, ...)`가 HOME과 WORKSPACE_ROOT를 home으로 설정한다. |
| tests/test_issue30_stall_watch.py:124,231 | box/mam_sandbox와 격리된 환경 helper를 사용한다. |
| tests/test_issue30_stall_watch_stop.py:29 | `_env(home)`이 WORKSPACE_ROOT=home을 지정한다. |
| tests/test_issue45_restore.py:93,172 | run_lib의 rig는 mam_sandbox에 의존한다. 실제 서버 테스트는 이번 리뷰에서 실행하지 않았다. |
| tests/test_issue24_resume_dialogs.py:70,82 | create/stop/resume 실행이 mam_sandbox/mock fixture를 사용한다. |
| tests/test_issue15_registry_isolation.py:75 | 별도 subprocess 환경에 임시 WORKSPACE_ROOT를 명시한다. |
| tests/test_issue5_phase0_contracts.py:481 | run_loop 언급은 정적 문서 계약 검사다. |
| tests/test_issue14_delivery_ack.py:33; test_issue18_liveness_contract.py:54 | 환경 helper에서 cwd를 root로 지정한다. |
| tests/test_issue34_job_tree.py:50; test_issue36_prompt_transport.py:47 | 환경 helper가 임시 home/root를 고정한다. |
| tests/test_c1_tui_readiness.py:12; test_layout.py:310 | 별도 임시 root를 source 전에 지정한다. |
| tests/test_tier1_unit.py:14; test_issue5_phase1_delegation.py:49 | 셸 helper 호출은 mam_sandbox를 사용한다. |
| tests/test_b7_diff_untracked.py:11 | diff_collect는 lib.sh의 shim bootstrap 경로가 아니다. |
추가 동일 결함은 확인하지 못했다. 이번 변경은 pytest fixture 사용 추가여서 Bash 제품 문법을 바꾸지 않는다. O1의 bash 3.2 empty-array 검증도 이번 실행에 포함되어 통과했다.
## 검증 한계 / Lifecycle
새 변경은 3개 파일이므로 그 변경과 회귀 탐침을 재검증했으며, 이전 head와 동일한 전체 파일 묶음은 반복하지 않았다. 변경 파일 전부와 issue33_budget/phase1_delegation/tier1 전체의 두 환경 통합 실행을 이번 리뷰가 모두 통과시켰다는 주장은 하지 않는다. 제한 없는 전체 실행은 브리프에 따라 오케스트레이터가 수행해야 한다. 환경 제한 자체를 NOT PASS 사유로 삼지 않았다.
started 명령을 먼저 실행했으나 MQTT 연결이 Operation not permitted로 3회 실패하여 exit 2였다. 보고서 작성 후 요청된 completed 명령을 실행한다.
[VERDICT: PASS]