docs(reports): archive v4.4.3 unanimous PASS review reports (Issues #10, #11, #13, #15)

Final-round reports of the fix/issue-10-11-13-15 review loop: planner-reviewer-claude-01
(aa16fa5c), reviewer-agy-01 (0f41ea47), reviewer-grok-01 (3ea06fb6) and
planner-reviewer-codex-01 (79204d61), all [VERDICT: PASS] on fae70c1.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
GodopuandClaude Fable 5.1 committed 2026-09-13 10:53:59 +09:00
1 parent fae70c13d9
commit 1cc84282f3
4 files changed
+330

No files matched your search

@@ -0,0 +1,93 @@
# 🔍 Review Report — Job aa16fa5c (branch `fix/issue-10-11-13-15` 루프 2회차, HEAD `fae70c1`)
- **Reviewer**: `planner-reviewer-claude-01` (role: planner,reviewer) · 2026-09-13
- **대상**: `git log bd3df89..HEAD` — `c82ea75`, `0282312`(release v4.4.3), `7610258`(N1), `f5a6575`(테스트 uuid4), **`fae70c1`**(codex R1/R2). 앞선 라운드에서 PASS 한 부분은 회귀 여부 중심으로, 새 커밋 3건 중 `fae70c1` 은 정밀 검토했다(`7610258`·`f5a6575` 는 앞선 라운드에서 정밀 검토했고 이번에는 회귀만 확인).
- **방법**:
- 코드 정독
- **샌드박스 재현**: 임시 HOME 을 `$TMPDIR` 아래 생성하고 실행 전 `resolve_home()` 이 그곳인지 확인했다. 대화 id 는 모두 런타임 `uuid4()`.
- 선택 테스트(실제 `.mam/jobs` 스냅샷 비교)
- 정적 검사
- 리뷰 중 45초 간격 `progress` heartbeat 발행. 코드 수정 없음.
- **안전 규칙 준수**: 실제 홈이나 등록된 orchestrator UUID 로 purge 를 실행하지 않았다. `../multi-agent-mux-b2` 는 건드리지 않았다.
## 0. 직전 루프(반복 3, HEAD `f5a6575`) 결과와 처리
| 리뷰어 | 판정 |
|---|---|
| `planner-reviewer-claude-01`(`037af8e0`) · `reviewer-agy-01`(`433a74dc`) · `reviewer-grok-01`(`1752c893`) | PASS |
| `planner-reviewer-codex-01`(`f315859f`) | **NOT PASS** — R1: agy in-use 검사가 DB 만 `lsof` 에 넘겨 presence lock 만 연 보유자를 놓침 / R2: DB 가 없는 고아 부속 파일은 purge 대상으로 해결되지 않음 |
creator 는 반론 없이 `fae70c1` 로 두 지적을 반영하고 테스트 2개를 더했다. 검증 잡(`9c3e6f9b`)에서 250 passed 를 확인했고, `VERSIONS.md` 의 신규 테스트 수가 낡았다고 스스로 기록했다(§2-(3)).
## 1. 새 커밋 정밀 검토
### (1) `7610258` `base.conversation_in_use` — ✅ (회귀 없음, 잔여 한계 R-1)
- **세션 env 검사**: `AGENT_SESSION_ENV` 5종 중 하나가 uuid 와 같으면 즉시 사용 중이다. 앞선 라운드에서 이 세션으로 실측했다(env 만으로도, env 없이 argv 만으로도 True).
- **헬퍼 사슬 제외는 첫 에이전트 CLI 조상에서 멈춘다.** `_is_agent_cli` 는 첫 옵션 이전 토큰의 basename 을 본다. 토큰 판독 사례:
- `node …/claude …`, `env X=1 claude …`, `/bin/sh …/agy …` → 에이전트 ✓
- `sh -c "…"`, `bash orc_onboard.sh --remove …`, `python -m lib_py.agents purge …` → 에이전트 아님(첫 옵션에서 판독 중단) ✓
- **오탐**: 위치 인자의 basename 이 우연히 에이전트 이름인 비-에이전트 프로세스(`vim notes/claude`, `python tools/codex`)는 에이전트로 판정된다. 다만 걷기가 거기서 멈춰도 purge 와 `orc_onboard.sh` 는 그 아래 헬퍼 사슬에 남으므로, 그런 프로세스가 둘 사이에 끼어야만 영향이 있다. 사실상 영향 없음.
- **미탐(R-1, 앞선 라운드 재현 A)**: 에이전트 이름으로 보이지 않는 조상(`python -m <agent>`, `node …/cli.js`)이 uuid 를 argv 에 갖고 있고 세션 env 도 없으면 헬퍼 사슬로 제외된다. 현재 배포(claude)는 이름과 env 양쪽으로 잡히므로 비차단이다. "알려진 헬퍼만 제외" 방식을 후속으로 권장한다.
### (2) `fae70c1` agy in-use · `has_artifacts` · 해결기 2단계 — ✅ (잔여 한계 R-a)
- **코드**:
- `AgyAgentAdapter._artifact_paths`(`agy.py:77-84`): DB, `-wal`/`-shm`/`-journal`, `brain/<uuid>`, annotation, presence lock 7경로.
- `has_artifacts`(`:86-90`): 그중 하나라도 있으면 True.
- `conversation_in_use` override(`:92-96`): 7경로 전부를 `lsof` 에 넘긴다.
- `BaseAgentAdapter.has_artifacts` 기본값(`base.py:194-200`): `uuid in path and os.path.exists(path)` — 기존 해결기의 경로 폴백과 **동일**하다. 그래서 claude·hermes·grok·codex 의 해결은 그대로이고, 공유 DB 인 opencode 는 경로에 uuid 가 없어 매치되지 않는다.
- `_resolve_purge_target`(`__main__.py:34-39`): 2단계가 `has_artifacts` 로 바뀌었다(1단계 revalidate `verify_artifact` 는 그대로).
- **샌드박스 재현(HEAD `fae70c1`, 매 케이스 새 `uuid4`)**:
| 경우 | 결과 |
|---|---|
| **R1**: 보유자가 presence lock 만 `flock` 으로 열고 argv·env 어디에도 uuid 가 없음(argv 에 uuid 없음을 확인) | `adapter.conversation_in_use` → **True**, CLI purge → **rc 4**, 존재하던 4조각 모두 보존 |
| **R2**: DB 없이 `-wal` + annotation 만 남음, `agy` 명시 | **rc 0**, agent `agy`, 2조각 purge, residual `[]` |
| R2, `auto` | **rc 0**, agent `agy`, 2조각 purge, residual `[]` |
| 아무것도 없음 | **rc 5**, agent `null`(미해결과 구분 유지) |
| 회귀: claude transcript 만 있음 | `auto` → **claude** 로 해결 |
| 회귀: opencode 공유 저장소만 있음, 무작위 uuid | `has_artifacts` False, `auto` → **rc 5** |
- **R-a (이미 보류된 항목, 이번 재현으로 증거 추가)**:
- 어댑터 `purge_artifacts` 는 여전히 **lock 을 지울지 정할 때만**, 그것도 DB·brain·annotation 을 **지운 뒤에** in-use 를 본다.
- 이 메서드를 직접 부르는 `stop_session.sh:329` 경로에서 lock 보유자가 있으면 DB·brain·annotation 을 지우고 lock 만 남긴다(재현: 3조각 삭제, lock 보존).
- CLI·`orc_onboard` 경로는 파괴 작업 **전에** 7경로 전체로 검사하므로 codex R1 의 "파괴 전 검사" 요구를 충족한다. `stop_session` 은 herdr 사망 pre-gate 를 거치므로 남는 경우는 "다른 프로세스가 같은 대화를 쥔" 드문 상황이다.
- **권장**: `purge_artifacts` 첫머리에서 `conversation_in_use` 가 참이면 빈 목록과 경고로 전체를 건너뛸 것(후속 이슈).
## 2. 검증 항목별 결과
| # | 항목 | 결과 |
|---|---|---|
| (1) | `7610258` 헬퍼 사슬·`_is_agent_cli` | ✅ §1-(1). R-1 비차단 |
| (2) | `fae70c1` agy in-use·`has_artifacts`·해결기 | ✅ §1-(2). 다른 어댑터 해결 영향 없음. R-a 비차단(보류 항목) |
| (3) | `orc_onboard.sh` 흐름 · SKILL.md · VERSIONS.md 정합 | ✅ purge 선행·exit 4(`--yes` 없음)/5(in-use, 등록 유지)·dry-run 무변경. SKILL.md 의 고아 조각·lock `lsof` 문단과 VERSIONS 항목 1·2 가 코드와 일치. **단 `VERSIONS.md:52` "신규 테스트 24개 … `test_issue10_13_purge.py` 17개" 가 낡았다** — 실제 19 + 7 = **26**(`fae70c1` 이 2개 추가). 병합 전 한 줄 정정 권장(비차단) |
| (4) | #15 경로 · `job_subscriber --registry-dir` | ✅ 무변경(`default_registry_dir()`, 운영 호출은 모두 명시) |
| (5) | 버전 락스텝 | ✅ `lib.sh:32`·`eager.py:16` = 4.4.3, `verify_framework_version` 통과, 릴리스 커밋 `0282312` 제목 그대로 |
| (6) | 테스트 · 정적 검사 | 아래 |
- **선택 실행 9파일**(브리프 지정 8 + `test_version_consistency`): **250 passed in 163.4 s, rc 0**(`test_issue10_13_purge.py` 23건 포함 — `fae70c1` 의 lock 전용 보유자·고아 부속 파일 테스트 포함).
- **#15 누수 실측**: 실행 전후 실제 `.mam/jobs` 레코드 목록이 **동일**했다(추가 0건).
- **정적 검사**:
- `py_compile`: `base.py`, `agy.py`, `__main__.py`, 테스트 파일 통과
- `bash -n orc_onboard.sh` 통과
- `git diff --check bd3df89...HEAD` 클린
- `verify_framework_version` 통과
- 작업 트리 깨끗, HEAD `fae70c1`
- purge 테스트 파일의 고정 UUID 리터럴 0건
## 3. 비차단 권고 (후속 이슈 1건으로 묶기를 권장)
1. **`VERSIONS.md:52` 테스트 수 정정**: 24/17 → 26/19. 목록에 "presence lock 만 연 보유자 거부, 고아 부속 파일로 agy 해결·purge" 추가. 병합 전 권장.
2. **R-a**: 어댑터 `purge_artifacts` 에서 in-use 이면 전체 건너뛰기(§1-(2)).
3. **R-1**: 에이전트 판정의 이름 의존 → 알려진 헬퍼만 제외.
4. **위임 래퍼의 브리프 argv 전달**: `ps` 노출이자 f5a6575 이 겪은 argv 충돌의 근본 원인. 파일이나 stdin 으로 전달 권장.
5. **R-b / R-c / R-e**: 등록 UUID 확인, claude 교차 프로젝트 탐색, 상속 `WORKSPACE_ROOT`.
## 4. GM 참고
- codex 의 NOT PASS(R1/R2)는 `fae70c1` 에서 해소되었다(위 재현). codex 가 이 HEAD 를 다시 확인하는 것이 만장일치 판정의 전제다.
- agy·grok 의 직전 PASS 는 `f5a6575` 기준이라 `fae70c1` 은 포함하지 않는다.
## 5. 종합
- `fae70c1` 은 codex R1(lock 만 연 보유자)과 R2(고아 부속 파일)를 정확한 위치에서 최소 변경으로 고쳤다. 기본 `has_artifacts` 가 기존 폴백과 같아 다른 어댑터의 해결은 바뀌지 않았다. 앞선 라운드 결과(N1·N2·#10·#11·#15·락스텝)도 회귀 없이 유지된다.
- 남은 항목은 이미 보류된 R-a·R-1 과 changelog 테스트 수 한 줄이다. 설계 재검토는 필요 없다.
[VERDICT: PASS]
@@ -0,0 +1,44 @@
# Round 2 review — fix/issue-10-11-13-15
Job: `79204d61`. Reviewer: `planner-reviewer-codex-01`.
Base: `bd3df89`. Reviewed HEAD: `fae70c13d9a7fb9df50e1bfe759f39e35d3e1500`.
PASS. Both findings from job `f315859f` are resolved. No additional blocking defect was found in this review.
## Scope and findings
Reviewed the branch diff from `bd3df89` and all five commits (`c82ea75`, `0282312`, `7610258`, `f5a6575`, `fae70c1`). Previously reviewed, unchanged sections received regression checks; the self-session protection, randomized fixtures, and artifact-resolution changes received detailed inspection.
| Requested area | Assessment |
|---|---|
| Prior R1: held presence lock | Fixed. The agy override passes DB, sidecars, brain directory, annotation, and presence lock to the shared detector. An independent temporary-home probe with an exclusively locked presence file returned `True` while held and `False` after release. The new CLI regression also verifies refusal and preservation of artifacts. |
| Prior R2: orphan artifacts | Fixed. The agy adapter's `has_artifacts` recognizes known auxiliary paths even without a DB. Independent explicit-agy resolution succeeded with only a presence file. The new auto-resolution test purges orphan WAL, annotation, and lock files and checks empty residuals. |
| Other adapters/shared DB | The default `has_artifacts` preserves the previous `uuid in artifact_path and exists` predicate. Verification still runs before fallback, and opencode remains last. Controlled-path checks for claude/hermes/grok/codex/opencode confirmed UUID-bearing paths are accepted and an unrelated shared path is rejected. These were predicate checks, not destructive backend operations. |
| Self-session protection | Session environment values are checked before process inspection. The excluded helper chain stops at the nearest recognized agent CLI, allowing that ancestor's UUID to count. Ordinary helper ancestors remain excluded; non-helper process matches count as holders. The passing tests cover helper ancestry, agent ancestry, and all five listed session variables. |
| Onboarding flow | Purge precedes registry mutation; CLI in-use exit 4 maps to onboarding exit 5, missing confirmation returns 4, and dry-run exits before purge. The corrected `added`/`removed` wording remains intact. |
| Registry isolation | CLI/service defaults retain explicit override → existing WORKSPACE_ROOT → cwd precedence. The subscriber now uses `default_registry_dir()`. An independent parser check intercepted subscriber execution before network access and confirmed the workspace-derived path. Sandbox isolation and the adjusted R1/B-9/snapshot expectations remain consistent. |
| Version/docs | Shell and eager constants, eight frontmatters, matrix and current documentation remain 4.4.3. The release commit subject is exactly `release(v4.4.3): bump framework and eight skills to 4.4.3 in lockstep`. Remaining 4.4.2 text in checked current documents is the historical changelog heading. The skill and release notes describe the held-lock and orphan fixes. |
The process detector remains heuristic: UUID text in unrelated processes can cause a conservative refusal, as documented, and agent-name token parsing recognizes the supported command forms rather than every possible interpreter launcher. File-descriptor detection depends on working `lsof`; the current run exercised it successfully. These limits do not reopen the two reproduced findings. WORKSPACE_ROOT remains an authoritative override, so callers changing workspaces must supply the intended root or explicit directories.
## Validation
Fresh run at the reviewed HEAD: **250 passed in 178.94 seconds**.
```text
tests/test_issue10_13_purge.py
tests/test_issue15_registry_isolation.py
tests/test_orc_onboard.py
tests/test_a4_adapter_contract.py
tests/test_issue5_phase1_delegation.py
tests/test_tier1_unit.py
tests/test_loop_cli.py
tests/test_issue5_phase4_runtime.py
tests/test_version_consistency.py
```
Full-branch `git diff --check` passed. Individual `bash -n` checks passed for lib.sh, onboarding, create, and stop scripts. `verify_framework_version()` passed with MAM_VERSION read from lib.sh and the imported eager constant. Final inspection confirmed the same HEAD and a clean tracked worktree. The full repository suite was not rerun.
Only this review report was added. No source edits, commits, pushes, merges, real-home purges, registered-orchestrator removals, or operations in the excluded second worktree were performed. Independent fixtures used temporary homes and fresh UUID4 identifiers. Progress events were published during review and testing.
[VERDICT: PASS]
@@ -0,0 +1,134 @@
# Peer Review Report: Branch `fix/issue-10-11-13-15` & v4.4.3 Lockstep (Round 2 Cross-Review)
- **Reviewer**: `agy` (`herdr:reviewer-agy-01`)
- **Job ID**: `0f41ea47`
- **Target Branch**: `fix/issue-10-11-13-15` @ `fae70c1` (base `main` @ `bd3df89` v4.4.2)
- **Commits Reviewed**:
- `c82ea75` — `fix(issue-10,11,13,15): complete agy purge, orchestrator purge, workspace-anchored registry`
- `0282312` — `release(v4.4.3): bump framework and eight skills to 4.4.3 in lockstep`
- `7610258` — `fix(issue-13): refuse to purge the conversation the caller is running in`
- `f5a6575` — `test(issue-13): give each purge test fresh conversation ids`
- `fae70c1` — `fix(issue-10,13): check every agy artifact for holders and purge orphaned leftovers`
- **Review Date**: 2026-09-13 (KST)
---
## 1. Executive Summary
Branch `fix/issue-10-11-13-15` resolves issues #10, #11, #13, and #15 while integrating peer-review feedback across two review loops.
In loop 1 (round 1), codex identified two edge cases:
- **R1**: `agy` in-use check passed only the main DB file to `lsof`, missing processes holding open the presence lock (or sidecars) without the UUID in command line arguments or environment variables.
- **R2**: Orphaned leftovers (e.g. WAL, annotations, or presence lock surviving after an interrupted or pre-#10 purge where the main DB was already gone) failed to resolve as a purge target because resolution relied on DB existence.
Commit `fae70c1` directly resolves both codex findings through:
1. `AgyAgentAdapter.conversation_in_use`: Passes all conversation paths (`_artifact_paths`: DB, sidecars, brain, annotation, presence lock) to `lsof -t`.
2. `AgyAgentAdapter.has_artifacts`: Recognizes any existing artifact piece even if the primary DB has already been deleted.
3. `BaseAgentAdapter.has_artifacts`: Replaces the resolver's ad-hoc path fallback with a clean polymorphic method defaulting to `uuid in path and os.path.exists(path)`, correctly preventing `opencode` (shared DB) from falsely claiming non-opencode UUIDs.
Together with caller session recognition (`7610258`) and dynamic test fixtures (`f5a6575`), the branch is complete, robust, and verified.
All 250 targeted tests across 9 test suites passed with zero failures and zero leaks into the live `.mam/jobs` registry.
---
## 2. In-Depth Technical Verification
### (1) Codex R1 & R2 Solutions (`fae70c1`)
- **Codex R1 (`AgyAgentAdapter.conversation_in_use`)**:
```python
def _artifact_paths(self, uuid: str, ctx: DiscoveryContext) -> list:
db = self.artifact_path(uuid, ctx)
root = self._cli_root(ctx)
return ([db] + [f"{db}{suffix}" for suffix in ("-wal", "-shm", "-journal")]
+ [f"{root}/brain/{uuid}", f"{root}/annotations/{uuid}.pbtxt",
f"{root}/presence/{uuid}.lock"])
def conversation_in_use(self, uuid: str, ctx: DiscoveryContext) -> bool:
return conversation_in_use(uuid, self._artifact_paths(uuid, ctx))
```
`conversation_in_use` passes every associated file path to `lsof -t`. Even if a process holds open only `presence/<uuid>.lock` (or a `-wal` sidecar) via `flock` and carries neither the UUID in `ps` command-line arguments nor any session environment variable, `lsof` catches the active file descriptor and refuses the purge. Verified by `tests/test_issue10_13_purge.py::test_purge_cli_refuses_when_only_the_presence_lock_is_held_open`.
- **Codex R2 (`AgyAgentAdapter.has_artifacts` & Orphan Resolution)**:
```python
def has_artifacts(self, uuid: str, ctx: DiscoveryContext) -> bool:
return any(os.path.exists(p) for p in self._artifact_paths(uuid, ctx))
```
If the main DB was previously unlinked or deleted, any remaining orphaned WAL files, annotations, or presence locks are recognized by `has_artifacts`. `_resolve_purge_target` correctly identifies `agy` as the owning agent and purges the stranded artifacts completely. Verified by `tests/test_issue10_13_purge.py::test_purge_cli_resolves_agy_from_orphaned_leftovers`.
- **`BaseAgentAdapter.has_artifacts` Default Contract & Resolver Integration**:
In `lib_py/agents/base.py`:
```python
def has_artifacts(self, uuid: str, ctx: DiscoveryContext) -> bool:
path = self.artifact_path(uuid, ctx)
return uuid in path and os.path.exists(path)
```
In `lib_py/agents/__main__.py` `_resolve_purge_target`:
```python
for name, adapter, ctx in probes:
try:
if adapter.has_artifacts(uuid, ctx):
return name, adapter, ctx
except Exception:
continue
```
- **Shared Store Isolation**: `opencode` uses a shared database path (`opencode.db`) which does not embed the UUID (`uuid in path` is `False`). Thus `opencode` never falsely claims other agents' UUIDs in the fallback pass.
- **Other Adapters (`claude`, `hermes`, `grok`, `codex`)**: All embed the UUID in their artifact paths (`f".../{uuid}.jsonl"`, etc.). Their resolution behavior remains identical to the historical contract.
### (2) Caller Session Protection (`7610258`) & Dynamic Fixtures (`f5a6575`)
- **`AGENT_SESSION_ENV` Verification**:
Inspects `CLAUDE_CODE_SESSION_ID`, `ANTIGRAVITY_CONVERSATION_ID`, `HERMES_SESSION_ID`, `GROK_SESSION_ID`, and `OPENCODE_SESSION_ID`. If the caller's environment carries the target UUID, `conversation_in_use` immediately returns `True`.
- **Helper-Chain Pruning (`_is_agent_cli`)**:
Excludes the purge command's own non-agent helper processes (python interpreter, shell runners) but halts exclusion at the nearest agent CLI ancestor (`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`). If that agent CLI ancestor carries the UUID on its command line, it is treated as an active holder.
- **Dynamic Test Fixtures (`f5a6575`)**:
All purge tests in `test_issue10_13_purge.py` use dynamic `uuid4` fixtures (`conv` and `other`), preventing false "in use" detections caused by concurrent delegation wrappers whose command-line prompts carry test file diffs.
### (3) `orc_onboard.sh` Flow & Documentation Alignment
- Purge executes **before** registry mutation. A refused purge (exit code `5` due to in-use detection) leaves `.mam/agent-sessions.yaml` untouched.
- Confirmation gate (`--yes`) prevents accidental deletion (exit code `4`).
- Missing on-disk artifacts emit a warning and cleanly remove the UUID registration (exit code `0`).
- Past-tense grammatical correction maps `add -> added`, `remove -> removed`, eliminating the `removeed` typo.
- Full alignment with `multi-agent-mux-orc-onboard/SKILL.md` and `VERSIONS.md` v4.4.3.
### (4) Registry & Audit Log Resolution (#15)
- `default_registry_dir()` and `get_logs_dir()` prioritize `MAM_JOBS_DIR`/`DELEGATE_JOB_LOGS_DIR` &rarr; `$WORKSPACE_ROOT/.mam/...` &rarr; `<cwd>/.mam/...`.
- `job_subscriber.py` argument default updated to `default_registry_dir()`.
- Verified zero test jobs leaked into `.mam/jobs` during test suite runs.
### (5) Version Lockstep Completeness (`v4.4.3`)
- `MAM_VERSION="4.4.3"` in `.agents/skills/lib.sh`.
- `FRAMEWORK_VERSION = "4.4.3"` in `.agents/skills/lib_py/loop/eager.py`.
- 8 `SKILL.md` frontmatter versions: `4.4.3`.
- `VERSIONS.md`: Current release `v4.4.3`, 8-row skills matrix `4.4.3`, and changelog section updated to document codex R1/R2 and claude N1 refinements.
- Documentation badges in `README.md`, `README.ko.md`, `BOOTSTRAP.md`, `BOOTSTRAP.ko.md`, and `MESSAGING.md` header all synchronized.
- Verified no non-historical `4.4.2` references remain.
---
## 3. Test Suite Verification Results
All tests executed with active MQTT heartbeat tracking:
| Test Suite | Result | Details |
| :--- | :---: | :--- |
| `tests/test_issue10_13_purge.py` | 23/23 PASS | Includes presence lock holder test (R1) & orphaned leftover purge test (R2) |
| `tests/test_issue15_registry_isolation.py` | 7/7 PASS | Resolution hierarchy & onboarding leak prevention |
| `tests/test_orc_onboard.py` | 37/37 PASS | Onboarding CLI, remove, past tense message, ownership verification |
| `tests/test_a4_adapter_contract.py` | 33/33 PASS | Agent adapters contract compliance, 2-item purge base invariant |
| `tests/test_version_consistency.py` | 3/3 PASS | 3-way version lockstep, runtime mismatch rejection, env immutability |
| `tests/test_issue5_phase1_delegation.py` | 66/66 PASS | Delegation CLI, snapshot contracts, event publishing |
| `tests/test_tier1_unit.py` | 53/53 PASS | Unit tests, path resolution, B-9 logs directory |
| `tests/test_loop_cli.py` | 9/9 PASS | Loop CLI parsing, creator requirement, planner auto-resolution |
| `tests/test_issue5_phase4_runtime.py` | 5/5 PASS | Python core loop runtime execution & lifecycle |
| **Total Targeted Tests** | **250/250 PASS** | **All 250 tests passed cleanly (0 failures, 0 regressions)** |
### Live Registry Immutability Audit
- Pre-test and post-test inspections of `.mam/jobs` confirmed that zero test job records were written to the real repository registry.
---
## 4. Conclusion
The refinements in `fae70c1` thoroughly and elegantly address codex review findings R1 and R2 without introducing any regressions or architectural friction. All six review criteria are completely satisfied.
[VERDICT: PASS]
@@ -0,0 +1,59 @@
# 🔍 Review Report — Job 3ea06fb6 (`fix/issue-10-11-13-15` 2회차, HEAD `fae70c1`)
- **Reviewer**: `reviewer-grok-01` (role: reviewer) · 2026-09-13
- **범위**: `git log`/`git diff` **`bd3df89...HEAD`**
- **HEAD**: `fae70c1` `fix(issue-10,13): check every agy artifact for holders and purge orphaned leftovers`
- **선행**: `ba3e3ab5` PASS(`0282312`) → `4b113d10` NOT PASS(N2) → `1752c893` PASS(`f5a6575`). 이번 초점: `7610258` 재확인 + **`fae70c1` Codex R1/R2**.
- **안전**: 실제 홈 purge 없음. 테스트는 uuid4 픽스처만. 다른 worktree 미접촉. 소스 무변경.
커밋: `c82ea75` → `0282312` → `7610258` → `f5a6575` → **`fae70c1`**.
## (1) `7610258` `conversation_in_use`
- `AGENT_SESSION_ENV` 5종이 uuid 와 같으면 즉시 in-use.
- cmdline 헬퍼 사슬은 **자기부터 가장 가까운 `_is_agent_cli` 조상 직전**만 제외. 그 조상이 uuid 를 들고 있으면 holder.
- `_is_agent_cli`: 첫 `-` 옵션 이전 토큰의 basename ∈ `{claude,agy,hermes,grok,opencode,codex}`.
오탐/미탐: `python -m <agent>` 조상은 이름 매칭이 안 되어 헬퍼로 남을 수 있음(배포 claude/agy 바이너리 경로에서는 env+basename 으로 잡힘). uuid 를 **언급만** 하는 프로세스도 holder — SKILL.md 가 그렇게 문서화. 자기 세션 purge 거부는 유지.
## (2) `fae70c1` R1/R2
**R1** `AgyAgentAdapter.conversation_in_use` (`agy.py:92-96`): `_artifact_paths` 의 DB·wal/shm/journal·brain·annotation·**lock** 전부를 `conversation_in_use(..., paths)` 에 넘김. cmdline/env 없이 lock 만 `flock` 한 보유자도 `lsof` 에 잡힘. `test_purge_cli_refuses_when_only_the_presence_lock_is_held_open` 통과. CLI 는 그 결과로 exit 4, **아무것도 안 지움**.
**R2** `has_artifacts`:
- 기본 (`base.py:194-200`): `uuid in artifact_path and exists`. 공유 DB(`opencode` → `opencode.db`, 경로에 uuid 없음)는 모든 uuid 에 매치되지 않음.
- agy 오버라이드 (`agy.py:86-90`): `_artifact_paths` 중 하나라도 있으면 참 (DB 없는 WAL/annotation/lock).
- `_resolve_purge_target` 2단계: `verify_artifact` 후 `has_artifacts` (옛 `uuid in path and exists` 대체). claude/hermes/grok/codex 경로는 uuid 를 포함하므로 기존 폴백과 동등. `test_purge_cli_resolves_agy_from_orphaned_leftovers` 통과.
다른 어댑터는 `has_artifacts` 를 오버라이드하지 않음. verify 가 먼저이므로 정상 jsonl/session 파일은 1단계에서 해결.
## (3) `orc_onboard.sh` / 문서
흐름 불변: `--yes` 없으면 exit 4, Python in-use 4 → 셸 5(등록 유지), 미해결 5 → WARN 후 등록 제거, dry-run 무변경, purge 가 YAML 앞. SKILL.md·VERSIONS.md v4.4.3 항목 1–2 가 lock 전 경로 `lsof` 와 고아 부속을 반영.
## (4) #15
`MAM_JOBS_DIR` → `WORKSPACE_ROOT/.mam/…` → cwd. `job_subscriber --registry-dir` 기본값 `default_registry_dir()` (`7610258` R-d). conftest 격리 유지.
## (5) 락스텝
`lib.sh`/`eager.py`/8 SKILL.md/`VERSIONS.md` = **4.4.3**. `verify_framework_version` 통과. 릴리스 커밋 `0282312` 제목 유지. `fae70c1` 은 changelog 항목 1–2 만.
## (6) 테스트
```
.venv/bin/python -m pytest -q \
tests/test_issue10_13_purge.py tests/test_issue15_registry_isolation.py \
tests/test_orc_onboard.py tests/test_a4_adapter_contract.py \
tests/test_issue5_phase1_delegation.py tests/test_tier1_unit.py \
tests/test_loop_cli.py tests/test_issue5_phase4_runtime.py \
tests/test_version_consistency.py
```
**250 passed in 162.54s** (직전 248 + R1/R2 2건). uuid4 픽스처. `git diff --check` 클린. 전체 스위트 미실행.
## 종합
Codex R1(lock-only holder)과 R2(고아 부속)가 어댑터 단위로 닫혔고, 1회차 PASS 항목은 회귀 없음. 설계 재작업 불필요.
[VERDICT: PASS]