Files
multi-agent-mux/docs/design/worktree-creator-model.md
T
GodopuandClaude Fable 5.1 fe96db1d96 docs(design): propose the worktree operating model - creator per worktree, shared reviewer pool
Design proposal for review (no code change): why the checkout-path
workspace assumption blocks parallel issues and caused the #18 checkout
switch, three candidate models, the recommended hybrid (writers isolated
per worktree, readers shared, one .mam control plane via env overrides),
how it maps onto today's scripts, what has to change, and the questions
put to the reviewers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
2026-09-14 10:10:49 +09:00

87 lines
8.6 KiB
Markdown

# 워크트리 운영 모델 제안 — creator 만 워크트리, 리뷰어는 공유 (Design Proposal)
- 상태: 제안 (리뷰 요청)
- 작성: 오케스트레이터 세션 `dbe6dd10-a210-4b46-b613-58a1860499b6`, 2026-09-14
- 배경 이슈: #17 항목 4(셸 계층 축소)·#18 사후 분석(체크아웃 전환 사고)
## 1. 문제
MAM 은 **워크스페이스 = `.agents/skills` 가 들어 있는 체크아웃 경로** 라는 가정 위에 서 있다.
| 경로에서 파생되는 것 | 근거 |
|---|---|
| `WORKSPACE_ROOT` | `lib.sh:26` — `${WORKSPACE_ROOT:-$SKILL_DIR/../..}` |
| `.mam/` (agent-sessions.yaml, jobs 레지스트리, 감사 로그, monitor.lock) | `$WORKSPACE_ROOT/.mam` (gitignore 대상) |
| herdr 서버 이름 | `resolve_herdr_session` — 워크스페이스 경로 슬러그, `--herdr-session` 으로 override |
| 모니터 토픽 지문 | `reconcile.sh:288-290` — `sha256(abspath(workspace_root))[:12]` |
| claude 대화 저장 키 | `~/.claude/projects/<cwd 경로 키>` — resume 는 같은 디렉터리여야 함 |
그 결과 두 가지 문제가 있다.
1. **동시 이슈 작업이 불가능하다.** 팀 리더 에이전트 5개와 오케스트레이터가 하나의 체크아웃을 공유하므로 브랜치는 한 번에 하나만 체크아웃된다. 이슈 A 의 리뷰 중 이슈 B 의 구현을 시작할 수 없다.
2. **체크아웃 전환 사고가 난다.** #18 작업 중 브랜치 생성 1분 뒤 HEAD 가 `main` 으로 되돌아가(reflog `moving from fix/issue-18 to main`, 18:32) 이후 12개 커밋이 `main` 에 직접 쌓였다. 병합 커밋 없이 push 되어 이력을 되돌리지 않았다. 공유 체크아웃에서는 어떤 프로세스든 `checkout` 하나로 다른 모든 참여자의 커밋 위치를 바꿀 수 있다.
## 2. 후보안
### A. 모두 워크트리별 (오케스트레이터 + creator + 리뷰어)
- 장점: 완전 격리. 현재 코드가 그대로 동작한다(워크트리 = 새 워크스페이스).
- 단점: 이슈마다 에이전트 5개를 새로 띄운다 → 토큰·요청 한도가 이슈 수에 비례(codex 는 이번 세션에서 이미 한도 도달). 리뷰어 대화 문맥이 이슈마다 초기화된다. `.mam`·모니터·토픽 지문이 이슈마다 흩어져 관측이 분산된다.
### B. 오케스트레이터 커밋만 워크트리, 에이전트는 본 체크아웃
- 장점: 오케스트레이터 커밋은 격리된다.
- 단점: **병렬성이 없다.** 에이전트는 대화 하나짜리 프로세스라 잡을 하나씩만 처리하고, 두 루프가 같은 creator·리뷰어를 두고 `session_busy`(rc 5) 로 경합해 직렬화된다. creator 는 여전히 본 체크아웃에서 브랜치를 옮겨 커밋해야 하므로 #18 사고 유형이 그대로 남는다. 리뷰어가 검증하는 트리가 브랜치 트리가 아니다.
### C. (제안) creator 만 워크트리, 리뷰어 풀은 공유, 제어 평면은 하나
- **creator = 워크트리 전용 인스턴스.** 편집·커밋하는 유일한 에이전트이므로 cwd 가 곧 이슈 브랜치여야 한다. 이슈마다 `creator-<agent>-<issue>` 로 만들고 끝나면 정지(대화 보존, 필요 시 재개).
- **리뷰어 풀 = 본 체크아웃 공유.** 읽기 전용. 브리프가 워크트리 경로·base·head 를 명시하고 리뷰어는 그 경로에서 `git diff <base>...<head>` 와 테스트를 실행한다. 리뷰가 병목이면 리뷰어 인스턴스를 추가한다.
- **오케스트레이터 커밋 = 워크트리.** 본 체크아웃은 리뷰어의 작업 공간이므로 오케스트레이터는 그곳에서 브랜치를 바꾸지 않는다.
- **제어 평면 = 본 체크아웃의 `.mam` 하나.** 워크트리에서 creator 를 만들 때 `WORKSPACE_ROOT`·`AGENT_SESSIONS_YAML`·`MAM_JOBS_DIR`·`DELEGATE_JOB_LOGS_DIR` 를 본 체크아웃으로 넘기면 같은 yaml 에 등록되고(행의 `pane.cwd` 는 워크트리), 잡 레지스트리·토픽 지문·모니터가 한 곳에 모인다.
## 3. C 안의 동작 방식 (현재 코드 기준)
```bash
MAIN=/path/to/multi-agent-mux # 본 체크아웃: 리뷰어 풀 + .mam
WT=/path/to/multi-agent-mux-wt/issue-20 # 이슈 워크트리
git -C "$MAIN" worktree add -b fix/issue-20 "$WT" main
ln -s "$MAIN/.venv" "$WT/.venv"; git -C "$WT" submodule update --init # 워크트리 준비(.venv, nats-docker)
# creator 를 워크트리 cwd 로, 그러나 본 체크아웃의 .mam 에 등록
WORKSPACE_ROOT="$MAIN" AGENT_SESSIONS_YAML="$MAIN/.mam/agent-sessions.yaml" \
MAM_JOBS_DIR="$MAIN/.mam/jobs" DELEGATE_JOB_LOGS_DIR="$MAIN/.mam/delegate_job_logs" \
bash "$MAIN/.agents/skills/multi-agent-mux-create/scripts/create_session.sh" \
--workspace "$WT" --agent claude --role Creator --session creator-claude-issue20 \
--herdr-session multi-agent-mux --herdr-workspace mam-agent
# 루프는 본 체크아웃에서, creator 이름만 워크트리용으로
cd "$MAIN" && bash .agents/skills/multi-agent-mux-loop/scripts/run_loop.sh \
--creator creator-claude-issue20 --all-reviewer \
--task "[이슈 #20 @ $WT, branch fix/issue-20, base <sha>] ... 리뷰어는 $WT 에서 git diff <base>...HEAD 와 pytest 를 실행하라 ..."
```
- 브리프 규약: 첫 줄에 `워크트리 경로 / 브랜치 / base sha` 를 적고, 리뷰어에게 "그 경로에서 검증"을 명시한다. 잡 브리프 파일(`.mam/jobs/<id>/brief.md`)은 본 체크아웃에 있으므로 creator 는 `$MAIN/.mam/jobs/<id>/brief.md` 를 읽는다(주입 문구의 상대경로 `.mam/jobs/...` 는 creator cwd 기준으로는 존재하지 않는다 → **주입 문구를 절대경로로 바꾸는 작은 변경이 필요**).
- 루프 러너의 `base_commit`/diff 수집(`runner.py:399-401`)은 `workspace_root`(본 체크아웃) 기준이다. C 안에서는 워크트리 경로를 기준으로 diff 를 모아야 하므로 **`--worktree <path>` 옵션(또는 `MAM_LOOP_WORKTREE` env)이 필요**하다.
- 오케스트레이터 커밋 규칙: 커밋 전 `git branch --show-current` 확인(메모리 규칙), 본 체크아웃에서는 `main` 유지.
## 4. 기대 효과와 한계
- 병렬화 이득은 **구현 단계**에서 크다: 워크트리마다 creator 가 동시에 작업하고, 전체 스위트도 워크트리마다 동시에 돈다.
- **리뷰 단계는 풀 크기만큼만 병렬**이다. 이슈 3개를 동시에 돌려도 리뷰어 하나는 잡을 순서대로 처리한다(래퍼는 busy 세션에 rc 5 → 러너가 `MAM_SESSION_BUSY_RETRY_S` 뒤 1회 재시도 → 그래도 busy 면 실패). 다중 루프 동시 기동에는 **리뷰어 큐잉 또는 리뷰어 인스턴스 증설**이 전제다.
- 루프 SKILL.md 의 "동시 루프 기동 금지(NFS lock shadowing)" 는 **같은 `.mam` 을 쓰는 루프**에 대한 경고다. C 안은 `.mam` 을 공유하므로, 다중 루프 동시 기동 전에 이 제약(체크포인트 파일·SQLite 갱신 경합)을 해소해야 한다.
- 워크트리 준비 비용(.venv 링크, 서브모듈, `.mam.env` 복사)은 스크립트 한 줄로 흡수 가능하다.
## 5. 필요한 변경 (작업 항목)
1. 주입 문구·브리프의 잡 경로를 절대경로로(`$REGISTRY_DIR/<id>/brief.md`).
2. 루프 러너에 `--worktree <path>` (diff 수집·`base_commit`·리뷰 브리프의 경로 자동 삽입).
3. `create_session.sh` 문서에 "제어 평면 override" 레시피 추가(`WORKSPACE_ROOT`/`AGENT_SESSIONS_YAML`/`MAM_JOBS_DIR`/`DELEGATE_JOB_LOGS_DIR`), 워크트리 준비 헬퍼(`scripts/worktree_prepare.sh`).
4. 다중 루프 동시 기동 시 `.mam` 경합 해소(체크포인트 파일 이름에 루프 id 포함, 리뷰어 busy 시 대기 큐).
5. 리뷰어 브리프 템플릿에 워크트리 경로·base·head 필드 고정.
## 6. 리뷰어에게 묻는 것
1. C 안의 역할 분리(쓰는 쪽만 격리, 읽는 쪽 공유)가 두 문제(병렬성, 체크아웃 전환 사고)를 실제로 해소하는가? 놓친 경로가 있는가(예: 리뷰어가 테스트 중 파일을 만드는 경우, 모니터 reconcile 이 워크트리 cwd 행을 어떻게 다루는지).
2. 제어 평면 공유(env override)가 현재 코드에서 안전한가? 특히 `pane.cwd` 가 워크트리인 행을 status/monitor/stop/resume 스킬이 올바르게 처리하는가.
3. A/B 안 대비 C 안의 비용·이득 평가에 동의하는가? 다른 대안이 있는가?
4. §5 작업 항목의 누락·과잉. 특히 다중 루프 동시 기동의 `.mam` 경합을 먼저 풀어야 하는지, 아니면 "루프는 하나씩, 구현만 병렬" 로 시작해도 되는지.
5. #17 항목 4(셸 계층 축소)와의 순서: 이 모델을 먼저 문서·레시피로 굳히고 항목 4 에서 코드로 흡수하는 순서가 맞는가.