# ๐Ÿ› ๏ธ Multi-Agent Mux ์ข…ํ•ฉ ๊ฐœ์„  ๋ฐ ๋ฏธํ•ด๊ฒฐ ๊ณผ์ œ ๋ฐฑ๋กœ๊ทธ (`IMPROVEMENTS.md`) - **์ตœ์ข… ๊ฐฑ์‹ ์ผ**: 2026-08-24 (`nats-docker` ์„œ๋ธŒ๋ชจ๋“ˆ ๋ถ„๋ฆฌ, B-20 2ร—K ๊ทธ๋ฆฌ๋“œ TUI ๋ ˆ์ด์•„์›ƒ ์—”์ง„, J-1/J-2 ๋ ˆ์ด์•„์›ƒ ํ™˜๊ฒฝ๋ณ€์ˆ˜/์ž„๊ณ„๊ฐ’ ๋ณด๊ฐ•, B-21 `--agent` ํ‘œ์ค€ํ™” ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ agent_of_row ํด๋ฐฑ ํ†ตํ•ฉ ์™„๋ฃŒ) - **ํ†ตํ•ฉ ๊ด€๋ฆฌ ๋Œ€์ƒ**: ๊ธฐ์กด `CODEBASE_REVIEW_REPORT.md` + `OPTIMIZATION.md` + `NATS_REPORT.md` - **์ด ์ถ”์  ๋ฏธํ•ด๊ฒฐ ๊ณผ์ œ**: **5๊ฑด** (์•„ํ‚คํ…์ฒ˜ 1๊ฑด: `A-2`, ์—ฃ์ง€์ผ€์ด์Šค ๋ฐ ๊ฐ€์šฉ์„ฑ 3๊ฑด: `B-16`, `B-17`, `B-18`, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ 1๊ฑด: `O-5`) - **์™„๋ฃŒ๋œ ๊ณผ์ œ**: **30๊ฑด** (A-1, A-3, A-4, A-5, B-1, B-3, B-4, B-5, B-7, B-8, B-9, B-10, B-13, B-14, B-15, B-19, B-20, B-21, C-1, C-2, C-3b, C-6, O-1, O-2, O-3, O-4-OrcOnboard, O-6, Herdr-0.8.0-Compat-SanitizeHash, P2-1-DelegateJobSafe-TrapFix, P2-2-C3a-C4-LegacyCleanup) --- ## ๐Ÿ“Œ ๊ฐœ์š” ๋ณธ ๋ฌธ์„œ๋Š” Multi-Agent Mux (MAM) ํ”„๋ ˆ์ž„์›Œํฌ์˜ **์ฝ”๋“œ๋ฒ ์ด์Šค ์•„ํ‚คํ…์ฒ˜ ๊ฒฐํ•จ, ๋Ÿฐํƒ€์ž„ ์—ฃ์ง€์ผ€์ด์Šค, ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ** ๋ฐ **`/multi-agent-mux-loop` ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์ตœ์ ํ™” ๊ณผ์ œ**๋ฅผ ๋‹จ์ผ ๋ฐฑ๋กœ๊ทธ๋กœ ํ†ตํ•ฉ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•œ ์ข…ํ•ฉ ๊ด€๋ฆฌ ๋ฌธ์„œ์ž…๋‹ˆ๋‹ค. --- ## 1. ๐Ÿ”ด ์•„ํ‚คํ…์ฒ˜ ๊ฒฐํ•จ (Architecture Flaws โ€” 1๊ฑด) ### **A-2 (P5-1): ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค + HMAC ์ธ์ฆ Off + ์™€์ผ๋“œ์นด๋“œ ์ „ํŒŒ (ํ•ด๊ฒฐ์ฑ…: `nats-server` ์ „์šฉ ๋ธŒ๋กœ์ปค ์ฑ„ํƒ)** - **ํ˜„์ƒ**: `mqtt_common.py`์˜ ๊ธฐ๋ณธ ๋ธŒ๋กœ์ปค๊ฐ€ ๊ณต๊ฐœ ์„œ๋ฒ„(`broker.hivemq.com`)์ด๊ณ , ์žก ์ƒ์„ฑ ์‹œ `auth_token`์ด ๋ฐœ๊ธ‰๋˜์ง€ ์•Š๋Š” ์กฐ๊ฑด ๋ถ„๊ธฐ(ํ‰๋ฌธ/๊ณต๊ฐœ ๋ธŒ๋กœ์ปค)๋กœ ์ธํ•ด `verify_hmac`์˜ `if not auth_token: return True` ๊ฒฝ๋กœ๊ฐ€ ํƒ€์ง‘๋‹ˆ๋‹ค. ๋ฐœํ–‰์ž๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ง€๋ฌธ ํ† ํ”ฝ์„ ์ฑ„ํƒํ•˜์ง€ ์•Š๊ณ  ์ „์—ญ `python/mqtt/jobs//events`๋กœ ๋ฐœํ–‰ํ•˜๋ฉฐ, `reconcile.sh:237`์ด ๊ฐ™์€ ์ „์—ญ ํ† ํ”ฝ์„ ๊ตฌ๋…ํ•ฉ๋‹ˆ๋‹ค. - **ํŒŒ๊ธ‰ ํšจ๊ณผ**: ์™ธ๋ถ€์—์„œ ์œ ์ž…๋˜๋Š” malicious `error` ์ด๋ฒคํŠธ ์ˆ˜์‹  ์‹œ `reconcile.sh`๊ฐ€ ๋ผ์ด๋ธŒ ์—์ด์ „ํŠธ pane์„ `kill-session`์œผ๋กœ ๊ฐ•์ œ ํŒŒ๊ดดํ•˜๋Š” ์น˜๋ช…์  ๋ณด์•ˆ/์•ˆ์ •์„ฑ ์œ„ํ—˜์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. - **์ตœ์‹  ์‹ค์ธก ๋ฐ ํ•ด๊ฒฐ ๋ฐฉ์นจ (`NATS_REPORT.md` ํ™•์ •)**: - ํด๋ผ์ด์–ธํŠธ ํ”„๋กœํ† ์ฝœ(`paho-mqtt`)์„ ๋น„๋™๊ธฐ `nats-py`๋กœ ์ „๋ฉด ์žฌ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ์•ˆ(Option B)์€ 46๊ฐœ ํ…Œ์ŠคํŠธ ํŒŒ๊ดด ๋ฐ ๋‹จ๋ช… ๋™๊ธฐ CLI ๋งˆ์ฐฐ ์œ„ํ—˜์œผ๋กœ **๋งŒ์žฅ์ผ์น˜ ๊ธฐ๊ฐ**๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - ๋Œ€์‹  **`nats-server`์˜ ๋‚ด์žฅ MQTT 3.1.1 ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ „์šฉ ์‚ฌ์„ค ๋ธŒ๋กœ์ปค๋กœ ์ฑ„ํƒ(Option C)**ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ 0์ค„ ๋ณ€๊ฒฝ์œผ๋กœ NKey/JWT ๊ณ„์ •ยทSubject๋ณ„ ACL ๊ฒฉ๋ฆฌ ๋ฐ JetStream ์˜์†์„ฑ์„ 100% ํ™•๋ณดํ•˜๊ธฐ๋กœ ํ™•์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋‹จ, ๋ธŒ๋กœ์ปค ์ œํ’ˆ๊ณผ ๋ฌด๊ด€ํ•˜๊ฒŒ ์กด์žฌํ•˜๋Š” **๊ฐ€์šฉ์„ฑ ์„ ํ–‰ ๊ฒฐํ•จ(Track 0: B-14, B-15)**์„ ๋จผ์ € ๊ต์ •ํ•œ ํ›„ Track 1(์ŠคํŒŒ์ดํฌ) ๋ฐ Track 2(A-2 ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ง€๋ฌธ ํ† ํ”ฝ + ๋ฌด์กฐ๊ฑด ํ† ํฐ ๋ฐœ๊ธ‰)๋ฅผ ์ˆœ์ฐจ ์ „๊ฐœํ•ฉ๋‹ˆ๋‹ค. --- ## 2. ๐ŸŸ  ์—ฃ์ง€ ์ผ€์ด์Šค ๋ฐ ๋Ÿฐํƒ€์ž„ ๋ฒ„๊ทธ (Edge-case Bugs โ€” 6๊ฑด / ์™„๋ฃŒ 5๊ฑด) ### **B-21 (โœ… ์™„๋ฃŒ โ€” `--agent` ํ”Œ๋ž˜๊ทธ ํ‘œ์ค€ํ™” ๋ฐ `stop_session.sh`/`update_yaml_resumed.sh` ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ `agent_of_row` ํด๋ฐฑ ํ†ตํ•ฉ)** - **ํ˜„์ƒ**: - `stop_session.sh` ๋ฐ `update_yaml_resumed.sh`๊ฐ€ `--agent` ์ƒ๋žต ์‹œ ์„ธ์…˜๋ช… ์ ‘๋ฏธ์‚ฌ regex์—๋งŒ ์˜์กดํ•˜์—ฌ, ๋ผ์ด๋ธŒ ์„ธ์…˜์ธ `agy-creator-01` ๋“ฑ ์œ ํšจํ•˜๊ฒŒ ์‹คํ–‰ ์ค‘์ธ ์„ธ์…˜์ด `exit 2`๋กœ ๊ฑฐ๋ถ€๋˜๋˜ ๊ฒฐํ•จ. - ์—์ด์ „ํŠธ ํ•ด์„๊ธฐ๊ฐ€ 4์ค‘ํ™”(`registry.py`, `stop_session.sh`, `update_yaml_resumed.sh`, `run_loop.sh`)๋˜์–ด ์ผ๊ด€์„ฑ์ด ๊ฒฐ์—ฌ๋จ. - ๊ฐ€์ด๋“œ ๋ฌธ์„œ(SKILL.md) ์˜ˆ์ œ ๋ฐ ์Šคํฌ๋ฆฝํŠธ ํ—ค๋”์—์„œ `--agent` ์ „๋‹ฌ์ด ๋ˆ„๋ฝ๋˜๊ฑฐ๋‚˜ ์—์ด์ „ํŠธ ํƒ€์ž…(4์ข…: `claude|agy|hermes|cline`)์ด ๋ถˆ์ผ์น˜ํ•จ. - **์กฐ์น˜ ๊ฒฐ๊ณผ (์™„๋ฃŒ)**: - `lib.sh`์— `resolve_agent_type_from_registry()` ๊ณต์šฉ ํ—ฌํผ ์‹ ์„ค: `agent_of_row` ์šฐ์„ ์ˆœ์œ„(โ‘  `row['agent']` โ†’ โ‘ก ์ด๋ฆ„ ์ ‘๋ฏธ์‚ฌ โ†’ โ‘ข `pane.cmd`)๋ฅผ ์—„๊ฒฉํžˆ ์ค€์ˆ˜ํ•˜์—ฌ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๊ธฐ๋ฐ˜ ํ•ด์„ ์ง€์›. - `stop_session.sh` ๋ฐ `update_yaml_resumed.sh`์˜ ์ ‘๋ฏธ์‚ฌ ์ „์šฉ case ๋ธ”๋ก์„ ๊ณต์šฉ ํ—ฌํผ๋กœ ๊ต์ฒดํ•˜๊ณ , ๋ฏธํ•ด์„ ์‹œ ๊ธฐ์กด `exit 2` ๊ณ„์•ฝ ๋ฐ ํ—ค๋”/usage ๋ฌธ์„œ ๋™๊ธฐํ™”. - `stop_session.sh`, `create_session.sh`, `resume_session.sh`์˜ ์‚ฌ์žฅ๋œ `lib.sh` ์†Œ์‹ฑ ๊ฒฝ๋กœ(`cd ... 2>/dev/null || pwd`) ๋ณต๊ตฌ. - `lib_py/layout.py`: `_env_int(*names, default=None)` ํ—ฌํผ๋กœ ๋ฆฌํŒฉํ„ฐํ•˜์—ฌ `MAM_MIN_PANE_COLS=0` ๋“ฑ falsy-zero ๋ฒ„๊ทธ(J-1)๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ , ์ž˜๋ชป๋œ ๋ณ„์นญ ์ž…๋ ฅ ์‹œ ํ›„์† ์œ ํšจ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ fallback ํ•˜๋„๋ก `continue` ์ฒ˜๋ฆฌ(C-2). - `multi-agent-mux-stop`, `multi-agent-mux-resume`, `multi-agent-mux-create`์˜ SKILL.md ๋ฐ ์Šคํฌ๋ฆฝํŠธ ํ—ค๋”๋ฅผ 4๊ฐœ ์—์ด์ „ํŠธ ๋ช…์‹œ ํ‘œ์ค€์œผ๋กœ ๋™๊ธฐํ™”. - **ํšŒ๊ท€ ๊ฐ€๋“œ**: - `tests/test_layout.py` (J-1 zero min-cols/min-rows ๋ฐ C-2 ๋ฌดํšจ๊ฐ’ fallback ํ…Œ์ŠคํŠธ 4๊ฑด, J-2 n=5 ์ž„๊ณ„๊ฐ’ ๋ณด๊ฐ• 1๊ฑด), `tests/test_a4_adapter_contract.py` (T3 1๊ฑด), `tests/test_tier2_component.py` (T4 fallback/priority 2๊ฑด, T5 ํŽœ์Šค+๋ช…๋ น ๋‹จ์œ„ ๋ฌธ์„œ ๊ฐ€๋“œ 1๊ฑด). ### **B-20 (โœ… ์™„๋ฃŒ โ€” 2ร—K ๊ทธ๋ฆฌ๋“œ TUI ๋ ˆ์ด์•„์›ƒ ์—”์ง„ `lib_py/layout.py` ๊ณต์šฉํ™” ๋ฐ `lib.sh` ์ธ๋ผ์ธ ๋ ˆ๊ฑฐ์‹œ ์ •๋ฆฌ)** - **ํ˜„์ƒ**: - ๊ธฐ์กด `lib.sh`์— ~30์ค„ ์ด์ƒ์˜ ์ธ๋ผ์ธ Python ๊ณ„์‚ฐ ์Šค๋‹ˆํŽซ์ด ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์–ด, ํ—ค๋“œ๋ฆฌ์Šค ๋ชจ๋“œ ๋ฐ ์—์ด์ „ํŠธ ์ˆ˜ ์ฆ๊ฐ€์— ๋”ฐ๋ฅธ ํŒจ๋„ ๋ฐฐ์น˜๊ฐ€ ๋น„๊ฒฐ์ •์ ์ด๊ณ  ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ–ˆ์Œ. - Herdr 0.8.0 CLI๊ฐ€ `left`/`up` ๋ฐฉํ–ฅ์„ ์ง€์›ํ•˜์ง€ ์•Š๊ณ  `right`/`down`๋งŒ ์ง€์›ํ•˜๋Š” ์ œ์•ฝ์— ๋ถ€ํ•ฉํ•˜๋Š” ๋ ˆ์ด์•„์›ƒ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๋ถ€์žฌ. - **์กฐ์น˜ ๊ฒฐ๊ณผ (์™„๋ฃŒ)**: - `.agents/skills/lib_py/layout.py` ๊ณต์šฉ ์—”์ง„ ์‹ ์„ค: ์˜ค๋ฅธ์ชฝ ํ™•์žฅ 2ร—K ๊ทธ๋ฆฌ๋“œ ์•Œ๊ณ ๋ฆฌ์ฆ˜, ํ•ด์ƒ๋„ ์˜ค๋ฒ„ํ”Œ๋กœ ๊ฐ€๋“œ(`min_cols=60`, `min_rows=20`), ํ—ค๋“œ๋ฆฌ์Šค 0ร—0 ๊ฒฐ์ •๋ก ์  ๋ถ„ํ•  ์ง€์›. - `lib.sh`: ์ธ๋ผ์ธ Python ์Šค๋‹ˆํŽซ์„ `python3 -m lib_py.layout` ๋‹จ์ผ ํ˜ธ์ถœ๋กœ ๊ต์ฒดํ•˜๊ณ  ๋ ˆ๊ฑฐ์‹œ ๋ณ€์ˆ˜/์ฃผ์„ ์ •๋ฆฌ. - ํ›„์† ์ •๋ฆฌ (I-2/I-3/C-1/J-1/J-2): `PaneInfo.focused` ๋ฏธ์‚ฌ์šฉ ํ•„๋“œ ์ •๋ฆฌ, `MAM_MAX_PANE_COLS`/`MAM_MAX_COLS` env ๋ฐฐ์„  ์™„๋ฃŒ, ํ—ค๋“œ๋ฆฌ์Šค ๋ชจ๋“œ์—์„œ `max_columns`๋ฅผ ์šฐํšŒํ•˜๋˜ ๊ฒฐํ•จ(C-1)์„ ๊ต์ •ํ•˜์—ฌ GUI์™€ ๋™์ผํ•œ `max_columns_reached` ์„ฑ์žฅ ๊ฐ€๋“œ ์ ์šฉ. `test_bug4_headless_unobservable_fast_path`์— 5.0์ดˆ ์ƒํ•œ ์‹œ๊ฐ„ ๋‹จ์–ธ์„ ๊ณ„์•ฝ์œผ๋กœ ๊ณ ์ •. `_env_int`์˜ falsy-zero trap(J-1) ๋ฐ ๋ฌดํšจ ๋ณ„์นญ skip(C-2) ํ•ด์†Œ, ํ—ค๋“œ๋ฆฌ์Šค n=5 ํ™€์ˆ˜ ์ž„๊ณ„๊ฐ’ ๊ฒ€์ฆ(J-2). - ํšŒ๊ท€ ๊ฐ€๋“œ: `tests/test_layout.py` (23๊ฐœ ํ…Œ์ŠคํŠธ 100% ํ†ต๊ณผ), `tests/test_b19_headless_reconcile_fixes.py` (6๊ฐœ ํ…Œ์ŠคํŠธ 100% ํ†ต๊ณผ). ### **B-19 (โœ… ์™„๋ฃŒ โ€” ํ—ค๋“œ๋ฆฌ์Šค ๋ถ„ํ•  ๋ ˆ์ด์•„์›ƒ 0ร—0 ์˜ˆ์™ธ ์ฒ˜๋ฆฌ, reconcile SKILLS_DIR ๋ˆ„๋ฝ ๋ฐ Fast-path ๊ฒŒ์ดํŒ… ๋ณด์™„)** - **ํ˜„์ƒ**: 1. `lib.sh` ํ—ค๋“œ๋ฆฌ์Šค ํ™˜๊ฒฝ์—์„œ `herdr pane layout`์ด `0ร—0`์„ ๋ฐ˜ํ™˜ํ•  ๋•Œ `overflow`๋กœ ์˜คํŒ์ •๋˜์–ด ์ƒˆ ์›Œํฌ์ŠคํŽ˜์ด์Šค(`w1, w2, w3`)๊ฐ€ ๊ณ„์† ์ฆ์‹ํ•˜๋˜ ๊ฒฐํ•จ (ํ›„์† B-20 2ร—K ๊ทธ๋ฆฌ๋“œ ์—”์ง„์œผ๋กœ ์™„์ „ ์Šน๊ณ„ ๋ฐ ๊ณต์šฉํ™”). 2. `reconcile.sh:19`์—์„œ `SKILLS_DIR` ๋ช…๋ น ์น˜ํ™˜ ์˜ค๋ฅ˜(`2>/dev/null || pwd`)๋กœ ๋นˆ ๋ฌธ์ž์—ด์ด ๋˜์–ด Python ๋‚ด ์ƒ๋Œ€ ๊ฒฝ๋กœ ์กฐ๋ฆฝ ์‹คํŒจ(`resume dry-run failed: No such file or directory`)๊ฐ€ ์œ ๋ฐœ๋˜๋˜ ๊ฒฐํ•จ. 3. `lib.sh:1620` `send_keys_safe`์—์„œ `herdr agent prompt` Fast-path๊ฐ€ ๋‹ค์ด์–ผ๋กœ๊ทธ ์ฒดํฌ ์—†์ด ์‹คํ–‰๋˜๊ฑฐ๋‚˜ ํ—ค๋“œ๋ฆฌ์Šค/๋น„ํ‘œ์‹œ ์ƒํƒœ์—์„œ ์ •์ˆ™์„ฑ ๋ฃจํ”„๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ 10์ดˆ ๋Œ€๊ธฐ/์‹คํŒจํ•˜๋˜ ๊ฒฐํ•จ. - **์กฐ์น˜ ๊ฒฐ๊ณผ (์™„๋ฃŒ)**: - `lib.sh`: B-20 ๊ณต์šฉ ์—”์ง„์„ ํ†ตํ•ด ํ—ค๋“œ๋ฆฌ์Šค 0ร—0 ๊ฒฐ์ •๋ก ์  ๋ถ„ํ•  ์ ์šฉ. `_pane_quiescent`์— `SKS_EMPTY_GIVEUP`(๊ธฐ๋ณธ 3ํšŒ) ์—ฐ์† ๊ณต๋ฐฑ ๊ฐ์ง€ ์‹œ ์กฐ๊ธฐ `rc=2`(๊ด€์ธก ๋ถˆ๊ฐ€, ~1.5์ดˆ ์†Œ์š”) ํƒˆ์ถœ์„ ๋„์ž…ํ•˜๊ณ , ๊ด€์ธก ๊ฐ€๋Šฅํ•œ ํŽ˜์ธ์€ 20ร—0.5s(10์ดˆ) ์ •์ˆ™์„ฑ ์œˆ๋„๋ฅผ ๋ณด์กด. `send_keys_safe`๊ฐ€ `rc=2`์ผ ๋•Œ ์‹œ๊ฐ ๋‹ค์ด์–ผ๋กœ๊ทธ ๋ฃจํ”„๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  RPC Fast-path๋กœ ์งํ–‰ํ•˜๋„๋ก ์ตœ์ ํ™”. RPC ์„ฑ๊ณต ์ฆ‰์‹œ `return 0` ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ค‘๋ณต ์ž…๋ ฅ ๋ฐฉ์ง€ ๋ฐ ์˜จ๋””๋งจ๋“œ ๋งˆ์ปค ๊ณ„์‚ฐ ์ ์šฉ. - `reconcile.sh`: `SKILLS_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"`๋กœ ์ ˆ๋Œ€ ๊ฒฝ๋กœ ์ฆ‰์‹œ ๊ณ„์‚ฐ ๋ฐ `env_python`/`atomic_dump_yaml`๋กœ ๋ช…์‹œ ์ฃผ์ž…, Python ์ธก `__file__` ์˜์กด์„ฑ ์ œ๊ฑฐ. - ํšŒ๊ท€ ๊ฐ€๋“œ: `tests/test_b19_headless_reconcile_fixes.py` (6๊ฐœ ๊ธฐ๋Šฅ/ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ 100% ํ†ต๊ณผ). ### **B-14 (โœ… ์™„๋ฃŒ โ€” F-1 / P1): `publish_event.py` ๋ธŒ๋กœ์ปค ์žฅ์•  ์‹œ `return 2` ์กฐ๊ธฐ ํƒˆ์ถœ๋กœ ์ธํ•œ 65๋ถ„ ๋ฃจํ”„ ์ •์ง€** - **ํ˜„์ƒ**: `publish_event.py`์—์„œ ๋ธŒ๋กœ์ปค ๋„คํŠธ์›Œํฌ ์žฅ์•  ๋ฐœ์ƒ ์‹œ `return 2`๋กœ ์กฐ๊ธฐ ์ข…๋ฃŒ๋˜์–ด, ๋’ค๋”ฐ๋ฅด๋Š” ๋กœ์ปฌ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ƒํƒœ(`update_job_status(status=completed)`) ๋ฐ ๊ฐ์‚ฌ ๋กœ๊ทธ(`append_event`, `registry.append_event`) ๊ฐฑ์‹ ์ด ๋ˆ„๋ฝ๋˜๋˜ ๊ฒฐํ•จ. - **์กฐ์น˜ ๊ฒฐ๊ณผ (์™„๋ฃŒ โ€” ์ปค๋ฐ‹ `c6b6c77`)**: ๋„คํŠธ์›Œํฌ ๋ฐœํ–‰ ์‹คํŒจ ์—ฌ๋ถ€์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋กœ์ปฌ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋ฐ ๊ฐ์‚ฌ ๋กœ๊ทธ๋ฅผ 100% ๋จผ์ € ๋™๊ธฐํ™”ํ•œ ํ›„ `published=False`์™€ ํ•จ๊ป˜ `return 2`๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ์žฌ๋ฐฐ์น˜ (G-1 ~ G-4 ํšŒ๊ท€ ๊ฐ€๋“œ๋กœ ๋ด‰์ธ ์™„๋ฃŒ). ### **B-15 (โœ… ์™„๋ฃŒ โ€” C1 & F-4 / P1): `job_subscriber.py` ๋””์Šคํฌ ํด๋ฐฑ ๋ถ€์žฌ ๋ฐ ์œ„์ž„ ๊ฒฝ๋กœ ์ธํ”„๋ผ ์—๋Ÿฌ ์˜คํŒ์ •** - **ํ˜„์ƒ**: `job_subscriber.py`๊ฐ€ ๋„คํŠธ์›Œํฌ ํ๋งŒ ๋Œ€๊ธฐํ•˜๋ฉฐ ๋กœ์ปฌ ๋””์Šคํฌ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š์•„ ๋ธŒ๋กœ์ปค ๋‹ค์šด ์‹œ ๋ธ”๋กœํ‚น๋˜๊ฑฐ๋‚˜ ์ธํ”„๋ผ ์—๋Ÿฌ๊ฐ€ ์ž‘์—… `error`๋กœ ์˜คํŒ์ •๋˜๋˜ ๊ฒฐํ•จ. - **์กฐ์น˜ ๊ฒฐ๊ณผ (์™„๋ฃŒ โ€” ์ปค๋ฐ‹ `c6b6c77`)**: `_check_disk_fallback()`์„ ๋„์ž…ํ•˜์—ฌ ๋กœ์ปฌ ๋””์Šคํฌ ์ƒ์˜ ํ„ฐ๋ฏธ๋„ ์ƒํƒœ๋ฅผ ๊ฐ์ง€ํ•˜๋ฉด ํ•ฉ์„ฑ ์ด๋ฒคํŠธ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ์ฆ‰์‹œ `rc=0`์œผ๋กœ ์ •์ƒ ์ข…๋ฃŒํ•˜๋„๋ก ๊ฐœ์„ . ๋ธŒ๋กœ์ปค ์ธํ”„๋ผ ์ ‘์† ์‹คํŒจ๋Š” ์ „์šฉ `rc=3`์œผ๋กœ ๋ถ„๋ฆฌ (G-5 ~ G-10 ํšŒ๊ท€ ๊ฐ€๋“œ๋กœ ๋ด‰์ธ ์™„๋ฃŒ). ### **B-16 (F-5 / P3): `make_client()` ๋งค ์‹คํ–‰ ๋žœ๋ค `client_id` ๋ฐœ๊ธ‰์œผ๋กœ ์ธํ•œ ์˜์† ์„ธ์…˜(Durable Session) ๊ตฌ์„ฑ ๋ถˆ๊ฐ€** - **ํ˜„์ƒ**: `mqtt_common.py:258`์—์„œ `client_id`๋ฅผ ๋งค๋ฒˆ `uuid.uuid4().hex[:8]`๋กœ ์ƒ์„ฑํ•˜์—ฌ, ๋ธŒ๋กœ์ปค๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์žฌ์—ฐ๊ฒฐ์„ ์‹๋ณ„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค (`NATS_REPORT.md` ยง3.5 F-5). - **ํŒŒ๊ธ‰ ํšจ๊ณผ**: ๋„คํŠธ์›Œํฌ ์žฌ์—ฐ๊ฒฐ ์‹œ ๋ฏธ์ˆ˜์‹  ์ด๋ฒคํŠธ ์œ ์‹ค ๊ฐ€๋Šฅ์„ฑ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. - **์กฐ์น˜ ๋ฐฉํ–ฅ**: B-15์˜ ๋กœ์ปฌ ๋””์Šคํฌ ํด๋ฐฑ์„ ํ‘œ์ค€ ๋ณต์› ๊ฒฝ๋กœ๋กœ ํ™•๋ฆฝํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ์„ธ์…˜ ์˜์กด๋„๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , ํ•„์š” ์‹œ ๊ฒฐ์ •๋ก ์  ์‹๋ณ„์ž ๊ทœ์น™์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ### **B-17 (P1): `_load_dotenv` ์˜คํƒ€/๋ถ€์žฌ ๊ฒฝ๋กœ ์ง€์ • ์‹œ Fail-Closed ๋ฐ ๊ณต์šฉ ๋ธŒ๋กœ์ปค ํด๋ฐฑ ๋ฐฉ์ง€** - **ํ˜„์ƒ**: `MAM_ENV_FILE`์ด ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •๋˜์—ˆ์œผ๋‚˜ ํ•ด๋‹น ๊ฒฝ๋กœ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, `_load_dotenv`๊ฐ€ ์กฐ์šฉํžˆ ๋ฆฌํ„ดํ•˜์—ฌ `broker.hivemq.com` ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค๋กœ ํด๋ฐฑ๋˜๋Š” ์œ„ํ—˜. - **ํŒŒ๊ธ‰ ํšจ๊ณผ**: ์„ค์ • ์˜คํƒ€ ๋ฐœ์ƒ ์‹œ ์žก ์ด๋ฒคํŠธ์™€ ํ”„๋กฌํ”„ํŠธ๊ฐ€ ๊ณต๊ฐœ ๋ธŒ๋กœ์ปค๋กœ ์ „์†ก๋  ์ˆ˜ ์žˆ์Œ. - **์กฐ์น˜ ๋ฐฉํ–ฅ (2๋‹จ ๊ตฌ์กฐ)**: 1. import ์‹œ์ : ๋ช…์‹œ์  `MAM_ENV_FILE` ๊ฒฝ๋กœ ๋ถ€์žฌ ์‹œ `logger.error` ๊ธฐ๋ก ๋ฐ `_env_file_missing = True` ํ”Œ๋ž˜๊ทธ ์„ค์ • (์ƒ์œ„ ์ž„์˜ ํƒ์ƒ‰ ๊ธˆ์ง€, import ์˜ˆ์™ธ ๋ฐฉ์ง€). 2. ์ ‘์† ์‹œ์ : `make_client()` ์‹œ `_env_file_missing`์ด๋ฉด `RuntimeError`๋กœ fail-closed ๊ฑฐ๋ถ€. ์ตœ์ข… ํ˜ธ์ŠคํŠธ๊ฐ€ `broker.hivemq.com`์ธ ๊ฒฝ์šฐ ๋ˆˆ์— ๋„๋Š” ๋ณด์•ˆ ๊ฒฝ๊ณ  ์ถœ๋ ฅ. ### **B-18 (P2): `.mam.env`์™€ `.env` ๊ณต์กด ๋ฐ ๋‹ค์ค‘ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๊ฒฝ๊ณ„ ํƒ์ƒ‰ ์ •ํ•ฉ์„ฑ** - **ํ˜„์ƒ**: `.mam.env`์™€ `.env`์˜ ์šฐ์„ ์ˆœ์œ„ ๋ฐ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๊ฒฝ๊ณ„(`.agents`, `.git`) ํƒ์ƒ‰ ๊ณผ์ •์—์„œ ๋‹ค์ค‘ ์›Œํฌ์ŠคํŽ˜์ด์Šค ํ™˜๊ฒฝ์—์„œ์˜ ์ผ๊ด€์„ฑ ์œ ์ง€. - **์กฐ์น˜ ๋ฐฉํ–ฅ**: `MAM_REAL_ROOT` -> `WORKSPACE_ROOT` -> ์ƒ์œ„ ๊ฒฝ๊ณ„ ๋””๋ ‰ํ„ฐ๋ฆฌ -> `cwd` ์ˆœ์„œ์˜ first-hit-wins ํƒ์ƒ‰ ๊ทœ์น™ ์ ์šฉ. --- ## 3. ๐ŸŸก ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์ตœ์ ํ™” ๊ณผ์ œ (Orchestration Optimizations โ€” ์ถ”์  ์ค‘ 1๊ฑด / ์™„๋ฃŒ 1๊ฑด: O-5, O-6) ### **O-5 (P2): NATS/MQTT ๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ ๊ณ ๋„ํ™” ๋ฐ `nats-server` ์ŠคํŒŒ์ดํฌ ๊ฒ€์ฆ (Track 1 ~ Track 2)** - **ํ˜„์ƒ**: `NATS_REPORT.md` ์•„ํ‚คํ…์ฒ˜ ์‹ค์ธก ๋ถ„์„์— ๋”ฐ๋ผ `nats-server` ๋‚ด์žฅ MQTT 3.1.1 ์–ด๋Œ‘ํ„ฐ๋ฅผ ์‚ฌ์„ค ์ „์šฉ ๋ธŒ๋กœ์ปค๋กœ ์ฑ„ํƒํ•˜๋Š” ์ „๋žต(Option C)์ด ํ™•์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - **์กฐ์น˜ ๋ฐฉํ–ฅ**: 1. **Track 1 (์ŠคํŒŒ์ดํฌ ๊ฒ€์ฆ)**: ๊ฒฉ๋ฆฌ ํ™˜๊ฒฝ์—์„œ `nats-server -js`์˜ MQTT 3.1.1 ํ˜ธํ™˜์„ฑ ์‹ค์ธก ๊ฒ€์ฆ. 2. **Track 2 (๋ณด์•ˆ/๊ฒฉ๋ฆฌ)**: ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ง€๋ฌธ ๊ธฐ๋ฐ˜ ํ† ํ”ฝ(`mam//jobs/...`) ๋ฐ ๋ฌด์กฐ๊ฑด `auth_token` ๋ฐœ๊ธ‰(G-11)์„ ์ ์šฉํ•˜์—ฌ A-2 ๋ณด์•ˆ ๊ฒฐํ•จ ์™„์ „ ์ข…๊ฒฐ. 3. **Track 3 (๋ฌธ์„œ/์„ค์ •)**: `MESSAGING.md`, `VERSIONS.md`, `.mam.env`์— `nats-server` ์„œ๋น™ ๊ฐ€์ด๋“œ ๋ฐ ์„ค์ • ๋™๊ธฐํ™”. ### **O-6 (โœ… ์™„๋ฃŒ โ€” P1): ์›๊ฒฉ ํ”„๋กœ๋•์…˜ ๋ธŒ๋กœ์ปค ์ž์‚ฐ ์ •๋ณธํ™” ๋ฐ `nats-docker` ์„œ๋ธŒ๋ชจ๋“ˆ ๋ถ„๋ฆฌ** - **๋‚ด์šฉ**: 1. ์›๊ฒฉ Docker NATS ๋ฐฐํฌ ๊ฐ€์ด๋“œ ๋ฐ ์ž์‚ฐ(`docker-compose.yaml`, `nats.conf`, `.env.example`, `README.md`) ๊ตฌํ˜„. 2. `nats-docker` ๋…๋ฆฝ Git ์ €์žฅ์†Œ ๋ฐ ์„œ๋ธŒ๋ชจ๋“ˆ(`.gitmodules`, `nats-docker/`) ๋ถ„๋ฆฌ ์™„๋ฃŒ (์ปค๋ฐ‹ `629a67f`, `12ba30b`, `916185c`). 3. ๋ฐฐํฌ ์‹ ์„ ๋„ ๋ฐ ๋ณด์•ˆ ํšŒ๊ท€ ๊ฐ€๋“œ D-22 ~ D-30 9์ข… ๊ตฌ์ถ• (297 -> 306 tests 100% PASS ๋‹ฌ์„ฑ). 4. ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ ๋‚ด `_resolve_docker_dir()` ๋ฐ `_resolve_private_server_doc()` ๋™์  ๊ฒฝ๋กœ ํ•ด์„๊ธฐ ๋„์ž…. ### **A-4 (โœ… ์™„๋ฃŒ โ€” P3-1): ์—์ด์ „ํŠธ ์ง€์‹ ์‚ฐ์žฌ โ€” `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 โ€” 3๊ฑด) ### **B-14 (F-1 / P1): `publish_event.py` ๋ธŒ๋กœ์ปค ์žฅ์•  ์‹œ `return 2` ์กฐ๊ธฐ ํƒˆ์ถœ๋กœ ์ธํ•œ 65๋ถ„ ๋ฃจํ”„ ์ •์ง€** - **ํ˜„์ƒ**: `publish_event.py:195-199`์—์„œ ๋ธŒ๋กœ์ปค ๋„คํŠธ์›Œํฌ ์žฅ์•  ๋ฐœ์ƒ ์‹œ `return 2`๋กœ ์กฐ๊ธฐ ์ข…๋ฃŒ๋˜์–ด, ๋’ค๋”ฐ๋ฅด๋Š” ๋กœ์ปฌ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ƒํƒœ(`update_job_status(status=completed)`) ๋ฐ ๊ฐ์‚ฌ ๋กœ๊ทธ(`append_event`, `registry.append_event`) ๊ฐฑ์‹ ์ด ๋ˆ„๋ฝ๋ฉ๋‹ˆ๋‹ค (`NATS_REPORT.md` ยง3.1 ์‹ค์ธก ์žฌํ˜„). - **ํŒŒ๊ธ‰ ํšจ๊ณผ**: `run_loop.sh`์˜ `wait_for_job()`์€ ๋กœ์ปฌ ๋””์Šคํฌ ํŒŒ์ผ์˜ ์ƒํƒœ๊ฐ€ `status=running`์œผ๋กœ ๋ฉˆ์ถฐ์žˆ์–ด `max_wait=3900s`๋ฅผ ์†Œ์ง„ํ•  ๋•Œ๊นŒ์ง€ **65๋ถ„๊ฐ„ ๋ฃจํ”„๊ฐ€ ์™„์ „ ์ •์ง€(Hang)**ํ•ฉ๋‹ˆ๋‹ค. - **์กฐ์น˜ ๋ฐฉํ–ฅ (Track 0 Step 1)**: ๋„คํŠธ์›Œํฌ ๋ฐœํ–‰ ์‹คํŒจ ์‹œ์—๋„ `append_event`์™€ `update_job_status`๋ฅผ ์˜จ์ „ํžˆ ์™„์ˆ˜ํ•œ ํ›„ `published=False`๋ฅผ ๊ธฐ๋กํ•˜๊ณ  `return 2`๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์‹คํ–‰ ์ˆœ์„œ๋ฅผ ์žฌ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค (G-1 ~ G-4 ํšŒ๊ท€ ๊ฐ€๋“œ ์‹ ์„ค). ### **B-15 (C1 & F-4 / P1): `job_subscriber.py` ๋””์Šคํฌ ํด๋ฐฑ ๋ถ€์žฌ ๋ฐ ์œ„์ž„ ๊ฒฝ๋กœ ์ธํ”„๋ผ ์—๋Ÿฌ ์˜คํŒ์ •** - **ํ˜„์ƒ**: 1. `job_subscriber.py:172-251`๊ฐ€ `queue.Empty` ์‹œ ๋„คํŠธ์›Œํฌ ํ๋งŒ ๋Œ€๊ธฐํ•˜๋ฉฐ ๋กœ์ปฌ ๋””์Šคํฌ ์ƒํƒœ๋ฅผ ํ™•์ธํ•˜์ง€ ์•Š์•„, ๋ธŒ๋กœ์ปค ๋‹ค์šด ์‹œ 120์ดˆ `idle_timeout` ๋™์•ˆ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ธ”๋กœํ‚น๋ฉ๋‹ˆ๋‹ค (`NATS_REPORT.md` ยง4.1 C1 ์ฑŒ๋ฆฐ์ง€ ๊ฒ€์ฆ). 2. `multi-agent-mux-delegate-job:331-341`์—์„œ `wait "$sub_pid"`์˜ `sub_rc`๋ฅผ ์ง์ ‘ `job_status`๋กœ ๋งคํ•‘(`rc=1` -> `job_status="error"`)ํ•˜์—ฌ, ๋ธŒ๋กœ์ปค ์—ฐ๊ฒฐ ์‹คํŒจ๋กœ ์ธํ•œ ๋ฏธํฌ์ฐฉ ์˜ˆ์™ธ(`rc=1`) ๋ฐœ์ƒ ์‹œ ์ž‘์—…์ž์˜ ์ •์ƒ ์‚ฐ์ถœ๋ฌผ์ด ์กด์žฌํ•˜๋”๋ผ๋„ ์ž‘์—…์„ ๊ฐ•์ œ๋กœ `"error"`๋กœ ์˜คํŒ์ •ํ•ฉ๋‹ˆ๋‹ค (`NATS_REPORT.md` ยง3.4 F-4). - **ํŒŒ๊ธ‰ ํšจ๊ณผ**: ๋ธŒ๋กœ์ปค ์žฅ์•  ์‹œ ์ž‘์—…์ž๊ฐ€ ์ž‘์—…์„ ์ •์ƒ ์™„์ˆ˜ํ–ˆ์Œ์—๋„ ๋ฃจํ”„๊ฐ€ 2๋ถ„ ์ด์ƒ ์ง€์—ฐ๋˜๊ฑฐ๋‚˜ ๊ฑฐ์ง“ ์‹คํŒจ(False Failure)๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. - **์กฐ์น˜ ๋ฐฉํ–ฅ (Track 0 Step 2 & 3)**: 1. `job_subscriber.py` ๋Œ€๊ธฐ ๋ฃจํ”„์— ๋กœ์ปฌ ๋””์Šคํฌ(`load_job`/`read_logged_status`) ์ƒํƒœ ํด๋ฐฑ์„ ๋„์ž…ํ•˜์—ฌ ๋””์Šคํฌ ์™„๋ฃŒ ๊ฐ์ง€ ์‹œ `source: disk-fallback` ํ•ฉ์„ฑ ์ด๋ฒคํŠธ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  3์ดˆ ๋‚ด `rc=0`์œผ๋กœ ์กฐ๊ธฐ ์ •์ƒ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค. 2. ๋ธŒ๋กœ์ปค ์ธํ”„๋ผ ์—ฐ๊ฒฐ ์‹คํŒจ์— ์ „์šฉ `rc=3`์„ ๋ถ€์—ฌํ•˜๊ณ  `job_status="broker_unavailable"` ๋ถ„๊ธฐ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ์ž‘์—… ๊ฒฐ๊ณผ์™€ ์ธํ”„๋ผ ์—๋Ÿฌ๋ฅผ ์—„๊ฒฉํžˆ ๊ฒฉ๋ฆฌํ•ฉ๋‹ˆ๋‹ค (G-5 ~ G-10 ํšŒ๊ท€ ๊ฐ€๋“œ ์‹ ์„ค). ### **B-16 (F-5 / P3): `make_client()` ๋งค ์‹คํ–‰ ๋žœ๋ค `client_id` ๋ฐœ๊ธ‰์œผ๋กœ ์ธํ•œ ์˜์† ์„ธ์…˜(Durable Session) ๊ตฌ์„ฑ ๋ถˆ๊ฐ€** - **ํ˜„์ƒ**: `mqtt_common.py:258`์—์„œ `client_id`๋ฅผ ๋งค๋ฒˆ `uuid.uuid4().hex[:8]`๋กœ ์ƒ์„ฑํ•˜์—ฌ, ๋ธŒ๋กœ์ปค๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์žฌ์—ฐ๊ฒฐ์„ ์‹๋ณ„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค (`NATS_REPORT.md` ยง3.5 F-5). - **ํŒŒ๊ธ‰ ํšจ๊ณผ**: ๋„คํŠธ์›Œํฌ ์žฌ์—ฐ๊ฒฐ ์‹œ ๋ฏธ์ˆ˜์‹  ์ด๋ฒคํŠธ ์œ ์‹ค ๊ฐ€๋Šฅ์„ฑ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. - **์กฐ์น˜ ๋ฐฉํ–ฅ**: B-15์˜ ๋กœ์ปฌ ๋””์Šคํฌ ํด๋ฐฑ์„ ํ‘œ์ค€ ๋ณต์› ๊ฒฝ๋กœ๋กœ ํ™•๋ฆฝํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ์„ธ์…˜ ์˜์กด๋„๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , ํ•„์š” ์‹œ ๊ฒฐ์ •๋ก ์  ์‹๋ณ„์ž ๊ทœ์น™์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. --- ## 3. ๐ŸŸก ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์ตœ์ ํ™” ๊ณผ์ œ (Orchestration Optimizations โ€” 1๊ฑด) ### **O-5 (P2): NATS/MQTT ๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ ๊ณ ๋„ํ™” ๋ฐ `nats-server` ์ŠคํŒŒ์ดํฌ ๊ฒ€์ฆ (Track 1 ~ Track 2)** - **ํ˜„์ƒ**: `NATS_REPORT.md` ์•„ํ‚คํ…์ฒ˜ ์‹ค์ธก ๋ถ„์„์— ๋”ฐ๋ผ, `nats-py` ํด๋ผ์ด์–ธํŠธ ์žฌ์ž‘์„ฑ(Option B)์„ ๋ฐฐ์ œํ•˜๊ณ  `nats-server` ๋‚ด์žฅ MQTT 3.1.1 ์–ด๋Œ‘ํ„ฐ๋ฅผ ์‚ฌ์„ค ์ „์šฉ ๋ธŒ๋กœ์ปค๋กœ ์ฑ„ํƒํ•˜๋Š” ์ „๋žต(Option C)์ด ํ™•์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - **์กฐ์น˜ ๋ฐฉํ–ฅ**: 1. **Track 1 (์ŠคํŒŒ์ดํฌ ๊ฒ€์ฆ)**: ๊ฒฉ๋ฆฌ ํ™˜๊ฒฝ์—์„œ `nats-server -js`์˜ MQTT 3.1.1 ํ˜ธํ™˜์„ฑ(Retained ํ„ฐ๋ฏธ๋„ ์ด๋ฒคํŠธ ์ „๋‹ฌ S-3, QoS 1 ACK S-4, Subject ๋ผ์šฐํŒ… S-5 ๋“ฑ 9์ข… ๋งคํŠธ๋ฆญ์Šค S-1 ~ S-9) ์‹ค์ธก ๊ฒ€์ฆ. 2. **Track 2 (๋ณด์•ˆ/๊ฒฉ๋ฆฌ)**: ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ง€๋ฌธ ๊ธฐ๋ฐ˜ ํ† ํ”ฝ(`mam//jobs/...`) ๋ฐ ๋ฌด์กฐ๊ฑด `auth_token` ๋ฐœ๊ธ‰(G-11)์„ ์ ์šฉํ•˜์—ฌ A-2 ๋ณด์•ˆ ๊ฒฐํ•จ ์™„์ „ ์ข…๊ฒฐ. 3. **Track 3 (๋ฌธ์„œ/์„ค์ •)**: `MESSAGING.md`, `VERSIONS.md`, `.mam.env`์— `nats-server` ์„œ๋น™ ๊ฐ€์ด๋“œ ๋ฐ ์„ค์ • ๋™๊ธฐํ™”. --- ## 4. โšช ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ ๋ฐ ์ฃฝ์€ ์ฝ”๋“œ (Legacy Remnants โ€” 0๊ฑด โ€” ์ „์› ์™„๋ฃŒ) --- ## 5. ๐ŸŽ‰ ์™„๋ฃŒ๋œ ๊ณผ์ œ (Completed Tasks โ€” 24๊ฑด) ### **B-9 (P4-1): `LOGS_DIR` import ์‹œ์  cwd ๊ณ ์ • ํ•ด์†Œ** โ€” โœ… ์™„๋ฃŒ - `mqtt_common.LOGS_DIR` ์ด ๋ชจ๋“ˆ import ์‹œ์ ์˜ `os.getcwd()` ๋กœ ์ ˆ๋Œ€ํ™”๋˜์–ด, ์ดํ›„ ํ”„๋กœ์„ธ์Šค๊ฐ€ `chdir` ํ•˜๋ฉด ๊ฐ์‚ฌ ๋กœ๊ทธ๊ฐ€ ์˜› ๊ฒฝ๋กœ์— ๊ณ„์† ์Œ“์ด๋˜ ๋ฌธ์ œ๋ฅผ ํ•ด์†Œํ–ˆ์Šต๋‹ˆ๋‹ค(์‹ค์ธก ์žฌํ˜„). ๊ฒฝ๋กœ ํ•ด์„์„ ํ˜ธ์ถœ ์‹œ์ ์œผ๋กœ ๋ฏธ๋ฃจ๋Š” `get_logs_dir()` ๋ฅผ ๋„์ž…ํ•˜๊ณ  ๋ชจ๋“ˆ ์ „์—ญ ๋Œ€์ž…์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค. - **ํ•˜์œ„ ํ˜ธํ™˜**: PEP 562 ๋ชจ๋“ˆ `__getattr__` ๋กœ `mqtt_common.LOGS_DIR` ์†์„ฑ ์ ‘๊ทผ์„ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋˜ ๋™์ ์œผ๋กœ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ €์žฅ์†Œ ๋‚ด `from mqtt_common import LOGS_DIR` ์‚ฌ์šฉ์€ 0๊ฑด์ž„์„ ์ „์ˆ˜ ํ™•์ธํ–ˆ์œผ๋ฏ€๋กœ ํ˜ธํ™˜ ํ‘œ๋ฉด์ด 100% ๋ฎ์ž…๋‹ˆ๋‹ค. - **๊ฐ€์‹œ์„ฑ & ํƒ์ƒ‰์„ฑ**: PEP 562 `__dir__` ์„ ํ•จ๊ป˜ ์ •์˜ํ•ด `dir(mqtt_common)` ๋ฐ ํƒญ ์™„์„ฑ์—์„œ `LOGS_DIR` ์ด ๊ณ„์† ๋ณด์ด๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค(`hasattr` ์€ `__getattr__` ๋งŒ์œผ๋กœ๋„ ๋™์ž‘ํ•˜๋ฏ€๋กœ ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค). - **๋ถ€์ˆ˜ ๊ฐœ์„ **: `DELEGATE_JOB_LOGS_DIR` ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์ด์ œ ์‹คํ–‰ ์ค‘ ๋ณ€๊ฒฝ๊นŒ์ง€ ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค(์ข…์ „์—๋Š” import ์ดํ›„ ๋ณ€๊ฒฝ์ด ๋ฌด์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค). - ๊ฐ™์€ ํŒŒ์ผ์˜ `DEFAULT_REGISTRY_DIR` ์€ ์ƒ๋Œ€ ๋ฌธ์ž์—ด๋กœ ๋‚จ์•„ ์žˆ์–ด ์• ์ดˆ์— ์ด ๊ฒฐํ•จ์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค โ€” B-9 ์˜ ๋ณธ์งˆ์€ "ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ **์ ˆ๋Œ€ํ™” ์‹œ์ **"์ด์—ˆ์Šต๋‹ˆ๋‹ค. - ํšŒ๊ท€ ๊ฐ€๋“œ 5์ข…์„ ์‹ ์„คํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ๋กœ๊ทธ ๊ณ„์ธต์€ best-effort `except Exception` ์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ์‚ผํ‚ค๋ฏ€๋กœ, ์ž˜๋ชป๋œ ์ˆ˜์ •์€ **๋ฌด์Œ ๋กœ๊ทธ ์†Œ์‹ค + ์ „ ํ…Œ์ŠคํŠธ ํ†ต๊ณผ**๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค(์‹ค์ธก). ์ด์— ๊ฐ€๋“œ ํ•˜๋‚˜๋Š” ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ผ **์‹ค์ œ ํŒŒ์ผ ์ƒ์„ฑ**์„ ๋‹จ์–ธํ•˜๋„๋ก ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค. ### **B-13 (Stage 2): ์…€ํ”„ ํ˜ธ์ŠคํŒ… ๋ฃจํ”„ ๋Ÿฐํƒ€์ž„ ํ”„๋ฆฌ์ฆˆ ์Šค๋ƒ…์ƒท** โ€” โœ… ์™„๋ฃŒ - ๋ฃจํ”„ ๊ธฐ๋™ ์‹œ `.agents/skills/` ๋ฅผ `$TMPDIR` ์˜ ์ž„์‹œ ๋””๋ ‰ํ„ฐ๋ฆฌ์— 1ํšŒ ๋™๊ฒฐํ•˜๊ณ  ๊ทธ ์Šค๋ƒ…์ƒท์—์„œ ์žฌ์‹คํ–‰(`exec`)ํ•˜๋„๋ก ํ•˜์—ฌ, ํ„ด ๋„์ค‘ Worker ๊ฐ€ ํ”„๋ ˆ์ž„์›Œํฌ ์Šคํ‚ฌ์„ ํŽธ์ง‘ํ•ด๋„ ์ง„ํ–‰ ์ค‘์ธ ๋ฃจํ”„๊ฐ€ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ƒํƒœยท์ €์žฅ์†Œ ๊ฒฝ๋กœ๋Š” `MAM_REAL_ROOT`/`WORKSPACE_ROOT` ๋กœ ์‹ค์ œ ๋ฃจํŠธ๋ฅผ ๊ณ„์† ๊ฐ€๋ฆฌํ‚ค๋ฏ€๋กœ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌยท๋ฝยทdiff ์ˆ˜์ง‘ ๋™์ž‘์€ ์ข…์ „๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. - **๊ณ„์ธต B ์‹ ๊ทœ ๋Œ€์‘**: bash ๊ฐ€ ์‹คํ–‰ ์ค‘์ธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ฐ”์ดํŠธ ์˜คํ”„์…‹ ๊ธฐ์ค€์œผ๋กœ ๊ณ„์† ์ฝ๋Š”๋‹ค๋Š” ์‚ฌ์‹ค์„ ์‹ค์ธก ํ™•์ธํ•˜์—ฌ(์ •์ƒ ๊ต์ฒด๋ณธ์—๋„ `unexpected EOF` ๋ฐœ์ƒ), ๋ž˜ํผ๋ฟ ์•„๋‹ˆ๋ผ `run_loop.sh` ๋ณธ์ฒด๊นŒ์ง€ ๋™๊ฒฐ ๋Œ€์ƒ์— ํฌํ•จํ–ˆ์Šต๋‹ˆ๋‹ค. - **B-6 ๊ณผ์˜ ๊ตฌ๋ถ„**: B-6 ์ด ์ œ๊ฑฐํ•œ ๊ฒƒ์€ *์œ„์ž„ ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค ์Šคํ‚ฌ ํŠธ๋ฆฌ ๋‚ด๋ถ€์—* ๋งŒ๋“ค๋˜ `.tmp` ์‚ฌ๋ณธ์ด๊ณ , ๋ณธ ์กฐ์น˜๋Š” *๊ธฐ๋™ ์‹œ 1ํšŒ ํŠธ๋ฆฌ ์™ธ๋ถ€์—* ๋งŒ๋“œ๋Š” ์Šค๋ƒ…์ƒท์ž…๋‹ˆ๋‹ค. ์Šคํ‚ฌ ํŠธ๋ฆฌ์—๋Š” ์•„๋ฌด๊ฒƒ๋„ ์“ฐ์ง€ ์•Š์œผ๋ฉฐ ๊ธฐ์กด ๊ฐ€๋“œ `test_z9_no_tmp_copy_left_in_skill_tree` ๊ฐ€ ๊ทธ๋Œ€๋กœ ํ†ต๊ณผํ•ฉ๋‹ˆ๋‹ค. - **๊ฒฐํ•จ ๊ต์ • (P1/C1/C2)**: ์ธ์ž ํŒŒ์„œ์˜ `$@` ์†Œ์ง„์— ๋Œ€๋น„ํ•ด ์ตœ์ƒ๋‹จ์—์„œ `MAM_LOOP_ARGV` ๋ฐฐ์—ด ํฌํš, `export MAM_LOOP_FREEZE_OWNED="1"` ๋กœ ์ •๋ฆฌ ๊ฒŒ์ดํŠธ ๋ˆ„์ˆ˜ ์ฐจ๋‹จ, `log_*` ์ •์˜ ์ „ ๊ตฌ๊ฐ„ `echo` ์ง์ ‘ ์‚ฌ์šฉ์œผ๋กœ ํด๋ฐฑ ์‹œ์˜ ๊ตฌ๋ฌธ ์˜ค๋ฅ˜ ํฌ๋ž˜์‹œ๋ฅผ ์›์ฒœ ๋ฐฉ์ง€ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ •๋ฆฌ ๋กœ์ง์€ ์ƒˆ ํŠธ๋žฉ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์กด `_mam_release_guard` ๋ฅผ ํ™•์žฅํ–ˆ์Šต๋‹ˆ๋‹ค โ€” `trap โ€ฆ EXIT` ์ค‘๋ณต ์„ค์น˜๋Š” ๊ธฐ์กด ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์กฐ์šฉํžˆ ๋Œ€์ฒดํ•˜๋ฉฐ(์‹ค์ธก), ์ด๋Š” B-12 ์™€ ๋™์ผํ•œ ๊ณ„์—ด์˜ ์‚ฌ๊ณ ์ž…๋‹ˆ๋‹ค. - ํšŒ๊ท€ ๊ฐ€๋“œ 5์ข…(`test_b13_reexec_preserves_original_argv`, `test_b13_freeze_survives_broken_wrapper`, `test_b13_freeze_dir_is_outside_the_skill_tree`, `test_b13_release_guard_cleans_up_and_releases_lock`, `test_b13_no_freeze_switch_disables_reexec`)์„ ์‹ ์„คํ•˜๊ณ  ๋ฎคํ…Œ์ด์…˜ M0~M6 ์œผ๋กœ ๋ฐฉ์–ด๋ ฅ์„ ๊ฒ€์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **B-10 (P3-2): `agent_identities` tier-3 ์‹ ์› ์บ์‹œ ์™„์ „ ์ œ๊ฑฐ (Option A)** โ€” โœ… ์™„๋ฃŒ - ์ €์žฅ์†Œ ์ „์ฒด์— `agent_identities` ์“ฐ๊ธฐ ์ฝ”๋“œ๊ฐ€ 0๊ฑด์ž„์„ ์žฌํ™•์ธํ•˜๊ณ (๋ผ์ด๋ธŒ `.db` ์ตœ์ƒ์œ„ ํ‚ค์—๋„ ๋ถ€์žฌ), ๊ตฌ์กฐ์ ์œผ๋กœ ํžˆํŠธ ๋ถˆ๊ฐ€์˜€๋˜ ์ฝ๊ธฐ ๊ฒฝ๋กœ 3๊ณณ์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค โ€” `workspace_uuid.py` tier-3 ํด๋ฐฑ(28์ค„), `reconcile.sh` drift D ์ง„๋‹จ(35์ค„), `stop_session.sh` purge ์‹œ ์บ์‹œ ์†Œ๊ฑฐ(6์ค„), ๊ด€๋ จ ์ฃผ์„ 3๊ณณ. UUID ํ•ด๊ฒฐ์€ tier-1(per-row own id) โ†’ tier-2(์–ด๋Œ‘ํ„ฐ `discover()`) 2๋‹จ๊ณ„๋กœ ๋‹จ์ˆœํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค. - **PyYAML ์˜์กด โ€” ์‹คํ–‰ ๊ฒฝ๋กœ ๊ธฐ์ค€์œผ๋กœ ํ•ด์†Œ**: `verify_session.py::mam_orchestrator_uuids` ๊ฐ€ `yaml` ์„ ํ•จ์ˆ˜ ์ง„์ž… ์ฆ‰์‹œ import ํ•˜๊ณ  ์žˆ์–ด(`:10`), tier-3 ์„ ์ง€์›Œ๋„ UUID ํ•ด๊ฒฐ ๊ฒฝ๋กœ๋Š” PyYAML ์„ ์š”๊ตฌํ–ˆ์Šต๋‹ˆ๋‹ค. `state.py` ์˜ ๊ธฐ์กด ์„ ๋ก€๋Œ€๋กœ YAML ํด๋ฐฑ ๋ถ„๊ธฐ ์•ˆ์œผ๋กœ ์ด๋™์‹œ์ผœ ๊ต์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. - **์ •์ •**: ์› ํ•ญ๋ชฉ์ด ์„œ์ˆ ํ–ˆ๋˜ "`lib.sh` ์˜ PyYAML ํ•˜๋“œ ์˜์กด" ์€ `load_state_json` ์ด `state.py` ๋กœ ์ด๊ด€๋˜๋ฉฐ **์ด๋ฏธ ํ•ด์†Œ๋œ ์ƒํƒœ**์˜€์Šต๋‹ˆ๋‹ค. ํ•œํŽธ `atomic_yaml.py` ๋Š” ๋ชจ๋“ˆ ์กด์žฌ ์ด์œ ์ƒ ์•ž์œผ๋กœ๋„ ์ตœ์ƒ๋‹จ์—์„œ import ํ•˜๋ฏ€๋กœ **์ €์žฅ์†Œ ์ฐจ์›์˜ PyYAML ์š”๊ตฌ์™€ ์„ค์น˜ ๊ฒŒ์ดํŠธ๋Š” ์œ ์ง€**๋ฉ๋‹ˆ๋‹ค. - ํšŒ๊ท€ ๊ฐ€๋“œ 3์ข…(`test_b10_no_agent_identities_reader_in_production`, `test_b10_workspace_uuid_has_no_yaml_import`, `test_b10_find_workspace_uuid_runs_without_pyyaml`)์„ ์‹ ์„คํ•˜๊ณ  ๋ฎคํ…Œ์ด์…˜ 5์ข…(M1ยทM2ยทM3aยทM3bยทM4)์œผ๋กœ ๋ฐฉ์–ด๋ ฅ์„ ๊ฒ€์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **B-5: macOS NFS ๊ฐ์ง€ `df -P` ํด๋ฐฑ ๊ฒ€์ฆ ๋ฐ ์ข…๊ฒฐ** โ€” โœ… ์™„๋ฃŒ (์ข…๊ฒฐ) - `_check_is_nfs`(`lib.sh:1181-1192`)์—์„œ macOS/BSD ํ™˜๊ฒฝ ์‹œ GNU ์ „์šฉ `df --output=target` ์‹คํŒจ(`rc=64`)์— ๋Œ€๋น„ํ•œ `df -P "$f" | tail -1 | awk '{print $6}'` POSIX ํด๋ฐฑ์ด ์ •์ƒ ๋™์ž‘ํ•จ์„ ์‹ค์ธก ๋ฐ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ(`test_stop_check_is_nfs_local`)๋กœ ๊ฒ€์ฆ ์™„๋ฃŒํ•˜์—ฌ ์ข…๊ฒฐ ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ### **C-6 (P2-3): `stop_session.sh` ๋ ˆ๊ฑฐ์‹œ ์ฃผ์„ ๋ฐ ๊ตฌ๋ฒ„์ „ ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ** โ€” โœ… ์™„๋ฃŒ - ํ—ค๋” ์ฃผ์„์ด ๊ด‘๊ณ ํ•˜๋˜ `--mode soft|hard` / `--capture-id` / `--graceful` 3์ข…์€ ํŒŒ์„œ๊ฐ€ `exit 2` ๋กœ ๊ฑฐ๋ถ€ํ•˜๋Š” ํ์ง€ ํ”Œ๋ž˜๊ทธ์˜€์Šต๋‹ˆ๋‹ค. ํ—ค๋” 29์ค„์„ ํ˜„์žฌ CLI ์— ๋งž๊ฒŒ ๊ต์ฒดํ•˜๊ณ , `usage()` ์— ๋ˆ„๋ฝ๋ผ ์žˆ๋˜ ์˜ต์…˜ ์„ค๋ช…๊ณผ `--agent` ์ ‘๋ฏธ์‚ฌ ์ถ”๋ก  ๋™์ž‘์„ ๋ณด๊ฐ•ํ–ˆ์œผ๋ฉฐ, Option B ์ดํ›„ ๋ฌด์˜๋ฏธํ•ด์ง„ "์›Œํฌ์ŠคํŽ˜์ด์Šค์— ๊ฒฉ๋ฆฌ๋œ" ํ‘œํ˜„๊ณผ ๋‚ด๋ถ€ ์ฃผ์„ 3๊ณณ์˜ ํ”Œ๋ž˜๊ทธ ํ‘œ๊ธฐ๋ฅผ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. - `MESSAGING.md` ์ƒํƒœ ํ‘œ๊ฐ€ ์ œ๊ฑฐ๋œ ํ”Œ๋ž˜๊ทธ๋กœ `stopped`/`terminated` ๋ฅผ ์ •์˜ํ•˜๋˜ ๊ฒƒ์„ ๊ต์ •ํ•˜๊ณ , ์ƒ์‚ฐ์ž๊ฐ€ ์‚ฌ๋ผ์ง„ `archived` ๋ฅผ ๋ ˆ๊ฑฐ์‹œ ๊ฐ’์œผ๋กœ ๋ช…๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋„์›€๋ง๊ณผ ํŒŒ์„œ์˜ ์ผ์น˜๋ฅผ ๊ฐ•์ œํ•˜๋Š” ํšŒ๊ท€ ๊ฐ€๋“œ `test_comp_stop_usage_matches_parser` ๋ฅผ ์‹ ์„คํ•˜๊ณ  ๋ฎคํ…Œ์ด์…˜ 3์ข…(M1~M3)์œผ๋กœ ๋ฐฉ์–ด๋ ฅ์„ ๊ฒ€์ฆํ–ˆ์Šต๋‹ˆ๋‹ค โ€” C-6 ์€ ๋ฌธ์„œ ๊ณผ์ œ๋ผ ๊ธฐ์กด ํ…Œ์ŠคํŠธ๊ฐ€ ์ „ํ˜€ ์žก์ง€ ๋ชปํ•˜๋˜ ์˜์—ญ์ž…๋‹ˆ๋‹ค. ### **P3-1 (A-4 Phase 2 / Option B / C-3b / M2~M7): ์—์ด์ „ํŠธ ์ง€์‹ ๊ณ„์ธต ์–ด๋Œ‘ํ„ฐ ์ผ์›ํ™” ๋ฐ isolation.root ์™„์ „ ํ๊ธฐ** โ€” โœ… ์™„๋ฃŒ - ์—์ด์ „ํŠธ๋ณ„ ์•„ํ‹ฐํŒฉํŠธ ๊ฒฝ๋กœ, ๊ฒ€์ฆ ๋กœ์ง, ์žฌ๊ฐœ/์‹œ์ž‘ ์ŠคํŽ™, ํ† ํฐ, ์ข…๋ฃŒ ํ‚ค, ์ธ์ฆ(`auth_ok`), ์ž๋™ ๋ฐœ๊ฒฌ(`discover`)์„ `BaseAgentAdapter` ๋ฐ 4๊ฐœ ๊ตฌ์ฒด ์–ด๋Œ‘ํ„ฐ(`claude`, `agy`, `hermes`, `cline`)๋กœ ์ด๊ด€ํ•˜๊ณ , CLI facts bridge(`shlex.quote`) ๋ฐ ์„œ๋ธŒ์ปค๋งจ๋“œ(`spawn-spec`, `resume-spec`, `exit-key`)๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. - Universal Global Config ์ „ํ™˜ ํ›„์—๋„ ๋‚จ์•„์žˆ๋˜ `isolation.root` 4๊ฐœ ์†Œ๋น„์ž(`lib.sh`, `verify_session.py`, `workspace_uuid.py`, `stop_session.sh`, `atomic_yaml.py`)๋ฅผ ์™„์ „ ํ๊ธฐ(Option B)ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_a4_adapter_contract.py` (9/9 PASS) ๋ฐ ์ „์ฒด ํšŒ๊ท€ ํ…Œ์ŠคํŠธ **259/259 PASS (100%)** ๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ### **P2-2 (C-3a / C-4): ๊ฒฉ๋ฆฌ ๋นˆ ์Šคํ… 4์ข…ยท๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 4๊ฑดยท๋ฏธ์‚ฌ์šฉ ์‹ฌ๋ณผ 3์ข… ์ œ๊ฑฐ** โ€” โœ… ์™„๋ฃŒ - `.agents/skills/lib.sh` ์˜ ๋ฐฑ์›Œ๋“œ ํ˜ธํ™˜ ๋นˆ ์Šคํ… `provision_isolation` / `isolation_lever` / `isolation_env_prefix` / `isolation_cmd_args` 4์ข…(ํ”„๋กœ๋•์…˜ ํ˜ธ์ถœ์ž 0๊ฑด)์„ ์ œ๊ฑฐํ•˜๊ณ , ์ฃผ์„ ๋ธ”๋ก์— C-3b(`isolation.root` ํ–‰ ํ•„๋“œ) ๊ฒฝ๊ณ„๋ฅผ ๋ช…์‹œํ•ด ํ›„์† ์ •๋ฆฌ ์‹œ ์˜ค์‚ญ์ œ๋ฅผ ์ฐจ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - ์œ„ ์Šคํ…์˜ ๋นˆ ์ถœ๋ ฅ๋งŒ ์žฌํ™•์ธํ•˜๋˜ ๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 4๊ฑด(`tests/test_tier1_unit.py` 3, `tests/test_tier2_component.py` 1)์„ ์ œ๊ฑฐํ•˜๊ณ , ๊ทธ ์ž๋ฆฌ์— `--isolate`/`--no-isolate` ๋ ˆ๊ฑฐ์‹œ no-op ํ”Œ๋ž˜๊ทธ์˜ ์ธ์ž ํŒŒ์„œ ๊ณ„์•ฝ์„ ๊ณ ์ •ํ•˜๋Š” `test_create_session_legacy_isolate_flags_noop` 1๊ฑด์„ ์‹ ์„คํ–ˆ์Šต๋‹ˆ๋‹ค. ์‹ ๊ทœ ํ…Œ์ŠคํŠธ๋Š” ๋ถ„๊ธฐ ์‚ญ์ œยทํ•œ์ชฝ๋งŒ ์‚ญ์ œยท์กฐ์šฉํ•œ no-op ํ™”ยทusage ๋ฌธ์„œ ์ค„ ์‚ญ์ œ 4์ข… ๋ณ€์ด๋ฅผ ๋ชจ๋‘ ๊ฒ€์ถœํ•จ์„ ๋ณ€์ด ๊ฒ€์‚ฌ๋กœ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. `test_tier1_unit.py:31` ์„น์…˜ ํ—ค๋”๋„ `(5 Test Cases)` ๋กœ ๋™๊ธฐํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ฐธ์กฐ 0ํšŒ ๋ฏธ์‚ฌ์šฉ ์‹ฌ๋ณผ 3์ข…์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค: `_REAL_HERDR_PATH`(`lib.sh:126-127`, ๋Œ€์ž…+export๋งŒ โ€” `_resolve_real_herdr_path` ์˜ stdout/rc ๋ฐ˜ํ™˜ ์ฑ„๋„์€ ๋ถˆ๋ณ€์ž„์„ ์‹ค์ธก ํ™•์ธ), `TERMINAL_STATUSES`(`registry.py:38`, `__all__` ๋ฏธํฌํ•จ์œผ๋กœ ์ž„ํฌํŠธ ๊ณ„์•ฝ ๋ถˆ๋ณ€), `ISOLATE`(`create_session.sh:57`, `set -u` ํ•˜ ์ˆจ์€ ํ™•์žฅ ๋ถˆ๊ฐ€๋Šฅ). - `_HERDR_SHIM_DIR_PATTERN` / `_HERDR_SKILLS_BIN_PATTERN`(`lib.sh:83-84` โ†’ `:105` ์‚ฌ์šฉ ์ค‘), `VALID_STATUSES`(`registry.py:150-151` ์‚ฌ์šฉ ์ค‘), `--isolate`/`--no-isolate` ๋ ˆ๊ฑฐ์‹œ ํ˜ธํ™˜ ๋ถ„๊ธฐ, C-3b ์†Œ๋น„์ž 4๊ณณ์€ ๊ณ„ํš๋Œ€๋กœ ๋ฏธ์ ‘์ด‰์ž…๋‹ˆ๋‹ค. - ์ „์ฒด ํšŒ๊ท€ **256/256 PASS (100%)** ๋กœ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค (259 โ†’ 256, ์ˆœ๊ฐ 3 = ์ œ๊ฑฐ 4 โˆ’ ์‹ ์„ค 1). ### **P2-1 (B-6 / B-12): `delegate_job_safe` ์ž„์‹œ ์‚ฌ๋ณธ ์ œ๊ฑฐ ๋ฐ ์„œ๋ธŒ์…ธ ๋ฃจํ”„ ๋ฝ ์กฐ๊ธฐ ํ•ด์ œ ์ฐจ๋‹จ ์กฐ์น˜** โ€” โœ… ์™„๋ฃŒ - `.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh` ๋‚ด `delegate_job_safe` ๊ฐ€ `.agents/skills/...` ๊ฒฝ๋กœ ๋‚ด์— `.tmp` ์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•˜๋˜ ๋ฐฉ์‹์„ ์ œ๊ฑฐํ•˜๊ณ  ์›๋ณธ ๋ž˜ํผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ธํ”Œ๋ ˆ์ด์Šค๋กœ ์ง์ ‘ ์‹คํ–‰(`bash "$orig_script" "$@"`)ํ•˜๋„๋ก ๊ฐœ์„ ํ•˜์—ฌ ๋ฒ„์ „ ๊ด€๋ฆฌ ํŠธ๋ฆฌ ์˜ค์—ผ ๋ฐ rsync ๋ฐฐํฌ ์œ ์ถœ(B-6)์„ ์™„์ „ํžˆ ํ•ด์†Œํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋ช…๋ น ์น˜ํ™˜(`$(delegate_job_safe ...)`) ์„œ๋ธŒ์…ธ ๋‚ด์— ์„ค์น˜๋˜๋˜ `trap _mam_release_guard EXIT` ๋กœ ์ธํ•ด ์ฒซ ๋ฒˆ์งธ ์œ„์ž„ ์žก ์ข…๋ฃŒ ์‹œ์ ์— `.mam/loop-guard-active` ๋งˆ์ปค๊ฐ€ ์‚ญ์ œ๋˜์–ด O-3 Scoped Guard ๋ฐ O-2 ๋ฝ์ด ๋ฌด๋ ฅํ™”๋˜๋˜ ์ธ์ ‘ P0 ๊ฒฐํ•จ(**B-12 / D1**)์„ ๋กœ์ปฌ ํŠธ๋žฉ ์ œ๊ฑฐ๋ฅผ ํ†ตํ•ด ๊ทผ๋ณธ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋ž˜ํผ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰ ์‹คํŒจ ์‹œ ๋„๋‹ฌ ๋ถˆ๊ฐ€๋Šฅํ•˜๋˜ ์—๋Ÿฌ ์ง„๋‹จ์„ `delegate_job_safe` ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ํ‘œ์ค€์˜ค๋ฅ˜๋กœ ์ถœ๋ ฅ(`log_error "delegate_job_safe failed (exit $rc)..."`)ํ•˜๋„๋ก ์ง„๋‹จ ๋กœ๊น…์„ ๋ณด๊ฐ•ํ–ˆ์Šต๋‹ˆ๋‹ค. - `tests/test_o3_scoped_guard.py` ๋‚ด Z-9 ํ…Œ์ŠคํŠธ๋ฅผ 4๊ฐœ ์„ธ๋ถ€ ํ–‰์œ„ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ(`test_z9_loop_lock_survives_delegation`, `test_z9_probe_detects_the_defect`, `test_z9_no_tmp_copy_left_in_skill_tree`, `test_z9_exit_code_and_diagnostics_propagation`)๋กœ ๊ต์ฒด ๊ฒ€์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **multi-agent-mux-orc-onboard: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ์˜จ๋ณด๋”ฉ ์Šคํ‚ฌ ๋ฐ `orchestrator_uuids` ๋ฐฐ์ œ ๊ฒŒ์ดํŠธ ์กฐ์น˜** โ€” โœ… ์™„๋ฃŒ - `.agents/skills/multi-agent-mux-orc-onboard/` ์Šคํ‚ฌ ๋ฐ `.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh` ํ—ฌํผ ๋ชจ๋“ˆ์„ ์ƒ์„ฑํ•˜์—ฌ, ๋ฉ”์ธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ๊ฐ€ ํ”„๋กœ์ ํŠธ ๋งฅ๋ฝ ํŒŒ์•… ์‹œ ์ž์‹ ์˜ ๋Œ€ํ™” UUID๋ฅผ ํฌ์ฐฉํ•ด `.mam/agent-sessions.yaml` ๋ฐ SQLite DB ๋‚ด `orchestrator_uuids` ๋ฆฌ์ŠคํŠธ๋กœ ์›์ž์  ๊ธฐ๋กํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. - `.agents/skills/lib.sh` ๋‚ด `find_workspace_uuid` ๋ฐ `verify_session_uuid` ํ•จ์ˆ˜๋ฅผ ๊ฐฑ์‹ ํ•˜์—ฌ `orchestrator_uuids` ๋ฆฌ์ŠคํŠธ์— ํฌํ•จ๋œ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ๋Œ€ํ™” ID๋ฅผ ์„œ๋ธŒ ์—์ด์ „ํŠธ(`canary-projects-multi-agent-mux-creator-agy`)์˜ `find_workspace_uuid` ๋ฐ `capture_conversation_id` ํƒ์ƒ‰ ๋Œ€์ƒ์—์„œ 100% ์Šคํ‚ต(Skip)ํ•˜๋Š” ๋ฐฐ์ œ ๊ฒŒ์ดํŠธ๋ฅผ ์ˆ˜๋ฆฝํ•˜์—ฌ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ๋Œ€ํ™” DB ์˜ค์—ผ ๋ฐ SQLite DB ๋ฝ ๊ฒฐํ•จ์„ ์›์ฒœ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ `tests/test_orc_onboard.py` (40/40 PASS)๋ฅผ ์ž‘์„ฑํ•˜์—ฌ ์ž…์ฆํ–ˆ์Šต๋‹ˆ๋‹ค. ### **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` ๋ฌธ์„œ ์—ฐ๋™์„ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค. ### **Herdr-0.8.0-Compat-SanitizeHash: ์„ธ์…˜๋ช… 32์ž SHA-1 ํ•ด์‹œ ์ ‘๋ฏธ์‚ฌ ์ ˆ๋‹จ ๊ธฐ๋ฐ˜ ์œ ์ผ์„ฑ ๋ณด์žฅ ๋ฐ Mock Herdr 0.8.0 ์—๋Ÿฌ ์ •๋ ฌ (Commit `14b9de1`)** โ€” โœ… ์™„๋ฃŒ - `.agents/skills/lib_py/agents/sanitize.py` ๋ฐ `.agents/skills/lib.sh` ๋‚ด `_sanitize_herdr_agent_name()`์˜ ๊ธฐ์กด ๋‹จ์ˆœ ์ ˆ๋‹จ ๋ฐฉ์‹(`s[:16]-s[-15:]`)์œผ๋กœ ์ธํ•ด ๋™์ผ ๋ถ€๋ชจ ๊ฒฝ๋กœ ํ•˜์œ„์˜ ํ˜•์ œ ์›Œํฌ์ŠคํŽ˜์ด์Šค๋“ค์ด ๋™์ผํ•œ ์„ธ์…˜๋ช…์œผ๋กœ ์ถ•์•ฝ๋˜๋˜ ๊ฒฐํ•จ์„ **8์ž๋ฆฌ SHA-1 ํ•ด์‹œ ์ ‘๋ฏธ์‚ฌ(`s[:23]-sha1[:8]`)** ๊ฒฐํ•ฉ ๋ฐฉ์‹์œผ๋กœ 100% ํ•ด์†Œํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋นˆ ๋ฌธ์ž์—ด(`"agent"`), ์ˆซ์ž/ํŠน์ˆ˜๋ฌธ์ž ์‹œ์ž‘(`"x-"` ์ ‘๋‘์‚ฌ), 32์ž ๊ฒฝ๊ณ„ ๋ฐ 33์ž ์ด์ƒ ์ ˆ๋‹จ ๋“ฑ 11๊ฐœ ์—ฃ์ง€ ์ผ€์ด์Šค์—์„œ **Bash ์‹ฌ โ†” Python ๋ชจ๋“ˆ ๊ฐ„ 100% ๋ฐ”์ดํŠธ ๋‹จ์œ„ ๋™๋“ฑ์„ฑ(Parity)**์„ ํ™•๋ฆฝํ–ˆ์Šต๋‹ˆ๋‹ค. - `tests/conftest.py` Mock Herdr ์—๋Ÿฌ ์ถœ๋ ฅ์„ ์‹ค์ œ Herdr 0.8.0 ๋ฐ”์ด๋„ˆ๋ฆฌ ์ถœ๋ ฅ ๊ทœ๊ฒฉ(`unknown option:`, `missing required`, `invalid_agent_name`)๊ณผ ์™„์ „ ์ผ์น˜ํ•˜๋„๋ก ์ •๋ ฌํ•˜๊ณ , `lib.sh` Early Abort ๊ฐ€๋“œ ์ •๊ทœ์‹(`missing required`, `invalid_agent_name`, `^error:`)์„ ๋ณด๊ฐ•ํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ 3ํšŒ ์žฌ์‹œ๋„ ๋ฃจํ”„ ์ง€์—ฐ์„ ์›์ฒœ ์ฐจ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - `lib.sh`์˜ `has-session` ๋ถ„๊ธฐ ๋‚ด ์ž”์กดํ•˜๋˜ ๊ตฌํ˜• ํœด๋ฆฌ์Šคํ‹ฑ์„ ์ œ๊ฑฐํ•˜๊ณ , `tests/conftest.py` ๋‚ด์˜ 7๊ณณ ๊ตฌํ˜• ์ ˆ๋‹จ ์‚ฌ๋ณธ์„ `_match_agent` ํ—ฌํผ ํ•จ์ˆ˜๋กœ ์ผ์›ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ „์šฉ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ `tests/test_sanitize_and_mock_errors.py` (3/3 PASS) ๋ฐ ์ „์ฒด ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ (**256/256 PASS, 0 Failures / 0 Errors**)๋ฅผ ๊ฒ€์ฆ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์ž์œจ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ฃจํ”„(`run_loop.sh --all-reviewer`)๋ฅผ ํ†ตํ•ด Creator(`agy`, Job: `94bceedd`) ๋ฐ Reviewer(`cline`, Job: `14187d43`) ๊ต์ฐจ ๊ฒ€์ฆ ๋งŒ์žฅ์ผ์น˜ **`[VERDICT: PASS]`** ๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. --- ## 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 ์‹คํ–‰ ์ˆœ์„œ (4-Track Priority Alignment) > **์šฐ์„ ์ˆœ์œ„ ์›์น™ ๋ฐ NATS ๋ถ„์„ ํ•ฉ์˜ ๋ฐ˜์˜ (`NATS_REPORT.md`)**: > 1. **Track 0 (์ตœ์šฐ์„  P1 โ€” ๊ฐ€์šฉ์„ฑ ๋ฐ ๋‚ด๊ฒฐํ•จ์„ฑ ๊ต์ •)**: ๋ธŒ๋กœ์ปค ์žฅ์•  ์‹œ 65๋ถ„ ๋ฃจํ”„ ์ •์ง€(`B-14`) ๋ฐ 120์ดˆ ์ง€์—ฐ/์˜คํŒ์ •(`B-15`)์„ ๋ฐฉ์ง€ํ•˜๋Š” **๋กœ์ปฌ ๋””์Šคํฌ ๋‚ด๊ฒฐํ•จ์„ฑ ํ™•๋ณด (G-1 ~ G-10 ํšŒ๊ท€ ๊ฐ€๋“œ ์‹ ์„ค, ๋ธŒ๋กœ์ปค ์ œํ’ˆ ๋ฌด๊ด€ ์„ ํ–‰ ํ•„์ˆ˜)**. > 2. **Track 1 (์ฐจ์ˆœ์œ„ P2 โ€” ๋ธŒ๋กœ์ปค ์ŠคํŒŒ์ดํฌ ๊ฒ€์ฆ)**: ๊ฒฉ๋ฆฌ ํ™˜๊ฒฝ์—์„œ `nats-server -js`์˜ MQTT 3.1.1 ํ˜ธํ™˜์„ฑ(Retained ํ„ฐ๋ฏธ๋„ ์ด๋ฒคํŠธ S-3, QoS 1 ACK S-4 ๋“ฑ 9์ข… ๋งคํŠธ๋ฆญ์Šค S-1 ~ S-9) ์‹ค์ธก ์ŠคํŒŒ์ดํฌ ๊ฒ€์ฆ (`O-5`). > 3. **Track 2 (๋ณด์•ˆ/๊ฒฉ๋ฆฌ ์™„๊ฒฐ P3)**: ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ง€๋ฌธ ๊ธฐ๋ฐ˜ ํ† ํ”ฝ(`mam//jobs/...`) ๋ฐ ๋ฌด์กฐ๊ฑด `auth_token` ๋ฐœ๊ธ‰(G-11)์œผ๋กœ `A-2` ๋ณด์•ˆ ๊ฒฐํ•จ ์™„์ „ ์ข…๊ฒฐ ๋ฐ `B-16` ์™„๊ฒฐ. > 4. **Track 3 (๋ฌธ์„œ/์„ค์ • ๋™๊ธฐํ™” P4)**: `MESSAGING.md`, `VERSIONS.md`, `.mam.env` ํ…œํ”Œ๋ฆฟ ๋™๊ธฐํ™”. | ์ˆœ์œ„ | ํ•ญ๋ชฉ | ๊ทผ๊ฑฐ | ๋น„์šฉ | ์„ ํ–‰ | |---|---|---|---|---| | **P1-1** | **B-14 (F-1)** | ๋ธŒ๋กœ์ปค ๋‹ค์šด ์‹œ `publish_event.py` ์กฐ๊ธฐ ํƒˆ์ถœ๋กœ ์ธํ•œ **65๋ถ„ ๋ฃจํ”„ ์ •์ง€(Hang)** ์›์ฒœ ์ฐจ๋‹จ (`append_event`/`update_job_status` ์„ ํ–‰ ๋ณด์žฅ, G-1 ~ G-4 ํšŒ๊ท€ ๊ฐ€๋“œ) | ์†Œ (1ํŒŒ์ผ) | โ€” | | **P1-2** | **B-15 (C1/F-4)** | ๋ธŒ๋กœ์ปค ๋‹ค์šด ์‹œ `job_subscriber.py` **120์ดˆ ์ง€์—ฐ ์ œ๊ฑฐ** ๋ฐ ์ •์ƒ ์™„๋ฃŒ ์ž‘์—…์˜ **`job_status="error"` ์˜คํŒ์ • ์ฐจ๋‹จ** (๋””์Šคํฌ ํด๋ฐฑ ๋ฐ `rc=3` ๋ถ„๋ฆฌ, G-5 ~ G-10 ํšŒ๊ท€ ๊ฐ€๋“œ) | ์†Œ~์ค‘ (2ํŒŒ์ผ) | B-14 | | **P2-1** | **O-5 (Track 1)** | `nats-server -js` MQTT 3.1.1 ํ˜ธํ™˜์„ฑ ์ŠคํŒŒ์ดํฌ(S-1 ~ S-9 ๋งคํŠธ๋ฆญ์Šค ์‹ค์ธก, S-3 Retained ํ„ฐ๋ฏธ๋„ ์ด๋ฒคํŠธ ๊ด€๋ฌธ) ๋ฐ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํ…œํ”Œ๋ฆฟ ์—ฐ๋™ | ์†Œ (๊ฒฉ๋ฆฌ ์ŠคํŒŒ์ดํฌ) | B-15 | | **P3-1** | **A-2 (Track 2)** | ์›Œํฌ์ŠคํŽ˜์ด์Šค ์ง€๋ฌธ ํ† ํ”ฝ(`mam//jobs/...`) ๋ฐ ๋ฌด์กฐ๊ฑด `auth_token` ๋ฐœ๊ธ‰(G-11)์œผ๋กœ A-2 ๋ณด์•ˆ ๊ฒฐํ•จ ์™„์ „ ์ข…๊ฒฐ | ์ค‘ (3ํŒŒ์ผ) | O-5 (S-3 ํ†ต๊ณผ) | | **P3-2** | **B-16 (F-5)** | ๋งค ์‹คํ–‰ ๋žœ๋ค `client_id` ๋ฐœ๊ธ‰์œผ๋กœ ์ธํ•œ ์˜์† ์„ธ์…˜ ๋ถˆ๊ฐ€ ์ด์Šˆ๋ฅผ B-15 ๋””์Šคํฌ ํด๋ฐฑ ํ‘œ์ค€ํ™”๋กœ ์™„๊ฒฐ | ๊ทน์†Œ | B-15 | | **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 ๋กœ์ง์„ ์‹ธ๊ฒŒ ๋งŒ๋“ฆ **(โœ… ์™„๋ฃŒ โ€” tests/test_a4_adapter_contract.py 3/3 PASS)** | ์ค‘ | B-7 | | **P1-2(๊ณผ๊ฑฐ)** | **B-8** | agy ์ฃผ์ž… ์‹œ `return 0` ์šฐํšŒ ์ œ๊ฑฐ ๋ฐ ์ œ์ถœ ๊ฒ€์ฆ ๋ฃจํ”„ ์ด๊ด€ **(โœ… ์™„๋ฃŒ โ€” tests/test_b8_send_keys_verification.py 1/1 PASS)** | ์†Œ | A-4 M0 | | **P2-1(๊ณผ๊ฑฐ)** | **B-6 / B-12** | ์Šคํ‚ฌ ํŠธ๋ฆฌ ๋‚ด ์ž„์‹œ ์‚ฌ๋ณธ ๋ฐ ์„œ๋ธŒ์…ธ EXIT ํŠธ๋žฉ์œผ๋กœ ์ธํ•œ ๋ฃจํ”„ ๋ฝ ์กฐ๊ธฐ ํ•ด์ œ ์ฐจ๋‹จ **(โœ… ์™„๋ฃŒ โ€” tests/test_o3_scoped_guard.py 27/27 PASS, commit b490713)** | ์†Œ | โ€” | | **P2-2(๊ณผ๊ฑฐ)** | **C-3a + C-4** | ๋นˆ ์Šคํ… 4์ข… + ๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 4๊ฑด + ์ฃฝ์€ ์‹ฌ๋ณผ 3์ข… ์ œ๊ฑฐ ๋ฐ `--isolate` no-op ํšŒ๊ท€ ๊ฐ€๋“œ ์‹ ์„ค **(โœ… ์™„๋ฃŒ โ€” tests/test_tier1_unit.py + test_tier2_component.py 256/256 PASS)** | ์†Œ | โ€” | | **P2-3(๊ณผ๊ฑฐ)** | **C-6** | `stop_session.sh` ํ—ค๋”/๋„์›€๋ง/์ฃผ์„/MESSAGING.md ์ •๋ฆฌ ๋ฐ ํšŒ๊ท€ ๊ฐ€๋“œ ์‹ ์„ค **(โœ… ์™„๋ฃŒ โ€” tests/test_tier2_component.py ๊ฐ€๋“œ ์‹ ์„ค, ์ „์ฒด 263/263 PASS)** | ๊ทน์†Œ | โ€” | | **P3-1(๊ณผ๊ฑฐ)** | **A-4 M2~M7** | ์–ด๋Œ‘ํ„ฐ ๋ณธ์ด๊ด€ ๋ฐ CLI facts ๋ธŒ๋ฆฌ์ง€/์„œ๋ธŒ์ปค๋งจ๋“œ ๊ตฌ์ถ• **(โœ… ์™„๋ฃŒ โ€” tests/test_a4_adapter_contract.py 9/9 PASS, ์ „์ฒด 259/259 PASS)** | ๋Œ€ | P1-1 | | **P3-2(๊ณผ๊ฑฐ)** | **B-10** | tier-3 ์‹ ์› ์บ์‹œ ์™„์ „ ์ œ๊ฑฐ ๋ฐ UUID ๊ฒฝ๋กœ PyYAML ํƒˆ์˜์กด (Option A) **(โœ… ์™„๋ฃŒ โ€” tests/test_tier1_unit.py ๊ฐ€๋“œ 3๊ฑด ์‹ ์„ค, ์ „์ฒด 266/266 PASS)** | ์ค‘ | A-4 M2 | | **P3-3(๊ณผ๊ฑฐ)** | **C-3b** | `isolation.root` 4๊ฐœ ์†Œ๋น„์ž ์™„์ „ ํ๊ธฐ (Option B ์ฑ„ํƒ) **(โœ… ์™„๋ฃŒ โ€” ์ „์ฒด 259/259 PASS)** | ์†Œ | A-4 M2 | | **B-13** | **Stage 2** | ์…€ํ”„ ํ˜ธ์ŠคํŒ… ๋ฃจํ”„ ๋Ÿฐํƒ€์ž„ ํ”„๋ฆฌ์ฆˆ ์Šค๋ƒ…์ƒท ๋ฐ ์ด์ค‘ ๋ฃจํŠธ ๊ฒฉ๋ฆฌ **(โœ… ์™„๋ฃŒ โ€” tests/test_o3_scoped_guard.py 5๊ฑด ๊ฐ€๋“œ ์‹ ์„ค, ์ „์ฒด 271/271 PASS)** | ์ค‘ | โ€” | | **P4-1(๊ณผ๊ฑฐ)** | **B-9** | ๊ฐ์‚ฌ ๋กœ๊ทธ ๋ฃจํŠธ ์ง€์—ฐ ํ‰๊ฐ€ ๋ฐ `__getattr__`/`__dir__` ๋™์  ๋ณ„์นญ **(โœ… ์™„๋ฃŒ โ€” tests/test_tier1_unit.py 5๊ฑด ๊ฐ€๋“œ ์‹ ์„ค, ์ „์ฒด 276/276 PASS)** | ๊ทน์†Œ | โ€” | | **์ข…๊ฒฐ** | **B-5** | `df -P` ํด๋ฐฑ ์ •์ƒ ๋™์ž‘ ์‹ค์ธก ๋ฐ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๊ฒ€์ฆ ์™„๋ฃŒ **(โœ… ์™„๋ฃŒ/์ข…๊ฒฐ โ€” tests/test_tier1_unit.py test_stop_check_is_nfs_local)** | โ€” | โ€” | **์ •๋ฆฌ(C ๊ณ„์—ด)๋ฅผ ๊ณผ๊ฑฐ P2 ์— ๋‘์—ˆ๋˜ ์ด์œ **: (a) C-3a ๋Š” ์ฃฝ์€ ์ฝ”๋“œ๋ฅผ ๊ณ ์ •ํ•˜๋˜ ํ…Œ์ŠคํŠธ๋ฅผ ํ•จ๊ป˜ ์ œ๊ฑฐํ•ด C-3a ๋ฅผ ์‹คํ–‰ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , (b) C-4 ๋Š” **์ž˜๋ชป ์‹คํ–‰ํ•˜๋ฉด ๋ฒ„๊ทธ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค**. ๋ฐฉ์น˜ํ• ์ˆ˜๋ก ๋ˆ„๊ตฐ๊ฐ€ "์‰ฌ์šด ์ •๋ฆฌ"๋กœ ์ง‘์–ด ๋“ค ํ™•๋ฅ ์ด ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค. ### 6.3 ๋ณ‘๋ ฌ ์‹คํ–‰ โ€” ํŒŒ์ผ ์†Œ์œ ๊ถŒ ์Šฌ๋กฏ (Rev.3 ๊ฐฑ์‹ ) > ๋ณ‘๋ ฌ ๋‹จ์œ„๋Š” **์ฃผ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ํŒŒ์ผ**์ž…๋‹ˆ๋‹ค. **ํ•ญ๋ชฉ๋ณ„ ์ฒ˜๋ฐฉ์ด ๊ฑด๋“œ๋ฆฌ๋Š” ํŒŒ์ผ** | ํŒŒ์ผ | ๊ฑด๋“œ๋ฆฌ๋Š” ํ•ญ๋ชฉ | |---|---| | `publish_event.py` | **B-14** | | `job_subscriber.py` | **B-15** | | `multi-agent-mux-delegate-job` | **B-15** | | `mqtt_common.py` | **A-2, B-9, B-16** | | `registry.py` | **A-2, B-14, C-4** | | `reconcile.sh` | **A-2, A-4, B-10** | | `.mam.env` / `MESSAGING.md` | **O-5, A-2** | | `run_loop.sh` | **B-6, B-7, O-2** | | `lib.sh` | **A-4, B-8, B-10, C-3a, C-4** | | `stop_session.sh` | **B-10, C-6** | | `create_session.sh` | **A-4, C-4** | **์Šฌ๋กฏ ๋ฐฐ์น˜ โ€” ์Šฌ๋กฏ ์•ˆ์€ ์ง๋ ฌ, ์Šฌ๋กฏ ๊ฐ„์€ ๋ณ‘๋ ฌ** | ์Šฌ๋กฏ | ์ˆœ์„œ | |---|---| | **Track 0 ๋ฐœํ–‰์ž/๊ตฌ๋…์ž ์Šฌ๋กฏ** (`publish_event.py`ยท`job_subscriber.py`ยท`delegate-job`) | `B-14` โ†’ `B-15` | | **Track 1 ๋ธŒ๋กœ์ปค ์ŠคํŒŒ์ดํฌ ์Šฌ๋กฏ** (๊ฒฉ๋ฆฌ ํ™˜๊ฒฝ `$SCRATCH/nats-spike`) | `O-5` (S-1 ~ S-9) | | **Track 2 ๋ณด์•ˆ/๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์Šฌ๋กฏ** (`mqtt_common.py`ยท`registry.py`ยท`reconcile.sh`) | `A-2` โ†’ `B-16` | | **`run_loop.sh` ์Šฌ๋กฏ** | `B-7` โ†’ `O-2` โ†’ `B-6` (์™„๋ฃŒ) | | **`lib.sh` ์Šฌ๋กฏ** | `C-3a`+`C-4` โ†’ `B-8` (์™„๋ฃŒ) | | **`stop_session.sh` ์Šฌ๋กฏ** | `C-6` (์™„๋ฃŒ) | | **๋‹จ๋… ์‹คํ–‰** (์Šฌ๋กฏ ๊ฒฝ๊ณ„๋ฅผ ๋„˜์Œ) | `A-4`, `B-10` (์™„๋ฃŒ) | --- ### 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์ข… ๋นˆ ์Šคํ… ๋ฐ ์ด๋ฅผ ๊ณ ์ •ํ•˜๋˜ ๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 4๊ฑด์„ ์ œ๊ฑฐํ•˜๊ณ  `--isolate`/`--no-isolate` no-op ํšŒ๊ท€ ๊ฐ€๋“œ๋กœ ๋Œ€์ฒดํ–ˆ์Šต๋‹ˆ๋‹ค. - **C-3b (โœ… ์™„๋ฃŒ โ€” P3-1 / Option B)**: `isolation.root` 4๊ฐœ ์†Œ๋น„์ž(`lib.sh` `verify_session_uuid` ์˜ `iso_root` ๋ถ„๊ธฐ, `mam_session_iso_root`, `find_workspace_uuid` ๊ฒฉ๋ฆฌ ๋ถ„๊ธฐ, `stop_session.sh:277` purge ๊ฐ€๋“œ ๋ฐ `atomic_yaml.py:30-33` ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ)๋ฅผ ์™„์ „ํžˆ ํ๊ธฐํ•˜๊ณ  Universal Global Config ๋ฐ ์–ด๋Œ‘ํ„ฐ ๊ธฐ๋ฐ˜ ๋‹จ์ผ ๊ฒฝ๋กœ๋กœ ์ด๊ด€ํ–ˆ์Šต๋‹ˆ๋‹ค. 2. **C-4 (โœ… ์™„๋ฃŒ)**: - `_HERDR_SHIM_DIR_PATTERN` โ€” **์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค** (`lib.sh:83` ์ •์˜, `lib.sh:105` ์‚ฌ์šฉ). ๋ชฉ๋ก๋Œ€๋กœ ์ง€์šฐ๋ฉด 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` ๋Š” ๋‚จ์€ ๋ฐฑ๋กœ๊ทธ ํ•ญ๋ชฉ(์•„ํ‚คํ…์ฒ˜ 1๊ฑด: `A-2`, ์—ฃ์ง€์ผ€์ด์Šค ๋ฐ ๊ฐ€์šฉ์„ฑ 3๊ฑด: `B-16`ยท`B-17`ยท`B-18`, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ 1๊ฑด: `O-5` โ€” ์ด 5๊ฑด)์„ ์œ„ ์šฐ์„ ์ˆœ์œ„(Track 0 โ†’ Track 1 โ†’ Track 2)์— ๋”ฐ๋ผ ์ผ์›ํ™”๋œ ๋ณด์™„ ๋กœ๋“œ๋งต์œผ๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.