# spec-p1-2-rw-isolation.md
# P1-2 읽기/쓰기 격리 — 상세 구현 스펙

**작성자:** 아테나 (UX/UI 디자이너, MoAI-ADK)
**작성일:** 2026-03-31
**상태:** DRAFT
**관련 Task:** MoAI-ADK Phase 1

---

## 1. 목적

Read 에이전트는 worktree를 생성하지 않고, Write 에이전트만 worktree를 생성한다. 이를 통해 불필요한 git worktree 오염을 방지하고, 멀티봇 환경에서 파일시스템 충돌 가능성을 최소화한다.

**핵심 목표:**
- Read 에이전트의 불필요한 worktree 생성 제거
- Write 에이전트만 격리된 worktree에서 작업
- Feature Flag로 무중단 점진 배포 가능
- DIRECT-WORKFLOW.md에 운영 절차 문서화

---

## 2. 상세 스펙

### 2.1 dispatch.py 변경

`--agent-type` 인자를 추가한다.

| 인자 | 타입 | 기본값 | 허용값 | 설명 |
|---|---|---|---|---|
| `--agent-type` | `str` | `"write"` | `"read"`, `"write"` | 에이전트 종류 지정 |

```bash
# Read 에이전트로 dispatch
python dispatch.py --agent-type read --task "코드 분석"

# Write 에이전트로 dispatch (기본값)
python dispatch.py --agent-type write --task "버그 수정"
python dispatch.py --task "버그 수정"   # --agent-type 생략 시 write
```

**파싱 코드:**
```python
# dispatch.py

import argparse

parser = argparse.ArgumentParser()
parser.add_argument(
    "--agent-type",
    choices=["read", "write"],
    default="write",
    help="에이전트 타입 (read: worktree 미생성, write: worktree 생성)",
)
args = parser.parse_args()
```

### 2.2 worktree_manager.py 변경

`create_worktree()` 함수에 `read_only` 파라미터를 추가한다.

| 파라미터명 | 타입 | 기본값 | 설명 |
|---|---|---|---|
| `read_only` | `bool` | `False` | True이면 worktree 미생성, 기존 worktree 경로 반환 |

```python
# worktree_manager.py

def create_worktree(
    repo_path: str,
    branch: str,
    read_only: bool = False,   # NEW
) -> str:
    """
    Args:
        repo_path: git 저장소 루트 경로
        branch: 체크아웃할 브랜치명
        read_only: True이면 worktree 생성 생략, repo_path 반환
    Returns:
        worktree 경로 (read_only=True이면 repo_path 그대로)
    """
    if read_only:
        logger.info("read_only=True: worktree 생성 생략, repo_path 반환")
        return repo_path

    # 기존 worktree 생성 로직
    worktree_path = _generate_worktree_path(repo_path, branch)
    subprocess.run(
        ["git", "worktree", "add", worktree_path, branch],
        check=True,
        cwd=repo_path,
    )
    return worktree_path
```

### 2.3 dispatch.py → worktree_manager 연동

```python
# dispatch.py

from worktree_manager import create_worktree
from utils.feature_flags import FeatureFlagLoader

flags = FeatureFlagLoader()

agent_type = args.agent_type  # "read" | "write"

if flags.get("rw_isolation_enabled"):
    read_only = (agent_type == "read")
else:
    read_only = False   # 플래그 비활성화 시 항상 write 동작

worktree_path = create_worktree(
    repo_path=REPO_PATH,
    branch=target_branch,
    read_only=read_only,
)
```

### 2.4 Feature Flag

| 플래그명 | 기본값 |
|---|---|
| `rw_isolation_enabled` | `false` |

**플래그 활성화(`true`):** `--agent-type read` 시 worktree 미생성, `write` 시 worktree 생성.

**플래그 비활성화(`false`):** `--agent-type` 값과 무관하게 항상 write 동작(worktree 생성). 기존 동작과 동일.

---

## 3. 인터페이스

### 3.1 변경 파일 목록

| 파일 | 변경 내용 |
|---|---|
| `dispatch.py` | `--agent-type` 인자 추가, feature flag 분기 |
| `worktree_manager.py` | `create_worktree(read_only=False)` 파라미터 추가 |
| `DIRECT-WORKFLOW.md` | 섹션 5 추가 (하단 참조) |

