# Review Report — Job d05e8e15 (v4.4.0 릴리스 락스텝 갱신) - Reviewer: planner-reviewer-claude-01 - 리뷰 범위: `b347efd..HEAD` (단일 커밋 `3874797` "release(v4.4.0)"), 21 파일 +160/−40 - 범위 고정: 브리프 내장 diff(39,725 B) vs `git diff b347efd..HEAD -- . ':(exclude).agents/reports'`(39,724 B) — 말미 개행 1바이트 외 **바이트 동일**. `.agents/reports` 하위 변경 없음. - 검증 환경: Python 3.9.6, `.venv`, 실제 리뷰어 셸의 ambient `MAM_VERSION=4.3.0` (이 커밋이 고친 격리 결함의 실전 재현 조건) - 참고: 현재 체크아웃 브랜치는 `release/v4.4.0`이며 `main`은 아직 `b347efd`(릴리스 커밋 미포함). VERSIONS.md "기준 브랜치: main"은 병합 후 상태를 선기술한 것으로, 병합 시점에 사실이 된다. ## 1. SemVer 판정(MINOR `v4.4.0`) 근거 재검증 작업자의 "규모는 크지만 깨는 것이 없다" 주장을 항목별로 실 트리에서 재확인했다. | 주장 | 검증 방법 | 결과 | | :--- | :--- | :--- | | Issue #5 전 구간 삭제·rename 0건 | `git diff --name-status fc0bd96..HEAD \| grep -v '^[AM]'` | 0건 ✅ | | `SCHEMA_VERSION = 1` 불변 | `mqtt_common.py:135` | ✅ | | `scripts/*.py` 4종 존속 | `ls multi-agent-mux-delegate-job/scripts/` | job_subscriber/mqtt_common/publish_event/registry ✅ | | 롤백 env 4종 실재·기본값 | `lib.sh:1972,1989,2000` (`MAM_DELEGATION_PY:-1`), `engine.py:109` (`MAM_ENGINE_CAS` 기본 "1"), `run_loop.sh:122` (`MAM_LOOP_PY:-1`, `MAM_LOOP_FREEZE:-0`) | ✅ | | 자동 완료 기본 비활성 | `loop/autocomplete.py:29,53` — `os.environ.get("MAM_AUTO_COMPLETE","0") == "1"` | ✅ | | 레거시 셸 루프 968줄 존치 | `wc -l run_loop.sh` = 968 (Phase 3 직전 936, Phase 4 직전 960) — VERSIONS.md의 "936줄 이식" / "968줄 존치" 두 숫자 모두 정확 | ✅ | | `run_loop.sh:17` source, `lib.sh:32-33` 무조건 재export | 행 번호 실측 일치. `MAM_VERSION=4.3.0 bash -c 'source lib.sh; echo $MAM_VERSION'` → `4.4.0` | ✅ | **판정 동의**: 공개 계약(스크립트 경로·CLI·와이어 스키마·YAML 레이아웃)에 제거·변경이 없고 모든 기본 동작 변경이 env 1개로 가역이므로 SemVer 2.0.0 §8의 MAJOR 요건을 충족하지 않는다. 유일한 신규 fail-closed 거부(`MAM_VERSION` 게이트)는 프로덕션 경로에서 `lib.sh`가 값을 무조건 덮어쓰므로 정상 배포된 트리에서는 발동할 수 없고, 혼재 트리에서만 발동한다. 이는 릴리스 노트 "부분 배포 금지"로 명시되어 있다. **v4.4.0 MINOR가 옳다.** ## 2. 락스텝 갱신 검증 - `lib.sh` MAM_VERSION, `eager.py` FRAMEWORK_VERSION, VERSIONS.md 현재 버전 + 매트릭스 8행, 8개 `SKILL.md` frontmatter 모두 `4.4.0` (grep 실측). - README/BOOTSTRAP 4종 배지: **v4.1.3 / v4.2.0 → v4.4.0**. `b347efd` 시점 README 배지는 `v4.2.0`인데 `lib.sh`는 `4.3.0`이었다. 즉 배지는 두 릴리스 동안 유실 상태였고, 이번 작업이 이를 함께 회수했다(유실 관점에서 긍정). 다만 배지는 락스텝 테스트 미커버(→ O-1). - 트리 내 잔존 `4.3.0` 문자열은 VERSIONS.md 이력, `delegate-job` README/job-protocol/registry/SKILL.md의 "구현 위치 각주 (v4.3.0)" 등 **역사적 서술**뿐이며 현재 버전 표기로 남은 것은 없다. ## 3. 테스트 변경 검증 (재현) ### 3-1. 락스텝 4번째 다리(`eager.py`) 커버리지 — 주장 사실 - `b347efd` 트리에서 `eager.py`만 4.4.0으로 올린 뒤 구 `test_version_consistency.py` 실행 → **2 passed (미검출)**. - HEAD 트리에서 `eager.py`만 4.5.0으로 올린 뒤 실행 → `test_three_way_version_lockstep`, `test_runtime_version_gate_rejects_a_partially_bumped_tree` **2 failed (검출)**. 커밋 메시지의 "gap" 주장과 수정 효과 모두 확인. - `_get_eager_py_framework_version`은 정적 regex 파싱(`^FRAMEWORK_VERSION\s*=\s*"(\d+\.\d+\.\d+)"`, MULTILINE)으로 `eager.py:16` 형식과 정확히 일치. 새 게이트 테스트는 `importlib.util.spec_from_file_location`으로 `sys.path` 오염 없이 로드하고 `os.environ`을 try/finally로 복원한다. `os`/`re`는 파일 상단에 이미 import되어 있다. ### 3-2. 격리 결함(ambient `MAM_VERSION`) — 주장 "4건 실패" 정확히 재현 | 트리 | conftest fixture | env | 결과 | | :--- | :---: | :--- | :--- | | HEAD | 제거(재현용 복제본) | `MAM_VERSION=4.3.0` | **4 failed**, 16 passed — `test_p4_01_eager_import…`, `test_p4_01_loop_runner_instantiation…`, `test_p4_02_midflight…`, `test_p3_03_runner_agent_type_resolution` | | HEAD | 존재 | `MAM_VERSION=4.3.0` (리뷰어 셸 실값) | 20 passed | | HEAD | 존재 | `MAM_VERSION=9.9.9` | 20 passed | | `b347efd` | 없음 | `MAM_VERSION=4.3.0` (자기 트리와 일치) | 19 passed — "우연히 같아 잠복" 주장 확인 | | `b347efd` | 없음 | `MAM_VERSION=9.9.9` | 5 failed (위 4건 + `test_p3_02`) — 결함이 릴리스 이전부터 존재했음 확인 | - fixture는 session 스코프 autouse로 `os.environ.pop`, 종료 시 복원. 게이트를 직접 검사하는 테스트(`test_p4_01` monkeypatch 9.9.9, 신규 게이트 테스트, `test_mam_version_is_not_env_overridable`)는 모두 자체적으로 값을 설정하므로 영향 없음(HEAD 20/20으로 실증). - `test_issue5_phase4_runtime.py`는 하드코딩 리터럴 제거 후 `verify_framework_version(eager.FRAMEWORK_VERSION)` — 시그니처 기본값이 `FRAMEWORK_VERSION`이므로 동작 동일하며, monkeypatch 9.9.9 불일치 검사는 그대로 유지. ### 3-3. 린트 - `py_compile` 4파일 OK, `bash -n lib.sh` OK, 변경 추가행 중 100자 초과 없음, `git status` clean. (pyflakes/ruff는 venv 미설치 — 이전 라운드와 동일.) ## 4. 문서 검증 - VERSIONS.md 4.4.0 절: 인용 파일·행 번호(`mqtt_common.py:135`, `run_loop.sh:17`, `lib.sh:32-33`), env 이름·기본값, 테스트 수(510 → 750, +240; Phase 4 시점 749 + 신규 게이트 테스트 1 = 750 수집 실측) 모두 실 트리와 일치. - `implementation_plan.md` Phase 0/3/4 상태 열, `phase4-freeze-removal.md` 부분 배포 금지 문구, `task.md` Rev.9 / P4-01 증거 갱신 — 내용 정확. ## 5. 결함 **차단 결함 없음.** 코드 변경은 상수 2개 + 테스트 3파일이며 세 가지 주장(락스텝 갭, 4건 격리 실패, fixture 효과)이 모두 실측 재현되었다. ### 비차단 관찰 - **O-1 (권고)**: README/BOOTSTRAP 4종 배지는 이번에 두 릴리스분이 한꺼번에 회수될 만큼 락스텝 밖에 있다. `test_three_way_version_lockstep`에 5번째 다리로 추가 권고. 검증한 프로토타입(15줄, `BADGE_DOCS` + `_get_badge_version` regex `badge/version-v(\d+\.\d+\.\d+)-`): HEAD에서 3 passed, `b347efd`에 역적용 시 `README.md badge (4.2.0) != lib.sh (4.3.0)`로 정확히 실패한다. - **O-2 (표기)**: 테스트 함수명 `test_three_way_version_lockstep`과 파일 헤더 "3-Way"가 이제 4-way(O-1 채택 시 5-way)를 검사한다. 이름 변경은 선택 사항. - **O-3 (환경)**: `test_p3_02_run_loop_wrapper_delegates_to_python_default`는 `.venv`가 없는 git worktree에서 `No module named 'paho'`로 실패한다(리뷰 중 관측, `.venv` 심링크로 해소). 본 커밋과 무관한 기존 테스트의 실행 환경 의존이며 메인 트리에서는 통과. - **O-4 (브랜치)**: 릴리스 커밋은 `release/v4.4.0`에만 있고 `main`은 `b347efd`이다. VERSIONS.md의 "main 병합 완료"는 이 릴리스 브랜치 병합으로 완성된다. - 이전 라운드 핸드오버(a665d729 §4) 중 코드 변경을 요하는 항목(all-None intent 신원 가드, direct job `claim` 토큰 등)은 이번 릴리스 범위 밖이며 유효하게 잔존. ## 6. 전체 스위트 - `env -u MAM_VERSION .venv/bin/python -m pytest tests -q`: __SUITE_RESULT__ [VERDICT: PASS]