claude, agy, grok: PASS with amendments; codex: NOT PASS (recipe overstates current env-override support; review identity and lifecycle ownership underspecified). Direction (creator per worktree, shared reviewer pool) agreed by all four. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
70 lines
6.7 KiB
Markdown
70 lines
6.7 KiB
Markdown
# 🔍 Design Review — Job 2174eaaf (`worktree-creator-model.md` @ `fe96db1`)
|
||
|
||
- **Reviewer**: `reviewer-grok-01` · 2026-09-14
|
||
- **문서**: `multi-agent-mux-wt/design-worktree-model/docs/design/worktree-creator-model.md` (`git log -1` = `fe96db1`). 본 체크아웃은 `main`.
|
||
- **성격**: 설계 리뷰. 코드·문서 미수정, 체크아웃 미전환.
|
||
|
||
제안 C(creator=워크트리, 리뷰어 풀=본 체크아웃, `.mam` 공유)는 두 문제(병렬 구현, 공유 체크아웃 `checkout` 사고)를 **채택 가능한 수준으로** 풀며, §5 에 빠진 실패 경로를 보완하면 구현에 들어갈 수 있다.
|
||
|
||
## §6 질문
|
||
|
||
### 1. 역할 분리가 두 문제를 푸는가? — **동의 + 보완**
|
||
|
||
- **병렬성**: creator 가 이슈별 cwd/브랜치를 가지면 구현은 동시에 진행된다. 리뷰어 풀은 잡 단위 직렬(`session_busy` rc 5 → `MAM_SESSION_BUSY_RETRY_S` 1회, `runner.py:313-314`). 문서 §4 서술과 맞다.
|
||
- **checkout 사고**: 본 체크아웃을 `main` 에 고정하고 오케스트레이터·creator 커밋을 워크트리에서만 하면, 공유 `checkout` 한 방으로 전원이 움직이는 경로는 사라진다.
|
||
- **놓친 경로 (문서를 고칠 곳: §4 한계 / §5 추가)**:
|
||
- 리뷰어가 `$WT` 에서 pytest 를 돌리면 `.pytest_cache`/`__pycache__`/실패 산출물이 워크트리에 남아 creator 가 dirty 로 본다. PYTHONDONTWRITEBYTECODE, `--basetemp` 를 WT 밖, 리뷰 후 `git status` 제약을 §5 에 적을 것.
|
||
- 워크트리 삭제 전 `stop` 없이 `worktree remove` 하면 yaml 행·herdr pane 이 남는다. 레시피에 stop → worktree remove 순서.
|
||
- 모니터 **자동등록** (`reconcile.sh:651-654`) 은 `pane.cwd` 가 `WORKSPACE_ROOT` 또는 그 하위일 때만 탄다. WT 가 `.../multi-agent-mux-wt/issue-20` 이면 MAIN 의 prefix 가 아니므로 **미등록 herdr 세션은 자동등록되지 않는다**. yaml 에 이미 있는 행은 이 필터를 타지 않는다. “create 레시피로만 등록”을 §3 에 명시할 것. yaml 행을 drift 로 지우지는 않음(이름 매칭).
|
||
|
||
### 2. 제어 평면 env override 가 안전한가? — **동의 + 보완 (필수)**
|
||
|
||
| 변수 | 근거 | C 안에서 |
|
||
|---|---|---|
|
||
| `WORKSPACE_ROOT` | `lib.sh:26-27` 이미 override | MAIN 으로 두면 yaml/jobs 기본이 MAIN |
|
||
| `AGENT_SESSIONS_YAML` | `lib.sh:34` | 명시하면 안전. 미설정 시 `WORKSPACE_ROOT/.mam/...` |
|
||
| `MAM_JOBS_DIR` / `DELEGATE_JOB_LOGS_DIR` | `mqtt_common.py:150-163`, `186-187` — `MAM_JOBS_DIR` 우선, 아니면 `WORKSPACE_ROOT/.mam` | `WORKSPACE_ROOT=MAIN` 만으로도 jobs 는 MAIN. 문서의 네 변수는 과잉이 아니라 방어. |
|
||
|
||
- **status**: `status.sh:59-76` 이 **행의 `pane.cwd`** 로 claude 프로젝트 키를 만든다. WT cwd 행을 MAIN `WORKSPACE_ROOT` 와 혼동하지 않음. **동의.**
|
||
- **resume/stop**: `resume_session.sh:42,165` 은 `--workspace` 가 pane 생성 cwd. `verify_session_uuid` (`verify_session.py:90-93`) 는 `workspace_key(pane.cwd) != workspace_key(ws)` 이면 **즉시 False**. `find_workspace_uuid` (`workspace_uuid.py:57-59`) 도 pane.cwd 와 `--workspace` 일치만 본다. 따라서 resume/stop 의 `--workspace` 는 **MAIN 이 아니라 WT(pane.cwd)** 여야 한다. `WORKSPACE_ROOT`/yaml 은 MAIN. **§3 레시피에 이 이원성을 쓰지 않으면 resume 이 깨진다.** 고칠 곳: §3 코드블록 다음 문단.
|
||
- **claude 저장 키**: `claude.py:117-118` `workspace_key(ctx.workspace)` → `~/.claude/projects/<cwd 키>`. create `--workspace WT` 이면 키가 WT. resume 도 WT 를 넘겨야 한다. 문서 표(§1)와 맞음.
|
||
- **토픽 지문**: `reconcile.sh:288-290` `sha256(abspath(WORKSPACE_ROOT))[:12]`. 모니터·creator 가 같은 `WORKSPACE_ROOT=MAIN` 이면 지문이 하나. HMAC/`auth_token` 은 job 레코드 단위라 공유 레지스트리와 맞음. 워크트리에서 override 없이 reconcile 을 돌리면 지문이 갈라진다 → 모니터는 항상 MAIN 에서.
|
||
|
||
### 3. A/B 대비 C 비용·이득 — **동의**. 더 싼 1단계가 있다.
|
||
|
||
- A: 이슈당 에이전트 5개·문맥 리셋·`.mam` 분산. 비쌈. 동의.
|
||
- B: 병렬 없음 + creator 가 본 체크아웃을 옮김. #18 유형 잔존. 동의.
|
||
- C: 구현 병렬 + 리뷰 문맥 유지 + 제어 평면 하나. 맞다.
|
||
- **대안 D (비차단)**: 리뷰어에게도 **같은 브랜치의 읽기 전용 워크트리**를 주면 MAIN 테스트 오염을 줄인다. 비용↑. 1단계 C 로 시작하고 D 는 선택.
|
||
- **대안 E** (훅으로 main checkout 금지): 병렬을 안 줌. C 를 대체하지 못함.
|
||
|
||
### 4. §5 누락·과잉 / 다중 루프를 먼저? — **보완**
|
||
|
||
| §5 | 판정 |
|
||
|---|---|
|
||
| 1 브리프 절대경로 | **필수, 범위 부족.** `multi-agent-mux-delegate-job:199` 주입이 `.mam/jobs/<id>/brief.md` 상대경로. creator cwd=WT 에는 없음. 같은 파일 `:178` **Output Report Path** 도 상대경로. 루프 `find_report` (`runner.py:389-394`) 는 `self.mam_dir/jobs/<id>` = MAIN. creator 가 WT 에 리포트를 쓰면 루프가 못 찾는다. **brief 와 report-final.md 모두 `$REGISTRY_DIR` 절대경로.** |
|
||
| 2 `--worktree` | **필수.** `collect_changes_diff` `runner.py:399-408` 과 `base_commit` `runner.py:564-565` 가 `cwd=self.workspace_root`(MAIN HEAD). 워크트리 브랜치 diff 가 아님. 인용 정확. |
|
||
| 3 create 레시피 | **필수.** resume `--workspace $WT` 이원성 추가. |
|
||
| 4 `.mam` 경합 | **두 `run_loop.sh` 전에 필수, 1단계에는 과잉 가능.** `loop-checkpoint.json` (`runner.py:60`)·`loop-guard-active` (`:427`) 는 파일 하나. 두 루프는 체크포인트를 덮어쓴다. **시작은 “루프는 하나, creator 잡은 delegate-job 으로만 병렬”.** 이슈당 루프를 동시에 돌리려면 §5-4 가 선행. §4 문장에 이 단계를 밝힐 것. |
|
||
| 5 브리프 필드 | 필수. |
|
||
|
||
### 5. #17 항목 4 와의 순서 — **동의**
|
||
|
||
운영 모델(C)을 문서·레시피로 고정한 뒤, 항목 4(셸 계층 축소)에서 `--worktree`·절대 브리프/리포트 경로를 코드로 흡수하는 순서가 맞다. 항목 4 를 먼저 하면 워크트리 cwd 가 다시 깨진다.
|
||
|
||
## 브리프 (1)–(7) 요약
|
||
|
||
| # | 판정 |
|
||
|---|---|
|
||
| (1) env 일관성 | 동의. resume/stop `--workspace`=pane.cwd(WT). status 는 pane.cwd 사용. |
|
||
| (2) 상대 brief | 동의, 깨짐. 리포트 경로도 깨짐. |
|
||
| (3) diff/base | 동의, `runner.py:399-408`·`564-565`. |
|
||
| (4) 다중 루프 | 실위험. 1단계는 루프 하나. |
|
||
| (5) 실패 경로 | pytest 오염, yaml 잔행, 모니터 자동등록 prefix, 잘못된 WORKSPACE 로 resume. 토픽/HMAC 은 공유 `.mam` 이면 안전. |
|
||
| (6) A/B/C | 타당. D 는 후속. |
|
||
| (7) #17-4 | 문서 먼저. |
|
||
|
||
채택 가능. 근본 결함 없음. 구현 전 §3·§5-1·§5-4 문구를 고치면 된다.
|
||
|
||
[VERDICT: PASS]
|