### 3.2 DIRECT-WORKFLOW.md 섹션 5

```markdown
## 5. Read/Write 에이전트 격리 운영

### 5.1 개요
- Read 에이전트: 코드 분석, 리뷰, 검색 등 파일을 수정하지 않는 작업
- Write 에이전트: 코드 수정, 파일 생성, 버그 수정 등 파일을 변경하는 작업

### 5.2 dispatch 명령

| 작업 유형 | 명령 예시 |
|---|---|
| 읽기 전용 분석 | `python dispatch.py --agent-type read --task "의존성 분석"` |
| 코드 수정 | `python dispatch.py --agent-type write --task "버그 수정"` |
| 기본 (생략) | `python dispatch.py --task "코드 수정"` (write와 동일) |

### 5.3 worktree 상태 확인

```bash
git worktree list        # 현재 worktree 목록
git worktree prune       # 사용 완료된 worktree 정리
```

### 5.4 주의사항
- Read 에이전트가 실수로 파일을 수정할 경우 repo_path의 메인 브랜치에 직접 영향
- Read 에이전트에서 파일 수정이 필요해지면 Write 에이전트로 재dispatch
- `rw_isolation_enabled` 플래그 비활성화 시 모든 에이전트가 write 동작
```

### 3.3 에러 처리

| 상황 | 처리 |
|---|---|
| 잘못된 `--agent-type` 값 | argparse가 즉시 종료 + usage 출력 |
| worktree 생성 실패 | `subprocess.CalledProcessError` → 상위로 propagate |
| read_only=True인데 repo_path가 없음 | `FileNotFoundError` raise |

---

## 4. 테스트 기준

### 4.1 단위 테스트

```python
# tests/test_rw_isolation.py

def test_read_agent_no_worktree_created(tmp_path, monkeypatch):
    """read_only=True이면 git worktree add 미호출"""
    mock_run = MagicMock()
    monkeypatch.setattr(subprocess, "run", mock_run)
    result = create_worktree(str(tmp_path), "main", read_only=True)
    mock_run.assert_not_called()
    assert result == str(tmp_path)

def test_write_agent_creates_worktree(tmp_path, monkeypatch):
    """read_only=False이면 git worktree add 호출"""
    mock_run = MagicMock()
    monkeypatch.setattr(subprocess, "run", mock_run)
    create_worktree(str(tmp_path), "feature/test", read_only=False)
    mock_run.assert_called_once()
    assert "worktree" in mock_run.call_args[0][0]

def test_flag_disabled_always_write(monkeypatch):
    """플래그 비활성화 시 read agent도 worktree 생성"""
    monkeypatch.setattr(flags, "get", lambda k: False)
    # --agent-type read이지만 read_only=False로 동작해야 함
    read_only = compute_read_only(agent_type="read", flags=flags)
    assert read_only is False

def test_agent_type_default_is_write():
    """--agent-type 미지정 시 기본값 write"""
    args = parser.parse_args([])
    assert args.agent_type == "write"
```

### 4.2 통합 테스트

- `python dispatch.py --agent-type read --task "분석"` 실행 후 `git worktree list` 변화 없음 확인
- `python dispatch.py --agent-type write --task "수정"` 실행 후 worktree 신규 생성 확인
- 플래그 비활성화 상태에서 두 케이스 모두 worktree 생성됨 확인

---

## 5. DoD (Definition of Done)

- [ ] `dispatch.py`에 `--agent-type read|write` 인자 추가 (기본값: write)
- [ ] `worktree_manager.py`에 `read_only` 파라미터 추가
- [ ] read_only=True 시 worktree 미생성, repo_path 반환 동작 확인
- [ ] `rw_isolation_enabled` 플래그 비활성화 시 항상 write 동작 확인
- [ ] `DIRECT-WORKFLOW.md` 섹션 5 추가 완료
- [ ] 단위 테스트 4건 이상 통과 (pytest)
- [ ] 기존 write 워크플로우 회귀 없음
- [ ] pyright 타입 오류 0건
- [ ] ruff 스타일 경고 0건
- [ ] PR 리뷰 승인 후 merge
