Files
multi-agent-mux/.agents/reports/planner-reviewer-codex-01/report-527f1409.md
T
GodopuandClaude Opus 5.5 ca688dcef4 release(v4.8.9): tests no longer take the checkout's loop lock - archive the review reports and bump the lockstep version
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
2026-10-09 10:59:38 +09:00

9.1 KiB

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에서 다음 형태로 실행한다:

<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에서 실패하는지 확인한다.

실제 결과:

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]