# ๐ Issue #5 Implementation Plan (Phase 1โ4 Execution & Rollback Specification)
- **Document Version**: Rev.4 (Post Revision Review Corrections)
- **Issue**: [Gitea Issue #5](https://git.godopu.com/tmpl/multi-agent-mux/issues/5)
- **Status**: Target Architecture Roadmap & Execution Gate Criteria
---
## 1. ๊ฐ์ ๋ฐ ๋ง์ด๊ทธ๋ ์ด์
์์น
๋ณธ ๋ฌธ์๋ Issue #5(Python ๋ชจ๋ํ ๋ฐ `lib_py` ์น๊ฒฉ)์ ๋จ๊ณ์ ๊ตฌํ(Phase 1โ4) ์์, ํ์ ์๋ฃ ๊ธฐ์ค(Gate), ๋กค๋ฐฑ ์ ์ฐจ, ๊ทธ๋ฆฌ๊ณ ๋ช
์์ ๋น๋ฒ์(Out of Scope)๋ฅผ ๊ท์ ํฉ๋๋ค.
### ๐ ํต์ฌ ์์น:
1. **์ ์ง์ ๊ฒฉ๋ฆฌ ๋ฐ ๋ฌด์ค๋จ ์ ํ**: ํ๋ก๋์
์
ธ ์ค์ผ์คํธ๋ ์ด์
(`run_loop.sh`)์ Phase 3 ์ด์ ๊น์ง ๊ณ์ํด์ ํ์ฑ ์ํ๋ฅผ ์ ์งํ๋ฉฐ, ํ์ด์ฌ ๋ชจ๋์ ๋
๋ฆฝ๋ ํจํค์ง(`lib_py`)๋ก ๋จ๊ณ์ ์ผ๋ก ์น๊ฒฉ๋ฉ๋๋ค.
2. **๋์ผ ์์
๊ณต๊ฐ ๋ค์ค Writer ์ ๋ ๊ธ์ง**: ๊ณผ๋๊ธฐ์ ๋จ๊ณ์์๋ ํน์ ์ํฌ์คํ์ด์ค์๋ ์ค์ง ๋จ ํ๋์ ์ํ ์ ์ด์(์ ๊ท ์์ง ๋๋ ๊ตฌํ ์
ธ ๋ฃจํ)๋ง ์คํ๋์ด์ผ ํฉ๋๋ค.
3. **Fail-Closed ๋ฐ Rollback ๋ณด์ฅ**: ๊ฐ ๋จ๊ณ๋ ์ด์ ๋ฒ์ ์ผ๋ก ์ฆ์ ๋๋๋ฆด ์ ์๋ ๋ช
ํํ ๋กค๋ฐฑ ์์ ๊ถ๊ณผ ์ฒดํฌํฌ์ธํธ ์ธ๊ณ ์ ์ฐจ๋ฅผ ๊ฐ์ถ์ด์ผ ํฉ๋๋ค.
---
## 2. ๋จ๊ณ๋ณ ๊ตฌํ ๋จ์ ๋ฐ ํ์ ์๋ฃ ๊ธฐ์ค (Roadmap & Gates)
| ๋จ๊ณ | ์์
๋ชฉํ | ์ธ๋ถ ๊ตฌํ ๋ด์ฉ | ํ์ ์๋ฃ ๊ฒ์ดํธ (Gate Criteria) | ๋กค๋ฐฑ ์ ์ฐจ (Rollback Path) |
|---|---|---|---|---|
| **Phase 0**
*(ํ์ฌ)* | **์ฌ์ ๊ณ์ฝ ๊ณ ์ ๋ฐ Fixture ์์ง** | โข CLI, ์ด๋ฒคํธ, ๋ฆฌํฌํธ, ๋ฝ ๊ณ์ฝ ๊ธฐ์ค์ ๋ฌธ์ํ
โข Herdr 0.8.2 ๋ค์ดํฐ๋ธ ์บก์ฒ ๋ฐ ๋ณตํฉ Watcher ์๋๋ฆฌ์ค 2๊ณ์ธต ๋ถ๋ฆฌ
โข 6๊ฐ ๋ฐฑ์๋ ์ค์ธก ์ฆ๊ฑฐ ํ๋ ฌ ์์ง | โข 510๊ฐ ์ ์ฒด ํ
์คํธ ์์ง ๋ฐ ํ๊ท 0-Fail (100% ํต๊ณผ)
โข Fixture ์คํค๋ง ๋ฐ ์ฆ๊ฑฐ ๊ฒฝ๊ณ ๊ฒ์ฆ ํต๊ณผ
โข ํ๋ก๋์
์ฝ๋ ๋ฌด๋ณ๊ฒฝ diff ๊ฒ์ฆ | ๋ฏธ์ถ์ ์ฐ์ถ๋ฌผ ์ฆ์ ์ญ์ (`rm -rf docs/contracts/issue-5 tests/fixtures/issue_5 tests/test_issue5_phase0_contracts.py`) |
| **Phase 1**
*(์๋ฃ v4.3.0)* | **`lib_py/delegation/` ์ถ์ถ** | โข `lib.sh` L1833 ์ดํ ์์ ํฌํผ๋ฅผ ํ์ด์ฌ ์๋น์ค ํด๋์ค๋ก ์ถ์ถ
โข `start_watchdog`์ ๋ด๋ถ ๋ช
์นญ `ensure_subscriber_daemon`์ผ๋ก ๋ช
๋ช
(๊ธฐ์กด ํจ์ ๋ณ์นญ ๋ณด์กด)
โข ์ฅ์ ํ๋ก์ธ์ค ๋จ์ผ MQTT ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ ํ๋กํ ํ์
| โข CLI/non-fatal/HMAC/seq/๋์คํฌ ํด๋ฐฑ ํ๊ท 100% ํต๊ณผ
โข ๋ฐ๋ชฌ ์๋ช
๋ฐ PID ๊ณ์ฝ ์ผ์น ํ์ธ
โข **์๋์๋ฃ ์ ์ฑ
๋ณ๊ฒฝ ์์** | `MAM_DELEGATION_PY=0`์ผ๋ก ๋ณด์กด๋ ๋ ๊ฑฐ์ ์ธ๋ผ์ธ ๋ณธ์ฒด(`_*_legacy`)๋ก ์ฆ์ ๋ถ๊ธฐ (์ฌ๋ฐฐํฌยทrevert ๋ถํ์; ๋ ๊ฑฐ์ ๋ณธ์ฒด ์ ๊ฑฐ๋ Phase 4) |
| **Phase 2a**
*(์๋ฃ, shadow-only)* | **`lib_py/loop/` ์ฝ์ด & Shadow Watcher** | โข `engine.py` (๋จ์ผ ์ ์ด ์ฃผ์ฒด), `watcher.py` (`herdr agent wait` ๋ํ) ๊ตฌํ
โข ๋ชจ๋ Writer์ ๋ํ ๋จ์ผ CAS ํธ๋์ญ์
๊ฒฝ๊ณ ๊ตฌํ
โข ์๋์๋ฃ๋ฅผ ์ํํ์ง ์๊ณ "Would-Complete" ๋ก๊น
๋ง ์ํํ๋ Shadow ๋ชจ๋ ๊ฐ๋ | โข ๋ฝ ๋ด ๋น๋๊ธฐ/I/O ๋ฐฐ์ ๊ฒ์ฆ
โข ์์ผ ๋จ์ /์ค๋
์ท ์ฌ์ฐ๊ฒฐ ๋ฐฑ์คํ ๊ฒ์ฆ
โข Shadow ๋ชจ๋๊ฐ ๋ ์ง์คํธ๋ฆฌ ์ํ๋ฅผ ์ฐ์ง ์์์ ๊ฒ์ฆ | 1) Shadow ๋ชจ๋ํฐ ํ๋ก์ธ์ค ์ข
๋ฃ ๋ฐ ์ธ๋ฉ๋ชจ๋ฆฌ ํ ํ๊ธฐ
2) CAS ์๋น์ค๋ ํ์ ํธํ ๋ชจ๋๋ก ์ ์งํ๊ฑฐ๋ `MAM_ENGINE_CAS=0` ํ๋๊ทธ๋ก ๋นํ์ฑํํ์ฌ ๋ ๊ฑฐ์ ๋ฌด์กฐ๊ฑด ํ๋ ๋ณํฉ(`update_job_status`)์ผ๋ก ๋ณต๊ท
3) ๊ธฐ์กด ์
ธ ๋ฃจํ ์ํ ๋ฐ ๋ ์ฝ๋ ๋ถ๋ณ ์ ์ง |
| **Phase 2b** | **์ด์ค ๊ฐ์ง ์๋์๋ฃ ํ์ฑํ (Flag-Gated)** | โข 4์ค ์คํ ๊ท์ + ๋ฆฌํฌํธ ํ์ ๊ณ์ฝ + ๋จ์ผ CAS ์ ์ด ๊ฒ์ดํธ ์ฐ๋
โข Pending Notification ์ง์ฐ ์๋ฆผ ๋ฐ ํฌ๋์ ๋ณต๊ตฌ ๊ตฌํ
โข ๊ฒ์ฆ๋ ๋ฐฑ์๋/์์
์ ํํด opt-in ํ๋๊ทธ๋ก ํ์ฑํ (๊ธฐ๋ณธ๊ฐ OFF) | โข ๋ถ์ํจ๊ณผ ์์
์์ธ ๋ฐ ๋ฌดํ์ fail-closed ํ
์คํธ ์๋ฃ
โข ๊ฒฝ์/์ฌ์์ ์๋๋ฆฌ์ค ํต๊ณผ
โข ํ๋๊ทธ OFF ์ ๊ธฐ์กด explicit event ๊ฒฝ๋ก 100% ๋ณด์กด | ํ๊ฒฝ๋ณ์/ํ๋๊ทธ `MAM_AUTO_COMPLETE=0` ์ค์ ; ์ด๋ฏธ ํ์ ๋ terminal ๋ ์ฝ๋๋ ๋ณด์กดํ๊ณ ์ ๊ท ์๋์๋ฃ๋ง ์ค๋จ |
| **Phase 3** | **`run_loop.sh` Thin Wrapper ์ ํ ๋ฐ ์ ๋ฉด ํ๊ท** | โข `run_loop.sh`๋ฅผ ์ธ์ ์ ๋ฌ ๋ํผ(`exec python3 -m lib_py.loop "$@"`)๋ก ์ ํ
โข ํ๋๋/๋ฆฌ๋ทฐ์ด/๋ฐ๋ก /์น๊ฒฉ ์ค์ผ์คํธ๋ ์ด์
๋ก์ง ์์ ์ด์
โข ์๊ฒฉํ ํ์ ํ์(Strict Parser) ์ ์ฉ | โข 5๊ฐ subprocess ์ ์ฉ ํ
์คํธ(~1,621์ค) ํฌํจ ์ ์ฒด 481๊ฐ+ ํ
์คํธ 0-Fail
โข ์๊ทธ๋, ๋ฃจํ ๊ฐ๋, ์์ CWD ๋ฐ ๊ณต๋ฐฑ ๊ฒฝ๋ก ๊ฒ์ฆ ํต๊ณผ | **์ฐ์ํ ํธ๋์คํ ์ํ์ค**:
1) Quiesce: ์คํ ์ค์ธ Python ๋ฃจํ ํ๋ก์ธ์ค์ ์ข
๋ฃ ์ ํธ๋ฅผ ์ ๋ฌํ์ฌ ์ ๊ท ๋์คํจ์น ์ค๋จ
2) Checkpoint: ํ์ฌ ๋ฃจํ ํ์ฐจ, ํ์ฑ Job ID ๋ฐ ๋ฆฌ๋ทฐ ์ํ๋ฅผ `.mam/loop-checkpoint.json`์ ์์์ ๊ธฐ๋ก
3) Exit: Python ๋ฃจํ ์ ์ ์ข
๋ฃ ๋ฐ ๊ฐ๋ ํด์
4) Resume: ๋ฐฑ์
๋ ์
ธ ์๋ณธ ์คํฌ๋ฆฝํธ๋ก `run_loop.sh` ๋ณต์ ํ ์ฒดํฌํฌ์ธํธ ๊ธฐ๋ฐ ์ฌ๊ฐ ๊ฒ์ฆ |
| **Phase 4** | **๋ถ๋ณ ๋ฐํ์ ๊ฒ์ฆ ๋ฐ Freeze ์ ๊ฑฐ** | โข ๊ธฐ๋ ์ ์ ์ฒด ๋ชจ๋ ์์ฃผ(Eager Import) ๋ฐ ์์ ํ
ํ๋ฆฟ ๋ถ๋ณ์ฑ ๊ฒ์ฆ
โข ์์
๋์ค ์คํฌ ํ์ผ ๊ต์ฒด ๋ฐ ๋ฆ์ ๊ฒฝ๋ก ์คํธ๋ ์ค ํ
์คํธ ํต๊ณผ
โข `/tmp/mam-loop-freeze.XXXXXX` ์ฐํ์ฑ
์์ ์ ๊ฑฐ | โข ๋ฐํ์ ์๊ธฐ์์ ํฌ๋์(B-13) ์ฌ๋ฐ ๋ฐฉ์ง ๊ฒ์ฆ
โข Live Helper ๋ฒ์ ํธํ ๊ฒ์ดํธ ๊ฒ์ฆ ํต๊ณผ
โข ์ด์ ๋ฌธ์ ๋ฐ ๋ฐฐํฌ ์คํฌ๋ฆฝํธ ๊ฐฑ์ | Freeze ๋ณต์ฌ ๋ก์ง(`run_loop.sh:112-127`) ์ฌํ์ฑํ ๋ฐ ๋ผ์ด๋ธ ํฌํผ ๋ฒ์ ๊ฒ์ฌ ๋ณต๊ตฌ |
---
## 3. ๋ผ์ด๋ธ ํฌํผ ๋ฒ์ ํธํ์ฑ ๋ฐ ์์
์ํ ์ ์ด ๊ณ์ฝ (Live Helper Compatibility Gate)
ํตํฉ ๋ณด๊ณ ์(Rev.2) ๋ฐ B-13 ํฉ์์ ๋ฐ๋ผ, `multi-agent-mux-create`, `resume`, `stop` ๋ฑ 1ํ์ฑ ์คํฌ๋ฆฝํธ๋ Freeze ๋ณต์ฌ๋ณธ์ด ์๋ Live Tree์์ ์คํ๋ฉ๋๋ค. Phase 4์์ Freeze๊ฐ ์ ๊ฑฐ๋๊ธฐ ์ ๊น์ง, ๋ผ์ด๋ธ ํฌํผ์ ๊ณ ์ ์คํ ์์ง ๊ฐ์ ์ถฉ๋์ ๋ฐฉ์งํ๊ณ ๊ธฐ์กด ์์
์ํ ์ ์ด ํจ๊ณผ๋ฅผ ๋ณด์กดํ๊ธฐ ์ํด ๋ค์ ๊ท์น์ ์ ์ฉํฉ๋๋ค:
1. **ABI ๋ฒ์ ๋ฐ ํ๋กํ ์ฝ ํด์ ๊ฒ์ฆ**:
- Live Tree์ ์คํฌ๋ฆฝํธ๊ฐ ์คํ๋ ๋, ํ์ฌ ์คํ ์ค์ธ ๋ฃจํ์ `MAM_VERSION` ๋๋ ๊ณตํต ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธํฐํ์ด์ค ํด์๋ฅผ ๋น๊ตํฉ๋๋ค.
- ๋ฉ์ด์ ๋ฒ์ ๋ถ์ผ์น ๋๋ ๋ ์ง์คํธ๋ฆฌ ์คํค๋ง ๋ณ๊ฒฝ์ด ๊ฐ์ง๋๋ฉด, ๋ผ์ด๋ธ ํฌํผ๋ ์ฆ์ ์ค๋ฅ๋ฅผ ๋ฐํํ๊ณ ์์ ํ๊ฒ ์ค๋จ(fail-closed)ํฉ๋๋ค.
2. **์์
์ทจ์(`cancelled`) ์ ์ด์ ์ ๊ท ์๋น์ค ๊ฒฝ์ ๋ณด์กด**:
- `multi-agent-mux-stop/scripts/stop_session.sh`๋ ์ธ์
๊ฐ์ ์ข
๋ฃ ์ ์์ฌ ํ์ฑ ์์
์ ๋ํด `cancelled` ์ด๋ฒคํธ๋ฅผ ๋ฐํํฉ๋๋ค (`stop_session.sh:242, 322`).
- ๋ผ์ด๋ธ ํฌํผ๋ ๋ ์ง์คํธ๋ฆฌ JSON ํ์ผ์ ์์๋ก ๋ณ์กฐํ์ง ์๊ณ , `delegate_publish_event` ๋ฐ ๊ณตํต ์ํ ์ ์ด ์๋น์ค(Transition Service)๋ฅผ ํธ์ถํ์ฌ CAS ๋ถ๋ณ์์ ์ค์ํ๋ฉด์ ์์
์ ์ ๊ท `cancelled` ์ํ๋ก ์ ์ด์ํต๋๋ค.
- ์ด๋ฅผ ํตํด ์ธ์
์ค๋จ ์ ์์
์ด ์๊ตฌ ๊ณ ์ฐฉ(hang)๋์ง ์๊ณ ์ค์ผ์คํธ๋ ์ดํฐ ๋ฃจํ๊ฐ ์ฆ๊ฐ ์ทจ์๋ฅผ ์ธ์งํ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
---
## 4. ๋ช
์์ ๋น๋ฒ์(Out of Scope) ๋ฐ ํธํ์ฑ ๊ณ์ฝ
1. **์ ์ฅ์ ํตํฉ ๊ธ์ง**:
- ์ธ์
๊ด๋ฆฌ์ฉ SQLite/YAML ์ ์ฅ์(`.mam/agent-sessions.yaml`, `.db`)์ ๋น๋๊ธฐ ์์
๊ด๋ฆฌ์ฉ JSON ๋ ์ง์คํธ๋ฆฌ(`.mam/jobs/`)๋ฅผ ํ๋๋ก ํตํฉํ๋ ค ์๋ํ์ง ์์ต๋๋ค.
2. **์์ท ์คํฌ์ Live Tree ์คํ ์ ์ง**:
- `multi-agent-mux-create`, `resume`, `stop` ๋ฑ 1ํ์ฑ ์
ธ ์คํฌ๋ฆฝํธ๋ Freeze ๋ณต์ฌ๋ณธ์ด ์๋ ์ค์ ์์
ํธ๋ฆฌ์ ์ฝ๋๋ฅผ ์คํํ๋๋ก ์ ์งํฉ๋๋ค.
3. **ํ์์์ 3์ ๋ถ๋ฆฌ ๋ณด์กด**:
- (a) ์ ์ฒด ๋ฒฝ์๊ณ ํ์์์, (b) MQTT ๊ฐ์
์ idle-timeout, (c) TUI idle ์๋์๋ฃ๋ฅผ ๋
๋ฆฝ์ ์ผ๋ก ์ ์งํ๋ฉฐ, ์๋์๋ฃ๊ฐ ๊ธฐ์กด ํ์์์ ๋ฉ์ปค๋์ฆ์ ๋ฎ์ด์ฐ์ง ์์ต๋๋ค.
---
## 5. ์ฑ๋ฅ ์์ฉ ๊ธฐ์ค (Performance Acceptance Criteria)
๊ณ ์ ๋ฐ 10ms ํด๋ง ๋์ ์ค์ ์์คํ
์์ ์ธก์ ์ ๊ธฐ์ค์ผ๋ก ์ฑ๋ฅ์ ํ๊ฐํฉ๋๋ค:
- **ํ๋ก์ธ์ค ํฌํฌ ์ (Fork Count)**: ๋ฃจํ ๋ฐ๋ณต๋น ์๋ธํ๋ก์ธ์ค ์์ฑ ํ์ ๋ํญ ๊ฐ์ (์
ธ ๋ฃจํ ๋๋น โฅ70% ๊ฐ์ถ).
- **์ ํด CPU ์ ์ ์จ (Idle CPU)**: ๋๊ธฐ ์ค CPU ์ฌ์ฉ๋ฅ 1% ๋ฏธ๋ง ์ ์ง (์ด๋ฒคํธ ๊ตฌ๋ ๋ฐ ์ ๊ณ ํด๋ง).
- **MQTT ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ**: ๋จ์ผ ์ฅ์ ํ๋ก์ธ์ค ๋ด์์ ๋ค์์ ์์
๋ฐํ ์ ์ฐ๊ฒฐ ์ฌ์๋ฆฝ ์ค๋ฒํค๋ ์ ๊ฑฐ (p50 ๋ ์ดํด์ ๋จ์ถ).