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
94 lines
8.8 KiB
Markdown
94 lines
8.8 KiB
Markdown
# 🔍 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]
|