# ๐Ÿ› ๏ธ Multi-Agent Mux ์ข…ํ•ฉ ๊ฐœ์„  ๋ฐ ๋ฏธํ•ด๊ฒฐ ๊ณผ์ œ ๋ฐฑ๋กœ๊ทธ (`IMPROVEMENTS.md`) - **์ตœ์ข… ๊ฐฑ์‹ ์ผ**: 2026-08-11 (P0-2/O-2 ๋™์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‚ด ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ๋ฐฉ์ง€ ์›์ž์  ๋ฝ ๋ฐ ๋งˆ์ปค ์†Œ์œ ๊ถŒ ๋Œ€์กฐ ์‚ญ์ œ ์กฐ์น˜ ์™„๋ฃŒ ๋ฐ˜์˜) - **ํ†ตํ•ฉ ๊ด€๋ฆฌ ๋Œ€์ƒ**: ๊ธฐ์กด `CODEBASE_REVIEW_REPORT.md` + `OPTIMIZATION.md` - **์ด ์ถ”์  ๋ฏธํ•ด๊ฒฐ ๊ณผ์ œ**: **10๊ฑด** (์•„ํ‚คํ…์ฒ˜ 2๊ฑด, ์—ฃ์ง€์ผ€์ด์Šค 5๊ฑด, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ 0๊ฑด, ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ 3๊ฑด) - **์™„๋ฃŒ๋œ ๊ณผ์ œ**: **12๊ฑด** (A-1, A-3, A-5, B-1, B-3, B-4, B-7, C-1, C-2, O-1, O-2, O-3) --- ## ๐Ÿ“Œ ๊ฐœ์š” ๋ณธ ๋ฌธ์„œ๋Š” Multi-Agent Mux (MAM) ํ”„๋ ˆ์ž„์›Œํฌ์˜ **์ฝ”๋“œ๋ฒ ์ด์Šค ์•„ํ‚คํ…์ฒ˜ ๊ฒฐํ•จ, ๋Ÿฐํƒ€์ž„ ์—ฃ์ง€์ผ€์ด์Šค, ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ** ๋ฐ **`/multi-agent-mux-loop` ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์ตœ์ ํ™” ๊ณผ์ œ**๋ฅผ ๋‹จ์ผ ๋ฐฑ๋กœ๊ทธ๋กœ ํ†ตํ•ฉ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•œ ์ข…ํ•ฉ ๊ด€๋ฆฌ ๋ฌธ์„œ์ž…๋‹ˆ๋‹ค. --- ## 1. ๐Ÿ”ด ์•„ํ‚คํ…์ฒ˜ ๊ฒฐํ•จ (Architecture Flaws โ€” 2๊ฑด) ### **A-2: ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค + HMAC ์ธ์ฆ Off + ์™€์ผ๋“œ์นด๋“œ ์ „ํŒŒ** - **ํ˜„์ƒ**: `mqtt_common.py`์˜ ๊ธฐ๋ณธ ๋ธŒ๋กœ์ปค๊ฐ€ ๊ณต๊ฐœ ์„œ๋ฒ„(`broker.hivemq.com`)์ด๊ณ , ์žก ์ƒ์„ฑ ์‹œ `auth_token` ์ด **ํ•œ ๋ฒˆ๋„ ๋ฐœ๊ธ‰๋˜์ง€ ์•Š์•„**(์‹ค์ธก 26/26 ์žก์ด `auth_token=None`) `verify_hmac` ์˜ `if not auth_token: return True` ๊ฒฝ๋กœ๊ฐ€ ํ•ญ์ƒ ํƒ€์ง‘๋‹ˆ๋‹ค. ๋ฐœํ–‰์ž๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ง€๋ฌธ ํ† ํ”ฝ์„ ์ฑ„ํƒํ•˜์ง€ ์•Š๊ณ  ์ „์—ญ `python/mqtt/jobs//events` ๋กœ ๋ฐœํ–‰ํ•˜๋ฉฐ, `reconcile.sh:237` ์ด ๊ฐ™์€ ์ „์—ญ ํ† ํ”ฝ์„ ๊ตฌ๋…ํ•ฉ๋‹ˆ๋‹ค. (HMAC ๊ตฌํ˜„ ์ž์ฒด๋Š” ์ •์ƒ์ž…๋‹ˆ๋‹ค โ€” ํ† ํฐ์ด ์—†์–ด ๊ฒ€์ฆ์ด ๊ณตํ—ˆํ•ด์ง€๋Š” ๊ฒƒ์ด ์›์ธ์ž…๋‹ˆ๋‹ค.) - **ํŒŒ๊ธ‰ ํšจ๊ณผ**: ์™ธ๋ถ€์—์„œ ์œ ์ž…๋˜๋Š” malicious `error` ์ด๋ฒคํŠธ ์ˆ˜์‹  ์‹œ `reconcile.sh`๊ฐ€ ๋ผ์ด๋ธŒ ์—์ด์ „ํŠธ pane์„ `kill-session`์œผ๋กœ ๊ฐ•์ œ ํŒŒ๊ดดํ•˜๋Š” ์น˜๋ช…์  ๋ณด์•ˆ/์•ˆ์ •์„ฑ ์œ„ํ—˜์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ### **A-4 (์„ค๊ณ„ ์ œ์•ˆ): ์—์ด์ „ํŠธ ์ง€์‹ ์‚ฐ์žฌ โ€” `BaseAgentAdapter` ์–ด๋Œ‘ํ„ฐ ๊ณ„์ธต ๋„์ž… (Rev.2)** > ๊ฒฐํ•จ ์กฐ์น˜๊ฐ€ ์•„๋‹ˆ๋ผ **๊ตฌ์กฐ ๊ฐœ์„  ์ œ์•ˆ**์ž…๋‹ˆ๋‹ค. ์ƒ์„ธ ์„ค๊ณ„ยท์‹ค์ธก ๊ทผ๊ฑฐ๋Š” `.mam/jobs/44062a63/claude-reports/report-final.md` ๋ฐ `744ac67a` ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. - **ํ˜„์ƒ**: "claude ์˜ transcript ๋Š” ์–ด๋”” ์žˆ๋‚˜", "cline ์žฌ๊ฐœ argv ๋Š” ๋ฌด์—‡์ธ๊ฐ€" ๊ฐ™์€ **์—์ด์ „ํŠธ์— ๋Œ€ํ•œ ์‚ฌ์‹ค**์ด ์Šคํฌ๋ฆฝํŠธ 8๊ฐœ ยท **34๊ฐœ ํŒฌ์•„์›ƒ ์ง€์ **์— ํฉ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. (8์ค„ ์œˆ๋„ ์•ˆ์— 4๊ฐœ ์—์ด์ „ํŠธ ์ค‘ 3๊ฐœ ์ด์ƒ์ด ๋“ฑ์žฅํ•˜๋Š” ์ง€์  ๊ธฐ์ค€: `create_session.sh` 8, `reconcile.sh` 7, `stop_session.sh` 6, `lib.sh` 4, `resolve_session_id.sh` 3, `resume_session.sh`/`update_yaml_resumed.sh`/`run_loop.sh` ๊ฐ 2) - **์‚ฌ๋ณธ ํ˜„ํ™ฉ**: `agent โ†’ *_id_own` ํ‚ค ๋งต **4๋ฒŒ**, `~/.claude/projects` 17์ฐธ์กฐ, `antigravity-cli/conversations` 11์ฐธ์กฐ, `.hermes/state.db` 6์ฐธ์กฐ, `.cline/data/sessions` 5์ฐธ์กฐ. - **ํŒŒ๊ธ‰ ํšจ๊ณผ**: ๊ฐ™์€ ์งˆ๋ฌธ์— **์„œ๋กœ ๋‹ค๋ฅธ ๋‹ต**์ด ๊ณต์กดํ•ฉ๋‹ˆ๋‹ค. ์„ธ์…˜๋ช…โ†’์—์ด์ „ํŠธ ์ถ”๋ก ์ด `reconcile.sh::row_agent`(pane.cmd โ†’ cmd_full โ†’ ์ด๋ฆ„ ์ ‘๋ฏธ์‚ฌ)์™€ `run_loop.sh:236-243`(์„ธ๊ทธ๋จผํŠธ ๋งค์นญ + ์‹คํŒจ ์‹œ `claude` ๊ธฐ๋ณธ๊ฐ’) ๋‘ ๋ฒŒ๋กœ ์กด์žฌํ•˜๋ฉฐ ํ›„์ž๋Š” ์˜คํŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. b4a1d094 ์—์„œ ๋“œ๋Ÿฌ๋‚œ "๊ฒฉ๋ฆฌ ๋ถ„๊ธฐ inert" ๊ฒฐํ•จ๋„ ์•„ํ‹ฐํŒฉํŠธ ๊ฒฝ๋กœ ๊ทœ์น™์ด ๋‘ ๋ฒŒ์ด์—ˆ๋˜ ๋ฐ์„œ ๋น„๋กฏ๋์Šต๋‹ˆ๋‹ค. #### ์„ค๊ณ„ ์š”์ง€ (Rev.2 ๊ฐฑ์‹ ) - **`.agents/skills/mam_agents/`** ํŒจํ‚ค์ง€(์•ฝ 484์ค„): `base.py`(ABC + `SpawnSpec` + `DiscoveryContext`), `registry.py`(์ •์  ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ), `__main__.py`(์…ธ ๋ธŒ๋ฆฌ์ง€), `adapters/{claude,agy,hermes,cline}.py`. - **์ธํ„ฐํŽ˜์ด์Šค**: `own_key` / `supports_assigned_id` / `ready_tokens` ์†์„ฑ + `auth_ok(run)` ยท `spawn_spec()` ยท `resume_spec(binary, uuid, materialized)` ยท `artifact_path(uuid, ctx)` ยท `verify_artifact(uuid, ctx)` ยท `discover(ctx)`. - **`DiscoveryContext` & `discover()` ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ**: `cwd`(๋ฌผ๋ฆฌ ์ ˆ๋Œ€๊ฒฝ๋กœ), `ws_key`, `home`, `claude_dir`, `iso_root`, `epoch`, `claimed` ํ•„๋“œ๋ฅผ ๊ฐ์ฒด ํ•˜๋‚˜๋กœ ์บก์Аํ™”. `_raw_candidates(ctx)` ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋กœ ์–ด๋Œ‘ํ„ฐ๋ณ„ ๋ฌผ๋ฆฌ ํƒ์ƒ‰๋งŒ ์„œ์ˆ ํ•˜๊ณ  `claimed`/`epoch` ํ•„ํ„ฐ๋Š” ๊ธฐ๋ฐ˜ ํด๋ž˜์Šค ํ…œํ”Œ๋ฆฟ์ด 100% ๋ณด์žฅ. - `auth_ok` ๋Š” ์„œ๋ธŒํ”„๋กœ์„ธ์Šค ์‹คํ–‰์ž๋ฅผ **์ฃผ์ž…**๋ฐ›์•„ CLI ๋ฏธ์„ค์น˜ ํ™˜๊ฒฝ์—์„œ๋„ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค(hermes ๋Š” ํ˜„์žฌ ๋ฏธ์„ค์น˜). - `resume_spec` ์˜ `materialized` ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ b4a1d094 ๊ทœ์น™(`claude -r <๋ฏธ์‹คํ˜„ uuid>` ์‹คํŒจ โ†’ `--session-id`)์„ ํก์ˆ˜ํ•ฉ๋‹ˆ๋‹ค. - `ready_tokens` ์†์„ฑ์„ ์–ด๋Œ‘ํ„ฐ๋กœ ๋‚ด๋ณด๋‚ด `wait_for_tui_ready` ์˜ 25์ค„ inline shell `case` ๋ธ”๋ก์„ ๋‹จ 1์ค„์˜ `grep -E -q "$MAM_READY_TOKENS"` ๋กœ ์ถ•์†Œ. - **๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํŒจํ„ด**: **์ •์  dict ์ฑ„ํƒ.** `entry_points` ๋Š” MAM ์ด `pip install` ๋˜์ง€ ์•Š๊ณ  `rsync`/`cp` ๋กœ ๋ฐฐํฌ๋˜๋ฏ€๋กœ ๋ถ€์ ํ•ฉ, ๋””๋ ‰ํ„ฐ๋ฆฌ ์Šค์บ”์€ "0๊ฐœ ๋ฐœ๊ฒฌ"๊ณผ "์—์ด์ „ํŠธ ๋ฏธ์„ค์น˜"๊ฐ€ ๊ตฌ๋ถ„๋˜์ง€ ์•Š์•„ ๋ถ€์ ํ•ฉ. - **bashโ†”python ๋ธŒ๋ฆฌ์ง€**: `python -m mam_agents facts ` ๊ฐ€ `shlex.quote` ๋œ `KEY=value` ๋ฅผ ์ถœ๋ ฅ. **์Šคํฌ๋ฆฝํŠธ๋‹น 1ํšŒ `eval`** ์ด ๊ณ„์•ฝ์ž…๋‹ˆ๋‹ค(์‹ค์ธก 22.8 ms/ํ˜ธ์ถœ vs bash `case` 2.3 ms โ€” ๋ถ„๊ธฐ๋งˆ๋‹ค ํ˜ธ์ถœํ•˜๋ฉด ์•ˆ ๋จ). #### ์‹คํ˜„ ๊ฐ€๋Šฅ์„ฑ ๋ฐ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ (Rev.2 ์‹ค์ธก) - ํŒŒ์ด์ฌ ์ง„์ž…์  **3์ข… ์ „๋ถ€**์—์„œ import ํ™•์ธ: `env_python`, `atomic_dump_yaml`(flock ์“ฐ๊ธฐ ๊ฒฝ๋กœ), venv ์—†๋Š” **๋งจ `/usr/bin/python3`**. - **`lib.sh` source ์‹œ์  1ํšŒ `export PYTHONPATH`**: `lib.sh` ๋กœ๋“œ ์‹œ `_mam_export_pythonpath` ๊ฐ€ `mam_skills_dir` ์„ `PYTHONPATH` ์— ์ž๋™ ์–น์–ด `run_loop.sh` ๋“ฑ ์…ธ ์ƒ์˜ ๋ชจ๋“  `python3 -c` ํ˜ธ์ถœ์ด ํ•œ ๋ฒˆ์— ํ˜ธํ™˜๋จ. - herdr shim ๋‚ด๋ถ€ `python3 -c` **9๊ณณ ์ „๋ถ€ ์—์ด์ „ํŠธ ์ง€์‹ 0** โ†’ shim ๊ฒฝ๊ณ„๊ฐ€ ์ด๋ฏธ ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ์žˆ์Šต๋‹ˆ๋‹ค. - **์ œ์•ฝ(๊ทœ์น™ํ™” ํ•„์š”)**: ์–ด๋Œ‘ํ„ฐ๋Š” **ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งŒ** ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์„œ๋“œํŒŒํ‹ฐ ์˜์กด์„ฑ์ด ๋“ค์–ด์˜ค๋ฉด venv ์—†๋Š” ๊ฒฝ๋กœ๊ฐ€ ๊นจ์ง‘๋‹ˆ๋‹ค. #### ์„ ํ–‰ ํ•„์ˆ˜ ์ฒดํฌ๋ฆฌ์ŠคํŠธ (๋ˆ„๋ฝ ์‹œ ์กฐ์šฉํžˆ ์—…๊ทธ๋ ˆ์ด๋“œ๊ฐ€ ๋ง‰ํž˜) 1. **`deploy/remove.sh:83-91` `fallback_assets` ์— `".agents/skills/mam_agents"` ๋“ฑ๋ก.** ๋ฏธ๋“ฑ๋ก ์‹œ `tests/test_deploy_freshness.py::test_d2` ๊ฐ€ ์‹คํŒจํ•˜๋ฉฐ(ํ”„๋กœํ† ํƒ€์ž…์—์„œ ์‹ค์ œ ๋ฐœ์ƒ), ์–ธ์ธ์Šคํ†จ ํ›„ ์ž”์กด ์ž์‚ฐ์ด ์›Œํฌ์ŠคํŽ˜์ด์Šค๋ฅผ **์˜๊ตฌํžˆ ๊ตฌ๋ฒ„์ „์— ๊ณ ์ •**์‹œํ‚ต๋‹ˆ๋‹ค(`install.sh` ๋Š” ๋น„-์Šคํ‚ฌ ์ž์‚ฐ์„ "์—†์„ ๋•Œ๋งŒ" ๋ณต์‚ฌ). 2. `deploy/install.sh` ๋ฌด๊ฒฐ์„ฑ ์ž์‚ฐ ๋ชฉ๋ก ๋“ฑ๋ก. 3. `deploy/gitea-ci.yml:69-77` ์˜ `flake8` / `py_compile` ๊ฒฝ๋กœ ์ถ”๊ฐ€ โ€” ํ˜„์žฌ CI ํŒŒ์ด์ฌ ์žก์€ `multi-agent-mux-delegate-job/scripts/` ๋งŒ ๊ฒ€์‚ฌํ•˜๋ฏ€๋กœ ์‹ ๊ทœ ํŒจํ‚ค์ง€๋Š” ๋ฆฐํŠธ ์‚ฌ๊ฐ์ง€๋Œ€์ž…๋‹ˆ๋‹ค. #### ๋‹จ๊ณ„์  ์ดํ–‰ (๊ฐ ๋‹จ๊ณ„๋Š” ์…ธ ์‚ฌ๋ณธ ์ œ๊ฑฐ๋ฅผ ๊ฐ™์€ ์ปค๋ฐ‹์— ํฌํ•จ) | ๋‹จ๊ณ„ | ๋‚ด์šฉ | |---|---| | M0 | ํŒจํ‚ค์ง€ ๊ณจ๊ฒฉ + `lib.sh` source ์‹œ์  `PYTHONPATH` export + ๋ฐฐํฌ/CI ๋“ฑ๋ก | | M1 | `own_key` / `agent_of_row` ์ด๊ด€ โ€” **ํ”„๋กœํ† ํƒ€์ž… ๊ฒ€์ฆ ์™„๋ฃŒ: ํŒฌ์•„์›ƒ 34 โ†’ 29** | | M2 | `artifact_path` + `verify_artifact` (`verify_session_uuid` 4๋ถ„๊ธฐ, `DiscoveryContext` ์ ์šฉ, ๊ฒฉ๋ฆฌ ๊ฒฝ๋กœ ์ผ์›ํ™”) | | M3 | `spawn_spec` / `resume_spec` / `auth_ok` (createยทresume argv ๋ฐ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ) | | M4 | `discover()` (raw candidates + base class template filter) โ€” hermes DB ์Šคํ‚ค๋งˆ ์‹ค์ธก ์„ ํ–‰ | | M5 | `stop_session.sh` purge ๊ฒฝ๋กœ ๋ฐ exit key | | M6 | `ready_tokens` ์–ด๋Œ‘ํ„ฐ ์ด๊ด€ (`wait_for_tui_ready` 25์ค„ case ์ œ๊ฑฐ) | | M7 | claude ready tokens ์—์„œ `projects` ์ œ๊ฑฐ ๋ฐ ์ž์ฒด ๊ฒ€์ฆ ๋ถ„๋ฆฌ ์ปค๋ฐ‹ | - **์ •์งํ•œ ์ƒํ•œ**: 34 โ†’ **์•ฝ 10**. ๋‚จ๋Š” ์•ฝ 10๊ณณ์€ ์…ธ ์ƒ์ฃผ TUIยทํ”„๋กœ์„ธ์Šค ์ œ์–ด(`send_keys_safe` ์˜ agy/claude/cline ๋ถ„๊ธฐ, `handle_startup_dialogs`, spawn ๋ž˜ํผ ๋ถ„๊ธฐ, `pgrep -P` ์ž์‹ pid ๊ฒŒ์ดํŠธ)๋กœ ์ด ์ถ”์ƒํ™”์˜ ๋Œ€์ƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. - **์ค‘๋‹จ ๊ธฐ์ค€**: M2 ์ดํ›„์—๋„ ํŒฌ์•„์›ƒ์ด 29 โ†’ 20 ์ดํ•˜๋กœ ๋–จ์–ด์ง€์ง€ ์•Š์œผ๋ฉด ์ค‘๋‹จํ•˜๊ณ  ์ž”์—ฌ ๋‹จ๊ณ„๋ฅผ ์žฌ๊ฒ€ํ† ํ•ฉ๋‹ˆ๋‹ค. - **๊ฒ€์ฆ ์ƒํƒœ**: Rev.2 ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ์ค€ ์ „์ฒด ํšŒ๊ท€ **162 passed (ํšŒ๊ท€ 0)**, ๋ณ€์ด 6/6 ๊ฒ€์ถœ, ๋ฐฐํฌ ์Šค์œ„ํŠธ 25/25, `py_compile` ํ†ต๊ณผ. --- ## 2. ๐ŸŸ  ์—ฃ์ง€ ์ผ€์ด์Šค ๋ฐ ๋Ÿฐํƒ€์ž„ ๋ฒ„๊ทธ (Edge-case Bugs โ€” 5๊ฑด) ### **B-5: `df --output` GNU ์ „์šฉ ํ”Œ๋ž˜๊ทธ ์‚ฌ์šฉ์œผ๋กœ macOS NFS ๊ฐ์ง€ ์‹คํŒจ** โ€” โš ๏ธ **์ข…๊ฒฐ ๊ถŒ๊ณ  (์žฌํ˜„ ๋ถˆ๊ฐ€)** - ์› ์„œ์ˆ : macOS/BSD ํ™˜๊ฒฝ์—์„œ `df --output` ๊ตฌ๋ฌธ ์˜ค๋ฅ˜๋กœ NFS ๊ฐ์ง€๊ฐ€ ์‹คํŒจํ•˜๊ณ  "NFS ์•„๋‹˜"์œผ๋กœ ์˜คํŒ๋˜์–ด SQLite WAL ํฌ๋งท์„ ๊ฐ•ํ–‰ํ•ฉ๋‹ˆ๋‹ค. - **์‹ค์ธก(ecef05a3)**: `df --output=target` ์€ ์—ฌ์ „ํžˆ `rc=64` ๋กœ ์‹คํŒจํ•˜๋‚˜ `ea36e81` ์—์„œ ์ถ”๊ฐ€๋œ `df -P` ํด๋ฐฑ์ด ์ •์ƒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค(macOS ์‹ค์ธก: `/System/Volumes/Data`). **๊ฒฐ๋ก ("๊ฐ์ง€ ์‹คํŒจ")์€ ๋” ์ด์ƒ ์ฐธ์ด ์•„๋‹ˆ๋ฏ€๋กœ ์ข…๊ฒฐ์„ ๊ถŒ๊ณ ํ•ฉ๋‹ˆ๋‹ค.** - **์ž”์—ฌ๋ถ„ โ†’ B-11 ๋กœ ๋ถ„๋ฆฌ ๊ถŒ๊ณ **: `mount | grep -E "$mountpoint.*(nfs|cifs|smb|sshfs)"` ๊ฐ€ ๋งˆ์šดํŠธํฌ์ธํŠธ๋ฅผ ์ด์Šค์ผ€์ดํ”„ ์—†์ด ERE ์— ๋ณด๊ฐ„ํ•˜์—ฌ ๊ฒฝ๋กœ์˜ `.` ์ด ์ž„์˜ ๋ฌธ์ž๋กœ ํ•ด์„๋ฉ๋‹ˆ๋‹ค(์ด๋ก ์ƒ ์˜คํƒ). ### **B-6: ์Šคํ‚ฌ ํŠธ๋ฆฌ์— ์ž„์‹œ ํŒŒ์ผ ๋ณต์‚ฌ ๋ฐ ์œ ์ถœ** - `run_loop.sh::delegate_job_safe`๊ฐ€ ๋ž˜ํผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ `.agents/skills/...` ํŠธ๋ฆฌ ๋‚ด๋ถ€์— `.tmp`๋กœ ๋ณต์‚ฌํ•˜์—ฌ ๋ฒ„์ „ ๊ด€๋ฆฌ ํŠธ๋ฆฌ๋ฅผ ์˜ค์—ผ์‹œํ‚ค๊ณ  rsync ๋ฐฐํฌ ์‹œ ์™ธ๋ถ€๋กœ ์œ ์ถœ๋ฉ๋‹ˆ๋‹ค. ### **B-8: `send_keys_safe` agy ๊ฒฝ๋กœ ๊ฒ€์ฆ ์ดํƒˆ** - agy ์„ธ์…˜ ์ฃผ์ž… ์‹œ ์ฃผ์ž… ์‹คํŒจ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์ฆํ•˜์ง€ ์•Š๊ณ  ๋ฌด์กฐ๊ฑด `return 0`์„ ๋‚จ๊ฒจ ์‹คํŒจ ์‹œ์—๋„ ์„ฑ๊ณต์œผ๋กœ ๋ณด๊ณ ๋ฉ๋‹ˆ๋‹ค. ### **B-9: `LOGS_DIR` import ์‹œ์  cwd ๊ณ ์ •** - `mqtt_common.py` ๋ชจ๋“ˆ ๋กœ๋“œ ์‹œ์ ์˜ cwd๋กœ ๊ฐ์‚ฌ ๋กœ๊ทธ ๊ฒฝ๋กœ๊ฐ€ 1ํšŒ ๊ณ ์ •๋ฉ๋‹ˆ๋‹ค. ### **B-10: `agent_identities` ์“ฐ๊ธฐ ๊ฒฝ๋กœ ๋ถ€์žฌ ๋ฐ PyYAML ์˜์กด์„ฑ** - ์ €์žฅ์†Œ ์ „์ฒด์— `agent_identities` ๋ฅผ ์ƒ์„ฑยท๊ฐฑ์‹ ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ 0๊ฑด์ด๋ฉฐ, `lib.sh` ์˜ PyYAML ํ•˜๋“œ ์˜์กด์„ฑ์œผ๋กœ ์ธํ•ด `.db` ๋งŒ์œผ๋กœ ์ถฉ๋ถ„ํ•œ ๊ฒฝ์šฐ์—๋„ PyYAML ๋ถ€์žฌ ์‹œ ์ƒํƒœ ์กฐํšŒ๊ฐ€ ๋ฌด๋ ฅํ™”๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. --- ## 3. ๐ŸŸก ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์ตœ์ ํ™” ๊ณผ์ œ (Orchestration Optimizations โ€” 0๊ฑด โ€” ์ „์› ์™„๋ฃŒ) --- ## 4. โšช ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ ๋ฐ ์ฃฝ์€ ์ฝ”๋“œ (Legacy Remnants โ€” 3๊ฑด) ### **C-3: ๊ฒฉ๋ฆฌ ๊ด€๋ จ ์ž”์žฌ** โ€” โš ๏ธ **C-3a / C-3b ๋กœ ๋ถ„๋ฆฌ ํ•„์š” (ยง6.5 ์ฐธ์กฐ)** - **C-3a (์ฆ‰์‹œ ์‹คํ–‰ ๊ฐ€๋Šฅ)**: `provision_isolation` / `isolation_lever` / `isolation_env_prefix` / `isolation_cmd_args` 4์ข… **๋นˆ ์Šคํ…**. ํ”„๋กœ๋•์…˜ ํ˜ธ์ถœ์ž 0๊ฑด. ์ด๋ฅผ ๊ณ ์ •ํ•˜๋˜ ๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 5๊ฑด(`test_tier1_unit.py` 3, `test_tier2_component.py` 1 ๋“ฑ)๋„ ํ•จ๊ป˜ ์ œ๊ฑฐ ๋Œ€์ƒ. - **C-3b (๋ณด๋ฅ˜ โ€” A-4 M2 ๊ฒฐ์ • ์‚ฌํ•ญ)**: `isolation.root` ํ–‰ ํ•„๋“œ ์†Œ๋น„์ž(`verify_session_uuid` ์˜ `iso_root` ๋ถ„๊ธฐ, `mam_session_iso_root`, `find_workspace_uuid` ๊ฒฉ๋ฆฌ ๋ถ„๊ธฐ, `stop_session.sh:277` purge ๊ฐ€๋“œ). **b4a1d094 / 44062a63 ์—์„œ ์˜๋„์ ์œผ๋กœ ๋˜์‚ด๋ฆฐ ์ฝ”๋“œ**์ด๋ฏ€๋กœ ์ง€์šฐ๋ฉด ๊ทธ ์ˆ˜์ •์ด ํšŒ๊ท€ํ•ฉ๋‹ˆ๋‹ค. ### **C-4: ์ฐธ์กฐ 0ํšŒ ๋ฏธ์‚ฌ์šฉ ์‹ฌ๋ณผ** โ€” โš ๏ธ **๋ชฉ๋ก ์ •์ •๋จ (7์ข… โ†’ ์‹ค์งˆ 3์ข…)** - **์‹ค์ œ ๋Œ€์ƒ 3์ข…**: `_REAL_HERDR_PATH`(๋Œ€์ž…ยทexport ๋งŒ), `TERMINAL_STATUSES`(`registry.py:38` ์ •์˜๋งŒ), `ISOLATE`(`create_session.sh:57` ๋Œ€์ž…๋งŒ). - **๋ชฉ๋ก์—์„œ ์ œ์™ธ**: `_HERDR_SHIM_DIR_PATTERN` ์€ **์‚ฌ์šฉ ์ค‘**์ž…๋‹ˆ๋‹ค(`lib.sh:57` ์ •์˜ โ†’ `lib.sh:79` ์‚ฌ์šฉ). ์ง€์šฐ๋ฉด shim ๊ฒฝ๋กœ ํŒ์ •์ด ๊นจ์ง‘๋‹ˆ๋‹ค. `local_herdr` ์€ ์ฐธ์กฐ 0๊ฑด์œผ๋กœ **์ด๋ฏธ ์ œ๊ฑฐ**๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - `provision_isolation` ์€ **C-3a ์™€ ์ค‘๋ณต**์ด๋ฏ€๋กœ ๊ทธ์ชฝ์—์„œ ํ•จ๊ป˜ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ### **C-6: `stop_session.sh` ๋„์›€๋ง ๋ฌธ์„œ ๊ตฌ๋ฒ„์ „ ํ‘œ๊ธฐ** - ์Šคํฌ๋ฆฝํŠธ ๋„์›€๋ง์—๋Š” `--mode soft|hard` ๋“ฑ์ด ์„œ์ˆ ๋˜์–ด ์žˆ์œผ๋‚˜ ์‹ค์ œ ์˜ต์…˜ ํŒŒ์„œ๋Š” `exit 2`๋กœ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. --- ## 5. ๐ŸŽ‰ ์™„๋ฃŒ๋œ ๊ณผ์ œ (Completed Tasks โ€” 12๊ฑด) ### **P0-2 (O-2): ๋™์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‚ด ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ๋ฐฉ์ง€ ์›์ž์  ๋ฝ ๋ฐ ๋งˆ์ปค ์†Œ์œ ๊ถŒ ๋Œ€์กฐ ์‚ญ์ œ ์กฐ์น˜** โ€” โœ… ์™„๋ฃŒ - [`.agents/skills/multi-agent-mux-loop/scripts/loop_lock.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/loop_lock.sh) ํ—ฌํผ ๋ชจ๋“ˆ์„ ์ž‘์„ฑํ•˜์—ฌ, `set -C` (noclobber) ๊ธฐ๋ฐ˜ ์›์ž์  ๋ฝ ์ƒ์„ฑ ๋ฐ ๋งˆ์ปค ์ž„์‹œ ์“ฐ๊ธฐ+Atomic Rename ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋งˆ์ปค ์ƒ์˜ `pid` + `lstart`(ํ”„๋กœ์„ธ์Šค ์‹œ์ž‘์‹œ๊ฐ) ์‹ ์› ๋Œ€์กฐ ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•˜์—ฌ, ๋™์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‚ด ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ์‹œ ์ด๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๊ธฐ๋™์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค. - ์ข…๋ฃŒ ํŠธ๋žฉ(`_mam_release_guard`) ์‹œ ๋งˆ์ปค ํŒŒ์ผ ์ƒ์˜ `pid` ๋ฐ `lstart` ๊ฐ€ ์ž๊ธฐ ์ž์‹ ๊ณผ 100% ์ผ์น˜ํ•  ๋•Œ๋งŒ ๋งˆ์ปค๋ฅผ ์‚ญ์ œํ•˜๋„๋ก ์†Œ์œ ๊ถŒ ๋Œ€์กฐ ์‚ญ์ œ๋ฅผ ์ˆ˜๋ฆฝํ•˜์—ฌ, ํƒ€ ๋ฃจํ”„ ์ธ์Šคํ„ด์Šค์˜ ๋งˆ์ปค๋ฅผ ์‹ค์ˆ˜๋กœ ์ œ๊ฑฐํ•˜์—ฌ O-3 ๊ฐ€๋“œ๋ ˆ์ผ์„ ๋ฌด๋ ฅํ™”์‹œํ‚ค๋Š” ๊ฒฐํ•จ์„ ์›์ฒœ ์ฐจ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_o2_race_free_lock.py` (22/22 PASS) ๋ฐ ์ „์ฒด ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ (46/46 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **P0-1 (B-7): `run_loop.sh` ๋ฃจํ”„ ๊ธฐ๋™ ์™ธ๊ณฝ diff ๋ˆ„๋ฝ ๋ฐ ์‹ ๊ทœ ๋ฏธ์ถ”์  ํŒŒ์ผ ์บก์ฒ˜ ๊ฒฐํ•จ ์กฐ์น˜** โ€” โœ… ์™„๋ฃŒ - `.agents/skills/multi-agent-mux-loop/scripts/diff_collect.sh` ํ—ฌํผ ๋ชจ๋“ˆ์„ ์ž‘์„ฑํ•˜์—ฌ, `run_loop.sh` ๊ฐ€ ์–ด๋А CWD ์—์„œ ๊ธฐ๋™๋˜๋”๋ผ๋„ ํ•ญ์ƒ `$REPO_ROOT` ๊ธฐ๋ฐ˜์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ์ด๋™ํ•˜์—ฌ `git diff` ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋„๋ก CWD ๋…๋ฆฝ์„ฑ์„ ํ™•๋ฆฝํ–ˆ์Šต๋‹ˆ๋‹ค. - Git ์ธ๋ฑ์Šค๋ฅผ ์˜ค์—ผ์‹œํ‚ค๋Š” `git add -N` ๋Œ€์‹ , `git ls-files -o --exclude-standard -z` ์™€ `git diff --no-index --binary /dev/null "$f"` ๊ตฌ๋ฌธ์„ ์กฐํ•ฉํ•˜์—ฌ ์—์ด์ „ํŠธ๊ฐ€ **์ƒˆ๋กœ ์ƒ์„ฑํ•œ ์‹ ๊ทœ ๋ฏธ์ถ”์  ํŒŒ์ผ(Untracked Files)๊นŒ์ง€ 100% diff์— ์•ˆ์ „ํ•˜๊ฒŒ ๋ณ‘ํ•ฉ**์‹œํ‚ค๋Š” ๊ธฐ๋ฒ•์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. - diff ๊ฐ€ 500์ค„ ๋˜๋Š” 30KB ๋ฅผ ์ดˆ๊ณผํ•  ๊ฒฝ์šฐ `--stat` ์š”์•ฝ์œผ๋กœ ์ „ํ™˜ํ•˜๋˜, **๋ฆฌ๋ทฐ์–ด ํ”„๋กฌํ”„ํŠธ์— `[WARNING: Truncated]` ๊ฒฝ๊ณ  ํƒœ๊ทธ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๋…ธ์ถœ**ํ•˜์—ฌ ๊ฐ์ถฐ์ง„ PASS ํŒ์ •์„ ์›์ฒœ ์ฐจ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์ž์œจ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ฃจํ”„(`run_loop.sh --plan --all-reviewer`)๋ฅผ ํ†ตํ•ด Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3์ž์— ์˜ํ•ด ๊ตฌํ˜„ ๋ฐ ๊ต์ฐจ ๊ฒ€์ฆ ํ›„ **`[VERDICT: PASS]` (๋งŒ์žฅ์ผ์น˜ ํ†ต๊ณผ)** ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_b7_diff_untracked.py` (20/20 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **Rev.2 (b4a1d094): ์ƒ์„ฑ ์‹œ ์„ธ์…˜ ID ์ž๋™ ํ• ๋‹น ๋ฐ Reconciler ๊ณ ์ •/๊ฒฝ๋กœ ์ •๊ทœํ™” ํ”„๋กœํ† ์ฝœ** โ€” โœ… ์™„๋ฃŒ - ์‹ ๊ทœ `claude` ์„ธ์…˜ ์ƒ์„ฑ ์‹œ `mam_gen_uuid`๋กœ UUID๋ฅผ ์ฆ‰์‹œ ์ƒ์„ฑํ•˜์—ฌ `--session-id `๋กœ ์ „๋‹ฌํ•˜๊ณ , `session_id_source: assigned`, `session_id_verified: false`๋กœ ๋“ฑ๋กํ•˜๋Š” ์›์ž์  ๊ณ ์ • ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ฒซ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€ ์ „๋‹ฌ ์‹œ ๋””์Šคํฌ ํŠธ๋žœ์Šคํฌ๋ฆฝํŠธ `.jsonl` ์ƒ์„ฑ์„ ๋ชจ๋‹ˆํ„ฐ ๋ฃจํ”„(`reconcile.sh` drift C0)๊ฐ€ ๊ฐ์ง€ํ•˜๊ณ  `session_id_verified: true`, `last_visible_status: pinned`๋กœ ๊ณ ์ •์‹œํ‚ต๋‹ˆ๋‹ค. - ๋ฏธํ• ๋‹น ๋‹ค์ˆ˜ ํ›„๋ณด ๋ฐœ๊ฒฌ ์‹œ ๋ฌด์ž‘์œ„ ๊ณ ์ •์„ ๊ธˆ์ง€ํ•˜๊ณ  `C-ambiguous` ์ƒํƒœ๋ฅผ ๋ช…ํ™•ํžˆ ๋ณด๊ณ ํ•˜๋„๋ก ๊ฐ•ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์‹ฌ๋ณผ๋ฆญ ๋งํฌ/ํŠธ๋ ˆ์ผ๋ง ์Šฌ๋ž˜์‹œ/์ƒ๋Œ€๊ฒฝ๋กœ ๊ณ„์‚ฐ ์‹œ `mam_abs_workspace` ๋ฐ `mam_workspace_key` (`cd -P && pwd -P` / `os.path.realpath`) ๊ฒฝ๋กœ ์ •๊ทœํ™”๋ฅผ ์ „์ˆ˜ ์ ์šฉํ•˜์—ฌ 100% ํ‚ค ์ผ์น˜์„ฑ์„ ํ™•๋ฆฝํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ๋‹จ์œ„/ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_uuid_target.py` (13/13 PASS) ๋ฐ ์ „์ฒด ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ๋ฅผ ๊ฒ€์ฆ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค. ### **B-4: ์‹œํ”„ํŠธ `ls`์˜ `created` ๋™์  POSIX ํƒ€์ž„์Šคํƒฌํ”„ ๋ณต์› ๋ฐ ์žฌ๊ฐœ ๊ฐ€๋“œ ์ •์ƒํ™”** โ€” โœ… ์™„๋ฃŒ - `.agents/skills/lib.sh` 554๋ฒˆ ๋ผ์ธ์˜ `999999` ํ•˜๋“œ์ฝ”๋”ฉ ์ถœ๋ ฅ์„ ์ œ๊ฑฐํ•˜๊ณ , real herdr ๋˜๋Š” `.mam/agent-sessions.yaml` ์— ๊ธฐ๋ก๋œ ์„ธ์…˜ ์ƒ์„ฑ ์‹œ๊ฐ(`created`/`created_at`/`created_epoch`) ๋ฐ ๋™์  POSIX ํƒ€์ž„์Šคํƒฌํ”„(`int(time.time())`)๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ์ •์ œํ–ˆ์Šต๋‹ˆ๋‹ค. - `reconcile.sh` drift-B ๊ฐ์ง€ ์‹œ epoch 0 ๋ฐ `1970-01-01` ์˜ค๊ธฐ๋ก ๊ฒฐํ•จ์„ ์ฐจ๋‹จํ•˜์—ฌ `find_workspace_uuid` ์žฌ๊ฐœ ๊ฐ€๋“œ๊ฐ€ ์ •์ƒ ์ž‘๋™ํ•˜๋„๋ก ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์ž์œจ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ฃจํ”„(`run_loop.sh --plan --all-reviewer`)๋ฅผ ํ†ตํ•ด Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3์ž์— ์˜ํ•ด ๊ตฌํ˜„ ๋ฐ ๊ต์ฐจ ๊ฒ€์ฆ ํ›„ **`[VERDICT: PASS]` (๋งŒ์žฅ์ผ์น˜ ํ†ต๊ณผ)** ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_b4_session_created.py` (21/21 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **O-2: ๋™์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‚ด ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ๋ฐฉ์ง€ ๋ฝ (Race-Free Mutex & Ownership)** โ€” โœ… ์™„๋ฃŒ - `loop_lock.sh` ๋…๋ฆฝ ๋ฝ ๋ชจ๋“ˆ(`mam_acquire_loop_lock` / `mam_release_loop_lock`)์„ ์ƒ์„ฑํ•˜๊ณ  ํ•˜๋“œ๋งํฌ(`ln`) ๊ธฐ๋ฐ˜ ์›์ž์  ํŒจํ‚ค์ง• ์“ฐ๊ธฐ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋นˆ/ํŒŒํ‹ฐ์…œ ๋งˆ์ปค ๋…ธ์ถœ ๋ฐ Livelock ์„ ์›์ฒœ ์ฐจ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - `pid` + `lstart`(ํ”„๋กœ์„ธ์Šค ์‹œ์ž‘ ์‹œ๊ฐ) ๊ธฐ๋ฐ˜ ์‹ ์› ๊ฒ€์ฆ ๋กœ์ง์„ ์ ์šฉํ•˜์—ฌ PID Rollover ์˜คํŒ์„ ์ฐจ๋‹จํ•˜๊ณ , stale ๋ฝ ํšŒ์ˆ˜ ์‹œ ๋งˆ์ปค ๊ทœ์•ฝ๊ณผ ๋™์ผํ•œ `steal_lock` (`$marker.steal`) ์‹ ์› ์ธ์ˆ˜ ๋””์ŠคํŒจ์ฒ˜๋ฅผ ๊ตฌ์ถ•ํ•˜์—ฌ ๊ณ ์•„ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ธํ•œ ์˜๊ตฌ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋ฐ๋“œ๋ฝ ๊ฒฐํ•จ์„ ๊ทผ๋ณธ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ด์ „ Rev.1 ๋ ˆ๊ฑฐ์‹œ `.steal` ๋””๋ ‰ํ„ฐ๋ฆฌ ์ž๋™ ์ •๋ฆฌ ์—…๊ทธ๋ ˆ์ด๋“œ ๊ฒฝ๋กœ ๋ฐ ์†Œ์œ ๊ถŒ ๊ฒ€์ฆ ๊ธฐ๋ฐ˜ ์›์ž์  ํ•ด์ œ(`mam_release_loop_lock`)๋ฅผ ํ†ตํ•ฉํ•˜์—ฌ ์ด์ฐจ ๋ฃจํ”„ ์ข…๋ฃŒ ์‹œ ์†Œ์œ ๊ถŒ ์—†๋Š” ๋งˆ์ปค ํŒŒ๊ธฐ๋ฅผ ์ฐจ๋‹จํ•˜๊ณ  O-3 ์œ„์ž„ ๊ฐ€๋“œ๋ฅผ ์™„๋ฒฝ ๋ณดํ˜ธํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_o2_race_free_lock.py` (22/22 PASS) ๋ฐ ์ „์ฒด ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ (204/204 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **O-3: ์กฐ๊ฑด๋ถ€ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์œ„์ž„ ๊ฐ€๋“œ (Invocation-Aware Scoped Guard)** โ€” โœ… ์™„๋ฃŒ - Normal Mode(์ง์ ‘ ์†Œ์Šค ์ˆ˜์ •)์™€ Loop Active Mode(`/multi-agent-mux-loop` ์ธ๋ณดํฌ ์‹œ `run_loop.sh` ์ž์œจ ์œ„์ž„)์˜ ์—ญํ•  ๊ฒฝ๊ณ„๋ฅผ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•˜๋Š” ์Šคํ‚ฌ ์ธํ„ฐ์…‰ํ„ฐ ๊ฐ€๋“œ๋ ˆ์ผ(`.agents/hooks.json` & `.agents/hooks/loop_delegation_guard.sh`)์„ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. - step-type ํŒŒ์ƒ๋ช… ๋งค์ฒ˜(`file_change|edit_notebook|write_blob`)๋ฅผ ์ ์šฉํ•˜์—ฌ ๊ฐ€๋“œ ๋ฌด๋ฐœํ™” ๊ฒฐํ•จ์„ ๋ฐฉ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค. - `pid` + `lstart`(ํ”„๋กœ์„ธ์Šค ์‹œ์ž‘์‹œ๊ฐ) ์‹ ์› ๋Œ€์กฐ ๊ฒ€์ฆ์„ ํ†ตํ•ด PID Rollover ๋ฐ `PermissionError` ์‹œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” Livelock ์˜๊ตฌ ์ฐจ๋‹จ ์˜คํŒ์„ ์™„๋ฒฝํžˆ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. - `run_loop.sh` ๋งˆ์ปค ๊ธฐ๋ก ๋ฐ `delegate_job_safe` ํŠธ๋žฉ ๋ณต์›(`_mam_release_guard`)์„ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค. - `AGENTS.md`, `MULTI_AGENT_RULES.md` (.ko.md), `SKILL.md` ๋ฌธ์„œ๋ฅผ ์ „์ˆ˜ ๋Œ€์นญ ๊ฐฑ์‹ ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ๋‹จ์œ„/ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_o3_scoped_guard.py` (22/22 PASS)๋ฅผ ์ˆ˜๋ฆฝํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **A-1: ์›Œํฌ์ŠคํŽ˜์ด์Šค ์„ธ์…˜ ๊ฒฉ๋ฆฌ & drift-B ์˜ค๋“ฑ๋ก ๋ฐฉ์ง€** โ€” โœ… ์™„๋ฃŒ - `derive_workspace_slug` ํ—ฌํผ ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๊ฒฝ๋กœ ๊ธฐ๋ฐ˜ ๋‹จ์ผ ์†Œ์ผ“ ์Šฌ๋Ÿฌ๊ทธ(`mam--`) ๋„์ถœ ์ฒด๊ณ„๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. - `reconcile.sh` drift-B ์ž๋™ ๋“ฑ๋ก ์‹œ foreign cwd ์ฐจ๋‹จ ๊ฒŒ์ดํŠธ๋ฅผ ๊ตฌ์ถ•ํ•˜์—ฌ ์„ธ์…˜ ์˜ค๋“ฑ๋ก์„ ๋ฐฉ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค. ### **A-3: ์‹œํ”„ํŠธ ๋ฒ„ํผ ๋™์‹œ ์ฃผ์ž… ์˜ค์—ผ & ์ž๋™ GC ์ฒด๊ณ„ ๊ตฌ์ถ•** โ€” โœ… ์™„๋ฃŒ - `lib.sh` ๋‚ด `send_keys_safe` ์‹œํ”„ํŠธ ๋ฒ„ํผ ๋ช…๋ น์˜ ์ž„์‹œ ํŒŒ์ผ๋ช…์„ `sks_${sess}_${job_id}_$$_${RANDOM}_$(date +%s%N)` ์‹ ํ˜ธ์ถœ ๋‹จ์œ„ ๋…๋ฆฝ ํ† ํฐ์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋‹ค์ค‘ ์—์ด์ „ํŠธ ๋™์‹œ ์ฃผ์ž… ์‹œ ๋Œ€ํ™” ๊ต์ฐจ ์˜ค์—ผ ๋ฐ ๋ฌด์Œ ์œ ์‹ค(T5)์„ ์›์ฒœ ์ฐจ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - `set-buffer` ์‹œ ์›์ž์  ์ž„์‹œ ์“ฐ๊ธฐ(`.$buf.$$.tmp`) ๋ฐ rename(`mv -f`) ๊ตฌ์กฐ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ํŒŒํ‹ฐ์…œ ๋ ˆ์ฝ”๋“œ ๊ด€์ธก์„ ๋ฐฉ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ธํ„ฐ๋ŸฝํŠธ/์˜ˆ์™ธ ์ข…๋ฃŒ ์‹œ ๋‚จ๋Š” stale ๋ฒ„ํผ ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ ์ •๋ฆฌํ•˜๋Š” 60๋ถ„ ๋‚ด์žฅ GC(`find -mmin +60 -delete`)๋ฅผ ๋‚ด์žฅํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_a3_buffer_isolation.py` (12/12 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **C-2: ๋ฏธ์‚ฌ์šฉ `.cache/` ์ƒํƒœ ๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ ๋ฐ ๋ฐ๋“œ ์ฝ”๋“œ ์ •๋ˆ** โ€” โœ… ์™„๋ฃŒ - `reconcile.sh`์—์„œ ์•„๋ฌด ๋ฐ์ดํ„ฐ๋„ ์ €์žฅํ•˜์ง€ ์•Š๋˜ ๋ฏธ์‚ฌ์šฉ `.cache/multi-agent-mux-monitor` ๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ(`mkdir -p`) ๊ตฌ๋ฌธ ๋ฐ `STATE_DIR` ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋ ˆ๊ฑฐ์‹œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ `AGENT_SESSIONS_STATE_DIR` ์„ค์ • ์‹œ ๋ฌด์Œ ์ƒ์„ฑ์„ ๋ฐฉ์ง€ํ•˜๊ณ  stderr์— ๊ฐ€์ด๋“œ ๊ฒฝ๊ณ ๋งŒ ์•ˆ๋‚ดํ•˜๋„๋ก ์ •๋ˆํ–ˆ์Šต๋‹ˆ๋‹ค. - `deploy/remove.sh` ์–ธ์ธ์Šคํ†จ๋Ÿฌ์—์„œ ๋ฏธ์‚ฌ์šฉ `.cache/` ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ ์•ˆ์ „ํ•˜๊ฒŒ ์ œ๊ฑฐ(`rmdir .cache`)ํ•˜๋„๋ก ๊ฐœ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ๋‹จ์œ„/ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_c2_no_stale_cache_dir.py` (5/5 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **A-5: `HERDR_SESSION_NAME` ๋„ค์ดํ‹ฐ๋ธŒ ์ „ํ™˜** โ€” โœ… ์™„๋ฃŒ - ๊ธฐ์กด `HERDR_SERVER_NAME` ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ herdr ์‹œํ”„ํŠธ๊ฐ€ ์ง์ ‘ ์ฝ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ **`HERDR_SESSION_NAME`** ๋ฐ YAML ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํ‚ค **`herdr_session`**์œผ๋กœ ์ „์ˆ˜ ์ „ํ™˜ ๋‹จ์ผํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. ### **B-1: `find_workspace_uuid` tier-3 ์‹ ์› ์บ์‹œ ํ•ด์„ ์˜ค๋ฅ˜ ํ•ด๊ฒฐ** โ€” โœ… ์™„๋ฃŒ - `lib.sh` tier-3 ์‹ ์› ์บ์‹œ ์กฐํšŒ ์‹œ ๋ฏธ์ •์˜ ๋ณ€์ˆ˜(`db_path`, `yaml_path`) ๋ฐ `yaml` import ๋ˆ„๋ฝ์œผ๋กœ ๋ฌด์กฐ๊ฑด `NameError` ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋˜ ๊ฒฐํ•จ์„ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. - DB๋ฅผ 1์ฐจ ๊ถŒ์œ„ ๊ฒฝ๋กœ๋กœ, `$YAML_PATH`๋ฅผ ํด๋ฐฑ์œผ๋กœ ์ •์ œํ•˜๊ณ  ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ `tests/test_b1_tier3_identity.py` (8/8 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **B-3: `command -v herdr` ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ๋ฌด๋ ฅํ™”** โ€” โœ… ์™„๋ฃŒ - `lib.sh`์— `_canonical_file()`, `_is_shim_path()`, `_resolve_real_herdr_path()`, `has_real_herdr()` ํ—ฌํผ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ `herdr()` bash ํ•จ์ˆ˜ ์˜คํŒ๊ณผ `.mam/shim/herdr` ๋ž˜ํผ ๋งค์นญ(ํŒŒ์ผ ์ˆ˜์ค€ ์‹ฌ๋งํฌ ํฌํ•จ)์„ ์™„์ „ ์ฐจ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - `create_session.sh`, `multi-agent-mux-delegate-job`, `create/SKILL.md`, `status/SKILL.md` ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ๋ฅผ `has_real_herdr`๋กœ ์ „์ˆ˜ ๊ต์ฒดํ–ˆ์Šต๋‹ˆ๋‹ค. - ํšŒ๊ท€ ํ…Œ์ŠคํŠธ `tests/test_b3_herdr_preflight.py` (11/11 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **C-1: Kanban ๋ฌธ์„œ 29ํšŒ ์–ธ๊ธ‰ vs ์‹ค์ œ ๊ตฌํ˜„ 0๊ฑด** โ€” โœ… ์™„๋ฃŒ - SKILL.md 3์ข…(monitor 22 / status 5 / create 2)๊ณผ README 2์ข…์˜ Kanban ์„œ์ˆ ์„ ์ „๋ฉด ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. - `multi-agent-mux-monitor` ์˜ ์‹คํ–‰ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์„œ์ˆ ์„ ์‹ค์ œ ๊ตฌํ˜„์ธ `reconcile.sh --subscribe` (MQTT push + ๋ธŒ๋กœ์ปค ๋‹ค์šด ์‹œ ํด๋ง ํด๋ฐฑ) ๊ธฐ์ค€์œผ๋กœ ์žฌ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์Šคํ‚ฌ ์ฐธ์กฐ 2๊ฑด(`kanban-worker`, `kanban-orchestrator`)์„ ์‹ค์กด ์Šคํ‚ฌ๋กœ ๊ต์ฒดํ–ˆ์Šต๋‹ˆ๋‹ค. - `hermes kanban create` CLI ํ”Œ๋ž˜๊ทธ ์ž”์žฌ 10์ข…(`--goal-max-turns`, `--assignee`, `--comment-card` ๋“ฑ)์„ ํŒŒ์ƒํ˜• ๊ฒ€์ฆ ๊ฒŒ์ดํŠธ(G-C)๋กœ ์ฐจ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ œํ’ˆ ํ‘œ๋ฉด(`.agents/skills/`, `README*.md`) Kanban ์ฐธ์กฐ **0๊ฑด** ํ™•์ธ. ### **O-1: ํƒ€๋‹นํ•˜์ง€ ์•Š์€ ๋ฆฌ๋ทฐ ํ”ผ๋“œ๋ฐฑ ๊ฑฐ๋ถ€/๋ฐ˜๋ก  ํ”„๋กœํ† ์ฝœ ๋ฏธ์ง€์› (Rebuttal Protocol)** โ€” โœ… ์™„๋ฃŒ - `run_loop.sh`์— `--max-rebut N` (๊ธฐ๋ณธ๊ฐ’ 1) ์˜ต์…˜ ๋ฐ Rebuttal/Re-adjudication/Arbitration 3๋‹จ๊ณ„ ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. - Creator๊ฐ€ ์ง€์  ํ•ญ๋ชฉ ๊ฑฐ๋ถ€ ์‹œ `[REBUT: ]` ํƒœ๊ทธ๋ฅผ ๋‚จ๊ฒจ ํ•ด๋‹น ๋ฆฌ๋ทฐ์–ด ๋Œ€์ƒ ์žฌ์‹ฌ(`[ADJUDICATION: SUSTAINED/OVERRULED]`)์„ ๊ฐ€๋™ํ•˜๋ฉฐ, ๊ต์ฐฉ ์‹œ Planner ์žฌ์ •(`[ARBITRATION: CREATOR/REVIEWER]`) ๋˜๋Š” Fail-Closed ๊ฒฐ์ •์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. - bash 3.2 macOS ๊ทœ๊ฒฉ ๋นˆ ๋ฐฐ์—ด ํ™•์žฅ ์•ˆ์ „์„ฑ(`${ARR[@]+"${ARR[@]}"}`) ๋ฐ per-iteration budget reset / total budget cap ๊ฒฐํ•จ์„ ์™„๋ฒฝํžˆ ๋ณด์™„ํ•˜๊ณ  ํšŒ๊ท€ ํ…Œ์ŠคํŠธ `tests/test_o1_rebuttal.py` (10/10 PASS)๋กœ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. - `MULTI_AGENT_RULES.md`, `.ko.md`, `multi-agent-mux-loop/SKILL.md` ๋ฌธ์„œ ์—ฐ๋™์„ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค. --- ## 6. ๐Ÿงญ ์šฐ์„ ์ˆœ์œ„ ์‹คํ–‰ ๋กœ๋“œ๋งต (Prioritized Execution Roadmap) > ํ‰๊ฐ€ ๊ทผ๊ฑฐยทํ•ญ๋ชฉ๋ณ„ ์‹ค์ธก ๊ฒฐ๊ณผ๋Š” `.mam/jobs/ecef05a3/claude-reports/report-final.md` ์ฐธ์กฐ. > **์ˆœ์œ„๋ฅผ ๋งค๊ธฐ๊ธฐ ์ „์— 12๊ฑด์„ ์ „๋ถ€ ํ˜„์žฌ ์ฝ”๋“œ์— ๋Œ€์กฐํ–ˆ์œผ๋ฉฐ, ๊ทธ์ค‘ 4๊ฑด(A-2ยทB-5ยทC-3ยทC-4)์˜ ๊ธฐ์กด ์„œ์ˆ ์ด ํ˜„์žฌ ์ฝ”๋“œ์™€ ๋‹ฌ๋ผ ๋ณธ๋ฌธ์„ ์ •์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.** ### 6.1 ์ •๋ ฌ ์›์น™ โ‘  ์™ธ๋ถ€์—์„œ ํŠธ๋ฆฌ๊ฑฐ ๊ฐ€๋Šฅํ•œ ์œ„ํ—˜ โ†’ โ‘ก ๊ฒ€์ฆ ์‹ ํ˜ธ๋ฅผ **๊ฑฐ์ง“์œผ๋กœ** ๋งŒ๋“œ๋Š” ๊ฒฐํ•จ โ†’ โ‘ข ๋‹ค๋ฅธ ํ•ญ๋ชฉ์„ ์‹ธ๊ฒŒ ๋งŒ๋“œ๋Š” ๊ตฌ์กฐ ์ž‘์—… โ†’ โ‘ฃ ๊ตญ์†Œ ๊ฒฐํ•จ โ†’ โ‘ค ์ •๋ฆฌ. **์กฐ์šฉํ•œ ์‹คํŒจ์— ๊ฐ€์ค‘์น˜๋ฅผ ๋‘ก๋‹ˆ๋‹ค.** ์‹œ๋„๋Ÿฌ์šด ์‹คํŒจ๋Š” ์‚ฌ๋žŒ์ด ๋ณด์ง€๋งŒ, ์กฐ์šฉํ•œ ์‹คํŒจ๋Š” "ํ†ต๊ณผ"๋กœ ๊ธฐ๋ก๋˜๊ณ  ๊ทธ ์œ„์— ๋‹ค์Œ ์ž‘์—…์ด ์Œ“์ž…๋‹ˆ๋‹ค. ### 6.2 ์‹คํ–‰ ์ˆœ์„œ > **์‚ฌ์šฉ์ž ์ง€์นจ ๋ฐ˜์˜**: **A-2 (๊ณต๊ฐœ ๋ธŒ๋กœ์ปค & HMAC)** ๊ณผ์ œ๋Š” ์ฐจํ›„ ์ž์ฒด ์ „์šฉ MQTT ๋ธŒ๋กœ์ปค ์„œ๋ฒ„๋ฅผ ๊ตฌ์ถ•ํ•  ์˜ˆ์ •์ด๋ฏ€๋กœ ์‚ฌ์šฉ์ž ์ง€์นจ์— ๋”ฐ๋ผ **์šฐ์„ ์ˆœ์œ„๋ฅผ ์ตœํ•˜์œ„(P5)๋กœ ์กฐ์ •**ํ•˜์˜€์Šต๋‹ˆ๋‹ค. | ์ˆœ์œ„ | ํ•ญ๋ชฉ | ๊ทผ๊ฑฐ | ๋น„์šฉ | ์„ ํ–‰ | |---|---|---|---|---| | **P0-1** | **B-7** | ์ €์žฅ์†Œ ๋ฐ– ๊ธฐ๋™ ์‹œ ๋ฆฌ๋ทฐ์–ด๊ฐ€ ๋ฌธ์ž์—ด `"No git diff available"` ๋กœ `[VERDICT: PASS]` ๋ฅผ ๋ƒ„. ์‹ ๊ทœ(๋ฏธ์ถ”์ ) ํŒŒ์ผ์€ ๋ฆฌ๋ทฐ ๋Œ€์ƒ ๋ฐ–. **(โœ… ์™„๋ฃŒ โ€” tests/test_b7_diff_untracked.py 20/20 PASS)** | ์†Œ (1ํŒŒ์ผ) | โ€” | | **P0-2** | **O-2** | ๋งˆ์ปค๋ฅผ ์กฐ๊ฑด ์—†์ด ๋ฎ์–ด์“ฐ๊ณ  ์ข…๋ฃŒ ํŠธ๋žฉ์ด **ํƒ€ ์ธ์Šคํ„ด์Šค์˜ ๋งˆ์ปค๊นŒ์ง€ ์‚ญ์ œ** โ†’ ์™„๋ฃŒ ์ฒ˜๋ฆฌ๋œ **O-3 ๊ฐ€๋“œ๊ฐ€ ์กฐ์šฉํžˆ ๋ฌด๋ ฅํ™”**๋จ **(โœ… ์™„๋ฃŒ โ€” tests/test_o2_race_free_lock.py 22/22 PASS)** | ์†Œ~์ค‘ (1ํŒŒ์ผ) | โ€” | | **P1-1** | **A-4 M0~M1** | `PYTHONPATH` ๋ถ€ํŠธ์ŠคํŠธ๋žฉยท๋ฐฐํฌ/CI ๋“ฑ๋กยท`own_key` ์ด๊ด€. B-8/B-10/C-3b ๋กœ์ง์„ ์‹ธ๊ฒŒ ๋งŒ๋“ฆ | ์ค‘ | B-7 | | **P1-2** | **B-8** | agy ์ฃผ์ž…์ด ๊ฒ€์ฆ ์—†์ด `return 0` โ†’ ์•„๋ฌด๊ฒƒ๋„ ์ „๋‹ฌ๋˜์ง€ ์•Š์€ ์žก์ด `started` ๋กœ ๊ธฐ๋ก๋จ. A-4 M0(`_pane_capture` ๋””์ฝ”๋”ฉ) ์ดํ›„์—” **ํšŒํ”ผ์ฑ… ์ œ๊ฑฐ**๋กœ ์ถ•์†Œ | ์†Œ | A-4 M0 | | **P2-1** | **B-6** | ๋ฒ„์ „ ๊ด€๋ฆฌ ํŠธ๋ฆฌ ์˜ค์—ผ + rsync ๋ฐฐํฌ ์œ ์ถœ. `mktemp -d` ๋กœ ์˜ฎ๊ธฐ๋Š” 1~2์ค„ | ์†Œ | โ€” | | **P2-2** | **C-3a + C-4** | ๋นˆ ์Šคํ… 4์ข… + ์ด๋ฅผ ๊ณ ์ •ํ•˜๋˜ **๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 5๊ฑด** + ์ฃฝ์€ ์‹ฌ๋ณผ 3์ข… ์ œ๊ฑฐ (ํšŒ๊ท€ ์‹œ๊ฐ„ ๋‹จ์ถ• ํšจ๊ณผ) | ์†Œ | โ€” | | **P2-3** | **C-6** | ๋„์›€๋ง 3์ค„ ์ •์ • | ๊ทน์†Œ | โ€” | | **P3-1** | **A-4 M2~M7** | ์–ด๋Œ‘ํ„ฐ ๋ณธ์ด๊ด€. ์ง„ํ–‰ ์ค‘ **B-10 ยท C-3b ์ฒ˜๋ถ„ ๊ฒฐ์ •** | ๋Œ€ | P1-1 | | **P3-2** | **B-10** | tier-3 ์‹ ์› ์บ์‹œ ์กด์น˜/์ œ๊ฑฐ ๊ฒฐ์ • + PyYAML ์˜์กด ์™„ํ™” | ์ค‘ | A-4 M2 | | **P3-3** | **C-3b** | `isolation.root` ์†Œ๋น„์ž ์ฒ˜๋ถ„ ๊ฒฐ์ • | ์†Œ | A-4 M2 | | **P4-1** | **B-9** | ๊ธฐ๋ณธ๊ฐ’ ํ•œ์ •. `logs_dir` ์ธ์žยท`DELEGATE_JOB_LOGS_DIR` ๋‘ ๊ฐ€์ง€ ํšŒํ”ผ ์ˆ˜๋‹จ ์กด์žฌ | ๊ทน์†Œ | โ€” | | **P5-1** | **A-2** | ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค ๋ฐ HMAC ๊ฒ€์ฆ ๋ณด์™„ (๐Ÿ“Œ *์‚ฌ์šฉ์ž ์ง€์นจ: ์ฐจํ›„ ์ „์šฉ MQTT ๋ธŒ๋กœ์ปค ์„œ๋น™ ํ™˜๊ฒฝ ๊ตฌ์ถ• ์‹œ์ ์— ์ง„ํ–‰*) | ์ค‘ (3ํŒŒ์ผ) | ์ „์šฉ ๋ธŒ๋กœ์ปค | | **์ข…๊ฒฐ ๊ถŒ๊ณ ** | **B-5** | ํด๋ฐฑ(`df -P`)์œผ๋กœ ์ด๋ฏธ ํ•ด์†Œ โ€” ์„œ์ˆ ๋œ ์‹คํŒจ๊ฐ€ ์žฌํ˜„๋˜์ง€ ์•Š์Œ | โ€” | โ€” | **A-2 ๊ณผ์ œ์˜ ํ›„์ˆœ์œ„ ๋ฐฐ์น˜ ์‚ฌ์œ **: ์‚ฌ์šฉ์ž ์ง€์นจ์— ๋”ฐ๋ผ ์ฐจํ›„ ์ž์ฒด ์ „์šฉ MQTT ๋ธŒ๋กœ์ปค ์„œ๋น™ ํ™˜๊ฒฝ ๊ตฌ์ถ• ์‹œ์ ์— ๋งž์ถฐ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด **์ตœํ•˜์œ„(P5-1)**๋กœ ๋ฐฐ์น˜ํ•˜์˜€์Šต๋‹ˆ๋‹ค. **์ •๋ฆฌ(C ๊ณ„์—ด)๋ฅผ P2 ์— ๋‘๋Š” ์ด์œ **: (a) C-3a ๋Š” ๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 5๊ฑด์„ ํ•จ๊ป˜ ์ œ๊ฑฐํ•ด ์ดํ›„ ๋ชจ๋“  ์ „์ฒด ํšŒ๊ท€๋ฅผ ๋‹จ์ถ•ํ•˜๊ณ , (b) C-4 ๋Š” **์ž˜๋ชป ์‹คํ–‰ํ•˜๋ฉด ๋ฒ„๊ทธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค**. ๋ฐฉ์น˜ํ• ์ˆ˜๋ก ๋ˆ„๊ตฐ๊ฐ€ "์‰ฌ์šด ์ •๋ฆฌ"๋กœ ์ง‘์–ด ๋“ค ํ™•๋ฅ ์ด ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค. ### 6.3 ๋ณ‘๋ ฌ ์‹คํ–‰ โ€” ํŒŒ์ผ ์†Œ์œ ๊ถŒ ์Šฌ๋กฏ (Rev.2 ๊ต์ฒด) > Rev.1 ์€ "์ฃผ์ œ๋ณ„ ํŠธ๋ž™"์œผ๋กœ ๋ณ‘๋ ฌํ™”๋ฅผ ์„œ์ˆ ํ–ˆ๊ณ  **๊ทธ ๋ถ„ํ•ด๋Š” 4๊ณณ์—์„œ ํ‹€๋ ธ์Šต๋‹ˆ๋‹ค**(์ฑŒ๋ฆฐ์ง€ `7d604ee7` ๊ณ„๊ธฐ๋กœ ํŒŒ์ผ ๋‹จ์œ„ ์žฌ๋Œ€์กฐ). ๋ณ‘๋ ฌ ๋‹จ์œ„๋Š” **์ฃผ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ํŒŒ์ผ**์ž…๋‹ˆ๋‹ค. **ํ•ญ๋ชฉ๋ณ„ ์ฒ˜๋ฐฉ์ด ๊ฑด๋“œ๋ฆฌ๋Š” ํŒŒ์ผ** | ํŒŒ์ผ | ๊ฑด๋“œ๋ฆฌ๋Š” ํ•ญ๋ชฉ | |---|---| | `run_loop.sh` | **B-6, B-7, O-2** | | `lib.sh` | **A-4, B-8, B-10, C-3a, C-4** | | `reconcile.sh` | **A-2, A-4, B-10** | | `mqtt_common.py` | **A-2, B-9** | | `stop_session.sh` | **B-10, C-6** | | `registry.py` | **A-2, C-4** | | `create_session.sh` | **A-4, C-4** | **์Šฌ๋กฏ ๋ฐฐ์น˜ โ€” ์Šฌ๋กฏ ์•ˆ์€ ์ง๋ ฌ, ์Šฌ๋กฏ ๊ฐ„์€ ๋ณ‘๋ ฌ** | ์Šฌ๋กฏ | ์ˆœ์„œ | |---|---| | **`run_loop.sh`** | `B-7` โ†’ `O-2` โ†’ `B-6` | | **`lib.sh`** | `C-3a`+`C-4` โ†’ `B-8` | | **MQTT ๊ณ„์—ด** (`mqtt_common.py`ยท`registry.py`ยท`publish_event.py`ยท`job_subscriber.py`ยท`reconcile.sh`) | `A-2` โ†’ `B-9` | | **`stop_session.sh`** | `C-6` | | **๋‹จ๋… ์‹คํ–‰** (์Šฌ๋กฏ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์Œ) | `A-4`, `B-10` | - `A-4`(`lib.sh`+`reconcile.sh`+`create_session.sh`+`resume_session.sh`)์™€ `B-10`(`lib.sh`+`reconcile.sh`+`stop_session.sh`)์€ **์–ด๋–ค ์Šฌ๋กฏ ์กฐํ•ฉ๊ณผ๋„ ๊ฒน์น˜๋ฏ€๋กœ ๋‹จ๋… ์‹คํ–‰**ํ•ฉ๋‹ˆ๋‹ค. - `A-4` ๋Š” ์‹ ๊ทœ ํŒŒ์ผ์„ ๋Œ€๋Ÿ‰ ์ถ”๊ฐ€ํ•˜๋ฏ€๋กœ **B-7 ์ด ๋จผ์ € ๋‹ซํ˜€ ์žˆ์–ด์•ผ ๋ฆฌ๋ทฐ๊ฐ€ ์„ฑ๋ฆฝ**ํ•ฉ๋‹ˆ๋‹ค. - **Rev.1 ์˜ค๋ฅ˜ ์ •์ • 4๊ฑด**: `B-6`(ํŠธ๋ž™ Cโ†’`run_loop.sh` ์Šฌ๋กฏ), `C-3a`ยท`C-4`(ํŠธ๋ž™ Cโ†’`lib.sh` ์Šฌ๋กฏ), `B-9`(๋…๋ฆฝโ†’MQTT ์Šฌ๋กฏ), `C-6`(๋…๋ฆฝโ†’`stop_session.sh` ์Šฌ๋กฏ). - ์ฐธ๊ณ : `reconcile.sh` ๋Š” `MAM_LOOP_MARKER`ยท`send_keys_safe` ๋ฅผ **์ฐธ์กฐ 0๊ฑด**์ด๋ฏ€๋กœ `O-2`ยท`B-8` ๊ณผ๋Š” ๊ฒฝํ•ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ž์ฒด `.mam/monitor.lock` ๋ณด์œ ). ### 6.4 B-7 ์ฒ˜๋ฐฉ (Rev.2 ์‹ ์„ค โ€” ์ง„๋‹จ๋งŒ ์žˆ๊ณ  ์ฒ˜๋ฐฉ์ด ์—†์—ˆ์Œ) `cd "$REPO_ROOT"` ๋งŒ์œผ๋กœ๋Š” **๋ฏธ์ถ”์  ์‹ ๊ทœ ํŒŒ์ผ์ด ์—ฌ์ „ํžˆ 100% ๋ˆ„๋ฝ**๋ฉ๋‹ˆ๋‹ค. `git diff` ๋Š” ์ •์˜์ƒ ์ถ”์  ํŒŒ์ผ๋งŒ ๋ด…๋‹ˆ๋‹ค. ```bash CHANGES_DIFF=$( cd "$REPO_ROOT" || exit 1 git diff "$BASE_COMMIT" # ๋ฏธ์ถ”์  ์‹ ๊ทœ ํŒŒ์ผ์„ ์ธ๋ฑ์Šค ๋ณ€๊ฒฝ ์—†์ด ๋ง๋ถ™์ธ๋‹ค. # --exclude-standard ๊ฐ€ .gitignore / .git/info/exclude ๋ฅผ ๊ทธ๋Œ€๋กœ ์กด์ค‘ํ•œ๋‹ค. git ls-files -o --exclude-standard -z | while IFS= read -r -d '' f; do git diff --no-index --binary /dev/null "$f" 2>/dev/null || true done ) ``` **`git add -N .` ์€ ์ฑ„ํƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.** ๋ฏธ์ถ”์  ํŒŒ์ผ์„ diff ์— ๋„ฃ๋Š” ๋ชฉ์ ์€ ๋‹ฌ์„ฑํ•˜์ง€๋งŒ(์‹ค์ธก ํ™•์ธ) **์ธ๋ฑ์Šค์— `A` ํ•ญ๋ชฉ์„ ๋‚จ๊ธฐ๋ฉฐ**, ๊ทธ ์ƒํƒœ์—์„œ Creator ๊ฐ€ `git commit -am` ์„ ์‹คํ–‰ํ•˜๋ฉด **์ถ”๊ฐ€ํ•œ ์  ์—†๋Š” ํŒŒ์ผ์ด ๋‚ด์šฉ์งธ ์ปค๋ฐ‹๋ฉ๋‹ˆ๋‹ค**(์‹ค์ธก ํ™•์ธ). `run_loop.sh` ๋Š” Creator ๊ฐ€ ๊ฐ™์€ ์ €์žฅ์†Œ์—์„œ ์ž‘์—…ํ•˜๋Š” ๋™์•ˆ ๋ฐ˜๋ณต ์‹คํ–‰๋˜๋ฏ€๋กœ ์‹ค์ œ ์œ„ํ—˜์ž…๋‹ˆ๋‹ค. ์œ„ ๋Œ€์•ˆ์€ ๋™์ผ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋ฉด์„œ ์ธ๋ฑ์Šค๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. **ํฌ๊ธฐ ์ƒํ•œ๋„ ํ•จ๊ป˜ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.** ํ˜„์žฌ `CHANGES_DIFF`(537ยท539ํ–‰)๋Š” **์•„๋ฌด ์ œํ•œ ์—†์ด** 547ํ–‰ ๋ฆฌ๋ทฐ ํ”„๋กฌํ”„ํŠธ์— ๋ณด๊ฐ„๋˜๊ณ  `send_keys_safe` paste-buffer ๋กœ ์ฃผ์ž…๋ฉ๋‹ˆ๋‹ค. ๋ฏธ์ถ”์  ํŒŒ์ผ์„ ํฌํ•จ์‹œํ‚ค๋ฉด ์ปค์ง€๊ธฐ๋งŒ ํ•˜๋ฏ€๋กœ ์ƒํ•œ์„ ๋‘๊ณ , ์ดˆ๊ณผ ์‹œ `--stat` ์š”์•ฝ์œผ๋กœ ๋Œ€์ฒดํ•˜๋˜ **์ž˜๋ ธ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ฆฌ๋ทฐ์–ด์—๊ฒŒ ๋ฐ˜๋“œ์‹œ ๋…ธ์ถœ**ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์กฐ์šฉํžˆ ์ž๋ฅด๋ฉด "๋นˆ diff PASS" ๊ฐ€ "๋ถ€๋ถ„ diff PASS" ๋กœ ๋ฐ”๋€” ๋ฟ์ž…๋‹ˆ๋‹ค). ๊ตฌ์ฒด์  ์ž„๊ณ„๊ฐ’์€ ๊ตฌํ˜„์ž๊ฐ€ ์ƒŒ๋“œ๋ฐ•์Šค ์„ธ์…˜์—์„œ paste-buffer ์‹คํŒจ ์ง€์ ์„ ์ธก์ •ํ•ด ํ™•์ •ํ•  ๊ฒƒ. ### 6.5 โš ๏ธ ์‹คํ–‰ ์ „ ๋ฐ˜๋“œ์‹œ ํ™•์ธํ•  ์ •์ • ์‚ฌํ•ญ 1. **C-3 ์€ ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋ฉด ํšŒ๊ท€๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.** ํ•ญ๋ชฉ์ด ์„ฑ๊ฒฉ์ด ๋‹ค๋ฅธ ๋‘˜์„ ๋ฌถ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. - **C-3a (์ฆ‰์‹œ ์‹คํ–‰ ๊ฐ€๋Šฅ)**: `provision_isolation` / `isolation_lever` / `isolation_env_prefix` / `isolation_cmd_args` 4์ข… ๋นˆ ์Šคํ… โ€” ํ”„๋กœ๋•์…˜ ํ˜ธ์ถœ์ž 0๊ฑด. ์ด๋ฅผ ๊ณ ์ •ํ•˜๋˜ `tests/test_tier1_unit.py` 3๊ฑด + `tests/test_tier2_component.py` 1๊ฑด๋„ ํ•จ๊ป˜ ์ œ๊ฑฐ ๋Œ€์ƒ. - **C-3b (๋ณด๋ฅ˜ โ€” A-4 M2 ๊ฒฐ์ • ์‚ฌํ•ญ)**: `isolation.root` ์†Œ๋น„์ž(`lib.sh` `verify_session_uuid` ์˜ `iso_root` ๋ถ„๊ธฐ, `mam_session_iso_root`, `find_workspace_uuid` ๊ฒฉ๋ฆฌ ๋ถ„๊ธฐ, `stop_session.sh:277` purge ๊ฐ€๋“œ). **b4a1d094 / 44062a63 ์—์„œ ๋ฐฉ๊ธˆ ์˜๋„์ ์œผ๋กœ ๋˜์‚ด๋ฆฐ ์ฝ”๋“œ**์ด๋ฉฐ, ์ง€์šฐ๋ฉด ๊ทธ ์ˆ˜์ •์ด ๋˜๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค. 2. **C-4 ์˜ "7์ข…" ์ค‘ 2์ข…์€ ์‚ฌ์‹ค๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.** - `_HERDR_SHIM_DIR_PATTERN` โ€” **์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค** (`lib.sh:57` ์ •์˜, `lib.sh:79` ์‚ฌ์šฉ). ๋ชฉ๋ก๋Œ€๋กœ ์ง€์šฐ๋ฉด shim ๊ฒฝ๋กœ ํŒ์ •์ด ๊นจ์ง‘๋‹ˆ๋‹ค. - `local_herdr` โ€” ์ฐธ์กฐ 0๊ฑด, **์ด๋ฏธ ์ œ๊ฑฐ๋จ**. - ์‹ค์ œ ๋Œ€์ƒ์€ `_REAL_HERDR_PATH`, `TERMINAL_STATUSES`, `ISOLATE` 3์ข…์ด๋ฉฐ `provision_isolation` ์€ C-3a ์™€ ์ค‘๋ณต์ž…๋‹ˆ๋‹ค. 3. **A-2 ์˜ ์›์ธ ํ‘œํ˜„ ์ •์ •** โ€” `verify_hmac` ๊ตฌํ˜„ ์ž์ฒด๋Š” ์ •์ƒ์ž…๋‹ˆ๋‹ค(ํ† ํฐ์ด ์žˆ์œผ๋ฉด `hmac.compare_digest` ๋กœ ๊ฒ€์ฆ). ์›์ธ์€ **ํ† ํฐ์ด ์•„๋ฌด ๋ฐ์„œ๋„ ๋ฐœ๊ธ‰๋˜์ง€ ์•Š์•„ ๊ฒ€์ฆ์ด ๊ณตํ—ˆํ•ด์ง€๋Š” ๊ฒƒ** + ๋ฐœํ–‰์ž๊ฐ€ ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ง€๋ฌธ ํ† ํ”ฝ์„ ์ฑ„ํƒํ•˜์ง€ ์•Š์€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ˆ˜์ •์€ โ‘  ๋ฐœํ–‰์ž ํ† ํ”ฝ ๊ต์ฒด โ‘ก `reconcile.sh:237` ๋ ˆ๊ฑฐ์‹œ ์ „์—ญ ๊ตฌ๋… ์ œ๊ฑฐ โ‘ข `verify_hmac` fail-closed + ํ† ํฐ ๋ฐœ๊ธ‰ ์ˆœ์ž…๋‹ˆ๋‹ค. 4. **B-5 ์ž”์—ฌ๋ถ„** โ€” ํด๋ฐฑ์œผ๋กœ ๊ฐ์ง€๋Š” ์ •์ƒํ™”๋์œผ๋‚˜ `mount | grep -E "$mountpoint.*(nfs|...)"` ๊ฐ€ ๋งˆ์šดํŠธํฌ์ธํŠธ๋ฅผ **์ด์Šค์ผ€์ดํ”„ ์—†์ด ERE ์— ๋ณด๊ฐ„**ํ•ฉ๋‹ˆ๋‹ค(๊ฒฝ๋กœ์˜ `.` ์ด ์ž„์˜ ๋ฌธ์ž๋กœ ํ•ด์„). ์ด๊ฒƒ๋งŒ ์‹ ๊ทœ ํ•ญ๋ชฉ(B-11)์œผ๋กœ ๋ถ„๋ฆฌ ๊ถŒ๊ณ . ### 6.6 ๊ฒฐ๋ก  `IMPROVEMENTS.md` ๋Š” ๋‚จ์€ ๋ฐฑ๋กœ๊ทธ ํ•ญ๋ชฉ(์•„ํ‚คํ…์ฒ˜ 2๊ฑด, ์—ฃ์ง€์ผ€์ด์Šค 6๊ฑด, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ 1๊ฑด, ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ 3๊ฑด โ€” ์ด 12๊ฑด)์„ ์œ„ ์šฐ์„ ์ˆœ์œ„์— ๋”ฐ๋ผ ์ผ์›ํ™”๋œ ๋ณด์™„ ๋กœ๋“œ๋งต์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.