Files
multi-agent-mux/.agents/reports/planner-reviewer-claude-01/report-f1132474.md
T

66 lines
6.1 KiB
Markdown

# Issue #60 리뷰 3차 — opencode 2.x 전용 지원 (job f1132474)
- 리뷰어: planner-reviewer-claude-01
- 검증 경로: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261018T073639Z-b5cb7f/1`
- identity: HEAD `0e05b1b6777ceb837066454ac688e04a0f5d14a0`, tree `c5cb1b16af283b3fdb447bafb865ba1abbfbb5a8` — 일치, 작업 트리 clean, `.mam` 없음. base..head 5커밋(a311c23, f0d1c00, 6b4b96f, cb5f439, 0e05b1b). 판정은 base..head 전체에 대해 내린다.
- 1차(6b4b96f)·2차(cb5f439)에서 실바이너리로 확인한 사항은 0e05b1b 가 건드리지 않은 제품 코드라 그대로 유효하다. 0e05b1b 는 status.sh, tests/_agent_home_guard.py, tests/test_issue60_opencode_v2.py 만 바꿨다. 확인한 사항:
- 측정 사실과 구현의 일치
- `session delete` 의 자식 삭제, cwd 무관, 공유 행 보존
- 3단 자손 정리
- 서비스 보유자 제외
- `--standalone` 수명
- resident children
- 실제 opencode 데이터는 읽기(`grep -c`, `stat`)로만 봤다.
## 결론
2차 차단 지적(B1)과 비차단 N1·N2 가 모두 해결됐고 새 회귀는 찾지 못했다. base..head 전체를 병합 가능으로 판단한다. 남은 것은 테스트 보강 권고뿐이다.
## 2차 지적별 확인
**B1 (XDG_DATA_HOME 테스트 격리) — 해결.**
- `_agent_home_guard.DROPPED_VARS` 에 `XDG_DATA_HOME` 이 추가됐다(`tests/_agent_home_guard.py:21`). 그래서 `conftest._isolate_agent_homes`(`conftest.py:210`)가 테스트마다 이를 지운다. mam_sandbox·issue31 `home` 처럼 HOME 만 바꾸는 fixture 도 이제 `<HOME>/.local/share` 를 본다.
- 2차에서 실패한 두 테스트(tier2 opencode e2e, `test_opencode_purge_leaves_no_rows`)가 `XDG_DATA_HOME=<scratchpad>` 에서 통과한다(아래 실행 결과).
- 뮤테이션: `DROPPED_VARS` 에서 다시 빼면 그 두 테스트와 `test_issue55::test_l1_every_path_variable_the_code_reads_is_accounted_for` 가 실패한다(3 failed). L1 은 환경과 무관하게 실패하므로, 이후 누가 지워도 잡힌다.
- 세션 가드는 `XDG_DATA_HOME` 이 설정돼 있으면 `<XDG_DATA_HOME>/opencode` 를 감시한다(`:48-49`). `ambient` 는 conftest 가 drop 전에 기록한 pane 값(`_AGENT_HOME_VARS = ("HOME",) + DROPPED_VARS`)이라 올바른 위치다.
**N1 (status.sh 고정 경로) — 해결.**
- 두 Python 블록(`status.sh:105-113`, `:305-313`) 모두 `get_adapter('opencode')._resolve_db(DiscoveryContext(workspace=cwd, agent_name='opencode', home_dir=home))` 를 쓴다.
- `cwd`(`:59`/`:259`)와 `home`(`HOME_DIR`, `:41`/`:241`)은 각 블록에 정의돼 있다. `env_python` 이 `PYTHONPATH=$SKILL_DIR` 를 넣고 환경을 상속하므로(`lib.sh:1852-1871`) `lib_py` import 와 PATH·XDG 가 그대로 전달된다. 같은 파일이 이미 `lib_py.delegation.logroot` 등을 import 한다.
- 행동 확인: git archive 사본에 임시 테스트를 넣고 실행했다(mam_sandbox+mock_herdr+mock_agents → create → reconcile 로 id 고정 → status). 1 passed.
- `--json` 의 `resume_state == "yes"` 와 plain 출력 행의 `yes`, 둘 다 rc 0.
- PATH 에서 opencode 를 빼도 폴백 경로로 `yes`.
- DB 를 `XDG_DATA_HOME` 쪽으로 옮기면, XDG 없이 `MISSING`, XDG 를 주면 `yes`.
- 행을 지우면 `MISSING`. 모두 rc 0.
- status 는 이제 opencode 행마다 `opencode debug paths` 를 실행한다. 이 명령은 opencode 자신의 log 디렉터리에 기록한다. 하지만 status 가 이미 돌리는 `reconcile.sh --dry-run` 의 drift C 도 같은 `_resolve_db` 를 부르므로 새로운 종류의 부작용은 아니다.
**N2 (`--version` 탐침이 실제 로그에 기록) — 해결.**
- `_real_opencode()`(`test_issue60_opencode_v2.py:290-303`)가 `TemporaryDirectory` 를 HOME·TMPDIR 로 하고 PATH 만 넘긴다. XDG_* 는 넘기지 않는다.
- 실제 `~/.local/share/opencode/log/opencode.log` 의 `args="[\"--version\"]"` 줄 수를 읽기로 세었다. 아래 두 스위트 실행 전 50, 후 50(증가 없음) 이다.
## 테스트 실행 (검증 경로, `env -i`, basetemp 는 scratchpad)
관련 10개 모듈: a4, issue31, issue10_13, issue60, tier2, issue55, issue57(status), issue21_worktree_prereqs(status), issue30_stall_watch, tier1.
- `XDG_DATA_HOME=<scratchpad>/jf1/xdg`, PATH 에 opencode 없음: **363 passed, 1 skipped**, rc 0. 실행 뒤 그 XDG 디렉터리는 비어 있었다(아무 파일·디렉터리도 생기지 않음).
- `XDG_DATA_HOME` 미설정, PATH 에 `~/.opencode/bin` 포함(실바이너리 계약 테스트 실행): **363 passed, 1 skipped**, rc 0.
- skip 은 두 번 모두 `/proc` 전용 테스트(macOS)다. #55 가드 오탐은 없었고, 실행 뒤 남은 opencode 프로세스도 없었다.
## 비차단 (테스트 보강 권고)
- **T1.** 이번에 바뀐 두 동작은 회귀 테스트가 없다. 뮤테이션(`XDG_DATA_HOME` 설정 상태, issue55·issue60·issue31·tier2):
- 가드의 XDG 감시를 원래대로 되돌림 → 28 passed, 실패 0
- status.sh 를 고정 경로로 되돌림 → 28 passed, 실패 0
`test_issue55::test_g1` 에 `watch_dirs({"HOME": h, "XDG_DATA_HOME": x})["opencode"] == x/opencode` 한 줄을 넣고, 위 임시 테스트와 같은 status 행동 테스트(XDG 쪽 DB → `yes`)를 넣기를 권한다.
- **T2 (기존 설계).** 가드는 opencode 데이터 디렉터리의 항목 이름을 비교한다. `XDG_DATA_HOME` 이 설정된 Linux 러너에서 사용자 opencode(서비스 포함)가 그 디렉터리에 새 항목을 만들면 #55 와 같은 종류의 오탐이 날 수 있다. 판정 근거로 쓰지 말고 보고만 할 종류다.
- 1·2차 비차단 N3(다른 MAM opencode 세션이 떠 있으면 무관한 purge 도 exit 4, lsof 없는 Linux 에서는 DB 보유자 검사 생략)는 의도된 동작으로 보고 그대로 둔다.
## 병합 가능성
- base..head 전체에서 `git diff --check` 는 깨끗하다.
- 변경 Python 파일은 Python 3.9(`/usr/bin/python3` 3.9.6)로 컴파일된다. 셸 스크립트는 `/bin/bash -n`(3.2)을 통과한다.
- 1·2차의 실바이너리 검증과 뮤테이션 결과에 이번 검증이 더해져, 차단 사항이 없다.
[VERDICT: PASS]