Merge-workspace review loop (--all-reviewer): round 1 (@a93c9bf) 4/4
PASS. Full suite at a93c9bf on macOS / Python 3.9 / herdr 0.9.3 with
WORKSPACE_ROOT set to an empty sentinel: 1752 passed / 0 failed / 38
skipped; the sentinel stayed empty, the review worktree had no .mam, 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
127 lines
9.1 KiB
Markdown
127 lines
9.1 KiB
Markdown
# Review — 527f1409
|
|
|
|
## 판정
|
|
|
|
PASS. 누적 변경에서 차단할 결함을 찾지 못했다. O3의 두 실제 run_loop 실행이 테스트 tmp_path 아래의 marker를 사용하고, 기존 잠금 경합/생성/해제 테스트의 marker는 유지된다. 새 회귀 테스트는 수정 전의 빈 `.mam/` 생성도 탐지한다.
|
|
|
|
## Review identity
|
|
|
|
- loop: `loop-20261008T234013Z-4f5d21`
|
|
- base: `97c2946ee0e11eabcecafe6407755c33c0289218`
|
|
- head: `a93c9bf29279f65ce0b9c9fb2c1aeea90a659420`
|
|
- tree: `741c19ba4c17601768b06684d5843d218a72beb1`
|
|
- 검증 cwd: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261008T234013Z-4f5d21/1`
|
|
- Python: `/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux-wt/loop-marker/.venv/bin/python` — 3.9.6.
|
|
- Bash: GNU bash 3.2.57(1)-release, arm64-apple-darwin25.
|
|
|
|
identity를 확인했고 git status는 깨끗하다. `git diff --check 97c2946 HEAD` 및 변경 Python 파일 3개의 AST 파싱이 통과했다. `.agents/skills`에는 변경이 없다. creator 소스 작업 트리에서 실행/수정하지 않았고 검증 트리의 코드도 수정하지 않았다.
|
|
|
|
## 변경 검토
|
|
|
|
- `tests/test_o3_scoped_guard.py:391`: reexec argv 테스트의 subprocess 환경에 tmp_path/loop-guard-active를 명시한다. 기존 환경은 dict(os.environ)으로 보존하므로 marker만 바뀐다.
|
|
- `tests/test_o3_scoped_guard.py:470`: no-freeze 테스트에도 같은 방식으로 임시 marker를 지정한다.
|
|
- 수정 대상이 한 모듈의 두 호출이므로 공통 fixture나 전역 autouse 없이 직접 지정한 범위가 적절하다. 다른 O2/O3 테스트가 의도적으로 만든 marker 경로는 건드리지 않는다.
|
|
- `tests/test_loop_marker_isolation.py:34`: checkout 복사본에서 실제 관련 테스트들을 nested pytest로 실행한 뒤 `.mam` 디렉터리 자체가 없음을 검사한다. 실행 실패나 skip을 성공으로 취급하지 않는다.
|
|
- `tests/test_issue17_workspace_root_isolation.py:71`: 이전의 하위 항목 목록 검사에 디렉터리 부재 검사를 추가한다. 잠금을 해제하면서 marker만 삭제하고 빈 `.mam/`을 남기는 경우까지 잡는다.
|
|
|
|
## 실제 실행 결과
|
|
|
|
이전 작업의 샌드박스 제한은 현재 해소되어, 이번에는 **정상 conftest와 실제 로컬 MQTT broker를 그대로 사용했다**. fixture를 제외하거나 ps를 대체하지 않았다.
|
|
|
|
실행 전 HERDR_*, MAM_*, MQTT_*, SKS_*, WORKSPACE_ROOT 및 상속된 control-plane 경로 환경을 제거했다. HOME은 새 임시 경로로 지정했다. `.mam.env`를 export하거나 내용을 출력하지 않았다. bytecode/cache 쓰기는 비활성화하고 basetemp/로그는 검증 트리 밖에 두었다.
|
|
|
|
실행 파일(모두 전체 파일):
|
|
|
|
- `tests/test_o2_race_free_lock.py`
|
|
- `tests/test_o3_scoped_guard.py`
|
|
- `tests/test_issue17_workspace_root_isolation.py`
|
|
- `tests/test_loop_marker_isolation.py`
|
|
|
|
따라서 변경한 테스트 파일 전부와 브리프의 필수 동반 파일이 포함된다. W1과 L1의 nested pytest도 실제로 완료되었다.
|
|
|
|
| 조건 | 결과 | 외부 sentinel | 검증 checkout `.mam/` |
|
|
|---|---|---|---|
|
|
| WORKSPACE_ROOT unset | 57 passed, 47.85s | 0 entries | 실행 전후 없음 |
|
|
| WORKSPACE_ROOT=기존 빈 sentinel | 57 passed, 48.29s | 0 entries | 실행 전후 없음 |
|
|
|
|
O2의 live-holder 거부, 경합 단일 승자, stale 회수, marker 보존, O3의 잠금 생성/해제 및 guard 동작이 통과했다. Python 3.9 및 macOS 기본 Bash 3.2에서 검증했다.
|
|
|
|
재현 드라이버/로그:
|
|
|
|
- `/tmp/527f1409-run.py`
|
|
- `/tmp/527f1409-unset.log`
|
|
- `/tmp/527f1409-sentinel.log`
|
|
|
|
드라이버는 환경을 정리한 뒤 해당 검증 cwd에서 다음 형태로 실행한다:
|
|
|
|
```text
|
|
<loop-marker venv>/bin/python -m pytest -p no:cacheprovider --basetemp=<외부 임시 경로>/bt -q --tb=short <위 4개 파일>
|
|
```
|
|
|
|
임시 실행 root:
|
|
|
|
- unset: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/527f1409-unset-77llo387`
|
|
- sentinel: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/527f1409-sentinel-p9dxhcge`
|
|
|
|
각 root의 sentinel 디렉터리가 비어 있음을 실행 후 확인했다.
|
|
|
|
## 수정 전 실패 확인
|
|
|
|
`/tmp/527f1409-negative.py`에서 **동일한 새 L1 회귀 함수**를 실행하되, `_copy_checkout`가 만든 외부 임시 복사본의 O3 테스트 파일만 base `97c2946` 버전으로 교체했다. 제품 코드는 base와 head가 동일하다. 원본 검증 트리나 creator 소스는 수정하지 않았다.
|
|
|
|
절차:
|
|
|
|
1. 현재 checkout을 임시 디렉터리 아래에 복사한다.
|
|
2. 그 복사본의 `tests/test_o3_scoped_guard.py`만 `git show 97c2946:tests/test_o3_scoped_guard.py` 내용으로 바꾼다.
|
|
3. 새 L1 함수가 선택한 실제 테스트들을 그대로 실행한다.
|
|
4. nested pytest의 성공/통과 수 검사 이후, 최종 `.mam` 부재 assertion에서 실패하는지 확인한다.
|
|
|
|
실제 결과:
|
|
|
|
```text
|
|
NEGATIVE_ASSERTION a test took the checkout's loop lock (its .mam was created)
|
|
COPY_MAM_EXISTS True
|
|
COPY_MAM_ENTRIES []
|
|
```
|
|
|
|
즉 테스트 본체가 성공해도 잠금 디렉터리가 남는 기존 결함을 정확히 재현했다. 현재 head에서는 같은 L1이 두 환경 모두 통과한다. 단순 테스트 실행 실패를 negative control 성공으로 센 것이 아니다.
|
|
|
|
- 로그: `/tmp/527f1409-negative.log`
|
|
- negative root: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/527f1409-negative-x1lkngmg`
|
|
|
|
## 실행 지점 조사 및 제외 근거
|
|
|
|
직접 `rg`로 run_loop.sh, RUN_LOOP, MAM_LOOP_MARKER, MAM_REAL_ROOT, runner 진입을 교차 검색하고 호출 인자/환경 및 제품 코드의 잠금 시점을 확인했다. 검색 기록은 `/tmp/527f1409-runner-audit.txt`에 있다.
|
|
|
|
| 후보 파일:라인 | 판정/제외 근거 |
|
|
|---|---|
|
|
| test_o3_scoped_guard.py:388,472 | checkout 스크립트로 실제 잠금까지 도달. 이번에 tmp marker 지정. |
|
|
| test_o3_scoped_guard.py:422 | --help로 잠금 전에 종료. |
|
|
| test_o3_scoped_guard.py:164,437 | 추출 함수/잠금 harness는 tmp_path를 REPO_ROOT 또는 MAM_REAL_ROOT/marker로 지정한다. 기존 marker 동작 검사 유지. |
|
|
| test_o2_race_free_lock.py:203 | 이미 tmp_path의 경합 marker를 MAM_LOOP_MARKER로 전달. 다른 호출은 loop_lock.sh 자체 또는 bash -n 검사다. |
|
|
| test_issue5_phase3_loop.py:163,181 | Python/legacy 두 실제 실행 모두 이미 tmp marker 지정. :151은 --help. |
|
|
| test_loop_cli.py:53,98 | session-check 실행은 tmp marker, planner 실행은 `_loop_env`의 tmp marker 및 임시 control root를 사용. 나머지 오류/도움말은 잠금 전 종료. |
|
|
| test_issue25_plan_reuse.py:355,365 | 도움말 또는 legacy 옵션 거부. 후자는 이미 tmp marker 지정, marker가 생기지 않음도 검사. |
|
|
| test_issue21_worktree_prereqs.py:398 | legacy 옵션 거부 실행에 이미 tmp marker 지정. Python runner 검사들은 임시 control root/fixture 사용. |
|
|
| test_issue21_loop_b.py:234 | checkout의 shell 호출은 임시 WORKSPACE_ROOT와 MAM_LOOP_MARKER를 명시. |
|
|
| test_issue21_acceptance.py:275,297 | 복사된 임시 main 트리의 shell 실행이며 경합용 임시 marker를 명시. |
|
|
| test_issue36_prompt_transport.py:532,539 | 임시 ctl의 복사된 스크립트와 ctl 아래 marker를 사용. :630의 추출 harness도 자기 PWD를 root로 지정. |
|
|
| test_issue5_phase4_runtime.py:142,166,183 | 실제 shell 호출은 모두 --help라 잠금 전에 종료. |
|
|
| test_o1_rebuttal.py:72,76 | --help 또는 잘못된 --max-rebut 인자로 잠금 전 종료. 나머지는 함수 추출/정적 검사. |
|
|
| test_b7_diff_untracked.py:174,189 | run_loop는 텍스트 읽기 또는 bash -n. 실제 수행하는 diff_collect는 루프 잠금을 잡지 않는다. |
|
|
| test_deploy_freshness.py:473 | 텍스트에서 export 구문을 확인하는 정적 검사. |
|
|
| test_issue5_phase0_contracts.py:481 | 문서/계약 문자열 검사. |
|
|
| test_tier4_e2e.py:279,285 | mam_sandbox에 복사된 run_loop 실행이므로 잠금 root도 임시 트리다. |
|
|
| test_issue17_workspace_root_isolation.py:56 | W1은 별도 checkout 복사본에서 선택 테스트를 실행. 새 `.mam` 부재 검사로 빈 디렉터리도 탐지. |
|
|
| test_loop_marker_isolation.py:34 | L1도 별도 복사본에서 실행하고 그 복사본의 `.mam` 부재를 확인. |
|
|
|
|
직접 Python `LoopRunner.run()` 진입도 확인했다. runner.py:1241의 run/_run_body는 shell의 mam_acquire_loop_lock를 호출하지 않는다. shell 진입이 실제 잠금을 획득하고 Python의 release_guard는 현재 PID 소유 marker만 해제하는 구조다. 따라서 Python runner의 단순 인스턴스 생성/메서드 mock 검사들을 shell 잠금 획득 누락으로 분류하지 않았다.
|
|
|
|
새 L1 목록은 일부 잠금 이전 거부 경로도 보수적으로 포함한다. 명시적으로 임시 marker를 이미 쓰는 다른 후보가 L1 목록에 전부 들어가야만 격리가 성립하는 구조는 아니며, 해당 제외 사유를 위에서 확인했다. 추가로 수정해야 할 checkout 잠금 획득 지점은 발견하지 못했다.
|
|
|
|
## Lifecycle
|
|
|
|
요청된 started 명령을 먼저 실행했고 exit 0으로 완료되었다. 정상 heartbeat 절차를 사용했다. 보고서 작성 뒤 요청된 completed 명령을 실행한다.
|
|
|
|
[VERDICT: PASS]
|