# ๐Ÿ” Review Report โ€” PR #37 ๋ณ‘ํ•ฉ ์ „ ๋…๋ฆฝ ๋ฆฌ๋ทฐ (job `4ab12ae2`) - **Reviewer**: `planner-reviewer-claude-01` (role: planner,reviewer) ยท 2026-09-24 - **๋Œ€์ƒ**: PR #37 `fix/issue-36` **@ `59be1c8`**, base `main 1debc7d` (v4.7.2). 6์ปค๋ฐ‹, 11ํŒŒ์ผ `+765/โˆ’30`, `git diff --check` ํด๋ฆฐ. - **๊ฒ€์ฆ ๊ฒฝ๋กœ**: `/var/folders/.../T/mam-review/loop-20260924T080014Z-2b3df0/1`. **identity ํ™•์ธ**: `HEAD = 59be1c89โ€ฆcb49`, `HEAD^{tree} = a009c906โ€ฆfab7` โ€” ๋ธŒ๋ฆฌํ”„์™€ ์ผ์น˜. - **์•ˆ์ „ ๊ทœ์น™ ์ค€์ˆ˜**: ๊ฒ€์ฆ ๊ฒฝ๋กœยท์†Œ์Šค ์›ŒํฌํŠธ๋ฆฌ(`multi-agent-mux-wt/pr-37`)ยท๋ณธ ์ฒดํฌ์•„์›ƒ(`main 1debc7d`) ๋ชจ๋‘ ์ˆ˜์ •ยท์ปค๋ฐ‹ยทcheckout ์—†์Œ. ์‹คํ—˜์€ scratchpad ์ž„์‹œ ๋””๋ ‰ํ„ฐ๋ฆฌ(uuid4)์—์„œ๋งŒ(๋ž˜ํผ๋Š” `--dry-run` + `--agent human` + ๋„๋‹ฌ ๋ถˆ๊ฐ€ ๋ธŒ๋กœ์ปค, ๋Ÿฌ๋„ˆ๋Š” in-process ์Šคํ…), pytest ๋Š” `AGENT_PYTHON_BIN` + `--basetemp=<๊ฒ€์ฆ ๊ฒฝ๋กœ ๋ฐ–>`. ์‹ค์ œ herdrยท์„ธ์…˜ยท`.mam`ยท๋ฐ๋ชฌ ์กฐ์ž‘ ์—†์Œ, pushยทmergeยทPR ์ƒํƒœ ๋ณ€๊ฒฝ ์—†์Œ. ## ๊ฒฐ๋ก  ์š”์•ฝ **๋ณ‘ํ•ฉ์„ ๋ง‰์„ ๊ฒฐํ•จ์€ ์—†๋‹ค.** ํ”„๋กฌํ”„ํŠธ๋Š” ๋Ÿฌ๋„ˆยท๋ž˜ํผยทlib.sh ๋„์šฐ๋ฏธยท์˜› ์…ธ ๋Ÿฌ๋„ˆยทcreate ์˜จ๋ณด๋”ฉ ๋‹ค์„ฏ ๊ฒฝ๋กœ ๋ชจ๋‘์—์„œ ํŒŒ์ผ๋กœ ๊ฐ„๋‹ค(`grep -rn -- '--prompt '` ์˜ ์ž”์กด ํ˜ธ์ถœ์€ ์ „๋ถ€ ์…ธ **ํ•จ์ˆ˜** ์ธ์ž์ด๊ฑฐ๋‚˜ ๋ฌธ์„œ/๊ธฐ๋ณธ๊ฐ’์ด๋‹ค). ๋น„์ฐจ๋‹จ ์ง€์  4๊ฑด(H1โ€“H4). ๊ทธ์ค‘ **H1 ์€ ์žฌํ˜„ํ•œ ์‹ค์ œ ๊ฒฐํ•จ**์ด๋‹ค: ํŒŒ์ด์ฌ ๋Ÿฌ๋„ˆ๋Š” ํ”„๋กฌํ”„ํŠธ ํŒŒ์ผ **์“ฐ๊ธฐ**๊ฐ€ ์‹คํŒจํ•˜๋ฉด(ENOSPC ๋“ฑ) ๋ถ€๋ถ„ ํŒŒ์ผ์„ `.mam` ์— ๋‚จ๊ธฐ๊ณ  ์˜ˆ์™ธ๋ฅผ ๊ทธ๋Œ€๋กœ ๋˜์ง„๋‹ค โ€” PR ์ด ์…ธ ์ชฝ ๋‘ ๊ณณ์—์„œ ๊ณ ์นœ ๋ฐ”๋กœ ๊ทธ ๋ถ€๋ฅ˜๊ฐ€ ๋Ÿฌ๋„ˆ์—๋Š” ๋น ์ ธ ์žˆ๋‹ค. ๋””์Šคํฌ ๊ณ ๊ฐˆ ๊ธ‰์˜ ๊ฒฝ๊ณ„ ์ƒํ™ฉ์ด๋ผ ์ฐจ๋‹จ์œผ๋กœ ๋ณด์ง€ ์•Š์•˜์ง€๋งŒ, ๋ฆด๋ฆฌ์Šค ์ปค๋ฐ‹์ด๋‚˜ ์ฆ‰์‹œ ํ›„์†์—์„œ ์„ธ ์ค„๋กœ ๋‹ซ์„ ๊ฒƒ์„ ๊ถŒํ•œ๋‹ค. ## 1. ์ „๋‹ฌ ๊ฒฝ๋กœ์˜ ์™„์ „์„ฑ (ํ•ญ๋ชฉ 1) | ๊ฒฝ๋กœ | ์ด์ „ | ์ด์ œ | ๊ทผ๊ฑฐ | |---|---|---|---| | ํŒŒ์ด์ฌ ๋Ÿฌ๋„ˆ `_run_cmd` | `--prompt ` argv | `.mam/prompt--XXXX.md` ์— ์“ฐ๊ณ  `--prompt-file` | `runner.py:467-502` | | ๋ž˜ํผ `submit` โ†’ `registry.py register` | `--prompt "$PROMPT"` | ํŒŒ์ผ๋กœ ์™”์œผ๋ฉด `--prompt-file` ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ, ํ…์ŠคํŠธ๋กœ ์™”์œผ๋ฉด ์ข…์ „๋Œ€๋กœ | `multi-agent-mux-delegate-job:186-208` | | ๋ž˜ํผ loop ํƒ€์ž…์˜ ํšŒ์ฐจ `update` | `--prompt "$current_prompt"` | `$job_dir/prompt.md` ์— ์“ฐ๊ณ  `--prompt-file` | `:405-450` | | `lib.sh` `delegate_submit_job` / `_delegate_submit_job_legacy` (์ œ์ถœ ๋„์šฐ๋ฏธ 11๊ณณ์˜ ์ข…์ฐฉ) | argv | `_delegate_prompt_file` ๋กœ `.mam/prompt-submit-XXXXXX` ์— ์“ฐ๊ณ  `--prompt-file`, ์„ฑ๊ณตยท์‹คํŒจ ๋ชจ๋‘ `rm -f` | `lib.sh:2038-2046, 2049-2064, 2160-2174` | | `lib_py/delegation/cli.py submit` | `--prompt` ํ•„์ˆ˜ | `--prompt`/`--prompt-file` ์ƒํ˜ธ ๋ฐฐํƒ€, register ๋กœ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌ | `cli.py:29-33, 64-66` | | ์˜› ์…ธ ๋Ÿฌ๋„ˆ `MAM_LOOP_PY=0` | `delegate_job_safe โ€ฆ --prompt ""` (ํ•จ์ˆ˜ ์ธ์ž) | ํ•จ์ˆ˜ ์•ˆ์—์„œ `--prompt` ๋ฅผ `.mam/prompt-shloop-XXXXXX` + `--prompt-file` ๋กœ ๋ฐ”๊ฟ” ๋ž˜ํผ exec | `run_loop.sh:196-221`. `run_loop.sh` ์˜ ์ž”์กด `--prompt "โ€ฆ"` 11๊ณณ์€ ์ด **ํ•จ์ˆ˜** ํ˜ธ์ถœ์ด๋ผ exec ์„ ๊ฑฐ์น˜์ง€ ์•Š๋Š”๋‹ค | | `create_session.sh --submit-job` | ์ฃผ์ž…๋ฌธ์— ๊ณผ์ œ ๋ณธ๋ฌธ ํฌํ•จ | ๊ณผ์ œ๋Š” `//brief.md` ์— ์“ฐ๊ณ  pane ์—๋Š” **๊ฒฝ๋กœ๋งŒ** | `create_session.sh:625-646` | ### 1-1. ๋ž˜ํผ์˜ ํŒŒ์ผ ์ฒ˜๋ฆฌ (์‹ค์ธก, `--dry-run --agent human`) - ์ƒ๋Œ€ `--prompt-file "my prompts/p 1.md"` ๋Š” **ํ˜ธ์ถœ์ž cwd ๊ธฐ์ค€**์œผ๋กœ ์ ˆ๋Œ€ํ™”๋œ๋‹ค(`:191`, `cd "$WORKDIR"` ์ด์ „) โ€” `--workdir` ๊ฐ€ ๋‹ค๋ฅธ ๊ณณ์ด์–ด๋„ ์ฐพ๋Š”๋‹ค. ์ƒ๋Œ€ `--registry-dir "reg dir"` ๋Š” ์ข…์ „๋Œ€๋กœ `--workdir` ๊ธฐ์ค€์ด๋‹ค(๊ธฐ์กด ์˜๋ฏธ ์œ ์ง€). ๊ณต๋ฐฑ ๊ฒฝ๋กœ ๋ชจ๋‘ ์•ˆ์ „. - ๋“ฑ๋ก๋œ `prompt` ๋Š” **๋ฐ”์ดํŠธ ๋‹จ์œ„๋กœ ๋™์ผ**(`'line1\nline2\n\n'`, ํ›„ํ–‰ ๊ฐœํ–‰ ๋ณด์กด) โ€” registry ๊ฐ€ ํŒŒ์ผ์„ ์ง์ ‘ ์ฝ๊ธฐ ๋•Œ๋ฌธ. ๋ž˜ํผ์˜ `$PROMPT` ๋ณ€์ˆ˜(`$(` ๊ฑฐ๋ถ€. - ์ฝ๋Š” ์‹œ์ : register ๋Š” ๋ž˜ํผ์˜ ์ฒซ ๋‹จ๊ณ„(`:207`)์ด๊ณ  ๋ž˜ํผ๋Š” ์žก์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ๋ธ”๋กํ•˜๋ฏ€๋กœ, ๋Ÿฌ๋„ˆยทlib.shยท์…ธ ๋Ÿฌ๋„ˆ๊ฐ€ **๋ž˜ํผ ๋ฐ˜ํ™˜ ํ›„** ์ง€์šฐ๋Š” ์ˆœ์„œ๋Š” ์•ˆ์ „ํ•˜๋‹ค. ### 1-2. ์ž„์‹œ ํŒŒ์ผ์˜ ์œ„์น˜ยท๊ถŒํ•œยท์ •๋ฆฌ | ์ƒ์„ฑ์ž | ์œ„์น˜ | ๊ถŒํ•œ | ์ •๋ฆฌ | |---|---|---|---| | ๋Ÿฌ๋„ˆ | ์ œ์–ด ๋ฃจํŠธ `.mam/` (`self.mam_dir`) | `NamedTemporaryFile` โ†’ 0600 | `finally: os.unlink` โ€” ์„ฑ๊ณตยท์‹คํŒจยท**OSError(exec ์‹คํŒจ)** ๋ชจ๋‘ (`:498-502`) | | lib.sh | `${WORKSPACE_ROOT}/.mam/` | `mktemp` โ†’ 0600 | ์ œ์ถœ ๋’ค `rm -f`; **์“ฐ๊ธฐ ์‹คํŒจ ์‹œ `rm -f` ํ›„ return 1** (`lib.sh:2042`) | | ์…ธ ๋Ÿฌ๋„ˆ | `$MAM_REAL_ROOT/.mam/` | `mktemp` โ†’ 0600 | ๋ž˜ํผ ๋ฐ˜ํ™˜ ๋’ค `rm -f`; ์“ฐ๊ธฐ ์‹คํŒจ ์‹œ ์ œ๊ฑฐ + ์›์ธ ๋กœ๊ทธ + return 1 (`:201-205`) | | create | `//brief.md` (์žก ๋””๋ ‰ํ„ฐ๋ฆฌ, ๋ณด์กด ๋Œ€์ƒ) | umask | ์‹คํŒจ ์‹œ ์žก `error` + exit 1 (`:632-637`) | ### H1 (๋น„์ฐจ๋‹จ์ด์ง€๋งŒ ์‹ค์ œ ๊ฒฐํ•จ, ์žฌํ˜„) โ€” ๋Ÿฌ๋„ˆ์˜ ์“ฐ๊ธฐ ์‹คํŒจ๋Š” ๋ถ€๋ถ„ ํŒŒ์ผ์„ ๋‚จ๊ธฐ๊ณ  ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค `runner.py:472-477` ์˜ `with NamedTemporaryFile(...) as fh: fh.write(p_text)` ๋Š” `try` **๋ฐ”๊นฅ**์— ์žˆ๋‹ค. ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด์ง„ ๋’ค `write` ๊ฐ€ ์‹คํŒจํ•˜๋ฉด(ENOSPCยทEIO) `finally` ์˜ `unlink` ์— ๋‹ฟ์ง€ ์•Š๋Š”๋‹ค. ๊ฒ€์ฆ ๊ฒฝ๋กœ์˜ ๋Ÿฌ๋„ˆ๋ฅผ in-process ๋กœ ๋„์šฐ๊ณ  `write` ๊ฐ€ `OSError(28)` ์„ ๋‚ด๋„๋ก ๊ฐ์‹ผ ๊ฒฐ๊ณผ: ``` RAISED: OSError [Errno 28] No space left on device โ† delegate_job ๋ฐ–์œผ๋กœ ๊ทธ๋Œ€๋กœ ์ „ํŒŒ(ํŠธ๋ ˆ์ด์Šค๋ฐฑ, 126 ์ฒ˜๋ฆฌ ์•„๋‹˜) leftover prompt files in .mam: ['prompt-loop-โ€ฆ-2ussg8e6.md'] โ† ๋ถ€๋ถ„ ํŒŒ์ผ ์ž”์กด wrapper called: 0 ``` ๊ฐ™์€ ๋ถ€๋ฅ˜๋ฅผ PR ์€ `lib.sh:2042`(`|| { rm -f "$f"; return 1; }`)๊ณผ `run_loop.sh:201-205` ์—์„œ ๊ณ ์ณค๊ณ  S9 ๋กœ ๊ณ ์ •ํ–ˆ์ง€๋งŒ, ๋Ÿฌ๋„ˆ์—๋Š” ๋Œ€์‘์ด ์—†๊ณ  ํ…Œ์ŠคํŠธ(S4/S4b)๋„ `subprocess.run` ์˜ OSError ๋งŒ ๋‹ค๋ฃฌ๋‹ค. ๋ธŒ๋ฆฌํ”„ ํ•ญ๋ชฉ 1 ์˜ "์“ฐ๊ธฐ ์‹คํŒจ ์‹œ ๋ถ€๋ถ„ ํŒŒ์ผ์ด ๋‚จ์ง€ ์•Š๋Š”์ง€"์— ๋Œ€ํ•ด ๋Ÿฌ๋„ˆ๋Š” **์•„๋‹ˆ์˜ค**๋‹ค. โ†’ ๊ถŒ๊ณ : `with` ๋ธ”๋ก์„ `try` ์•ˆ์œผ๋กœ ์˜ฎ๊ธฐ๊ณ  `except OSError` ์—์„œ `unlink` ํ›„ `CompletedProcess(cmd, 126, "", "cannot write the prompt file: โ€ฆ")` ๋ฅผ ๋Œ๋ ค์ฃผ๋ฉด exec ์‹คํŒจ์™€ ๊ฐ™์€ "์‹คํŒจ ์ œ์ถœ" ๊ฒฝ๋กœ๋กœ ํ•ฉ์ณ์ง„๋‹ค(3โ€“4์ค„). `self.mam_dir.mkdir` ์‹คํŒจ๋„ ๊ฐ™์€ ๋ธ”๋ก์—์„œ ์žกํžŒ๋‹ค. ## 2. ์‹คํŒจ ์ฒ˜๋ฆฌ (ํ•ญ๋ชฉ 2) - **exec ์‹คํŒจ(OSError โ†’ rc 126)**: `_run_cmd` ๊ฐ€ `CompletedProcess(cmd, 126, "", "cannot start the wrapper: โ€ฆ (prompt N bytes, wrapper โ€ฆ)")` ๋ฅผ ๋Œ๋ ค์ฃผ๋ฏ€๋กœ ์ฒซ ์‹œ๋„ยทbusy ์žฌ์‹œ๋„ ๋ชจ๋‘ ๊ฐ™์€ "์‹คํŒจ ์ œ์ถœ" ๊ฒฝ๋กœ๋กœ ๋“ค์–ด๊ฐ„๋‹ค. ์žฌ์‹œ๋„ ์‹คํŒจ ์‹œ job id ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ์—๋„ ์ด์ œ `log_error` ๋ฅผ ๋‚จ๊ธด๋‹ค(`runner.py:525`, ์ด์ „์—๋Š” ๋ฌด์–ธ). `failed_submit_jobs` ์ฒ˜๋ฆฌ๋Š” ๋ฐ”๋€Œ์ง€ ์•Š์•˜๋‹ค(id ๊ฐ€ ์žˆ์œผ๋ฉด ๋“ฑ๋ก, ์—†์œผ๋ฉด `None` ๋ฐ˜ํ™˜ โ†’ ํ˜ธ์ถœ์ž๊ฐ€ `return 1`). S4/S4b ๊ฐ€ E2BIGยทEAGAIN ์œผ๋กœ ๊ณ ์ •. - **์žฌ์‹ฌยท์ค‘์žฌ ๋ฏธ๋“ฑ๋ก โ†’ rc 1**: `:1354-1357`, `:1376-1378`. ํŒ์ • ์žก์ด ๋“ฑ๋ก์กฐ์ฐจ ์•ˆ ๋๋Š”๋ฐ "๋ฐ˜๋ก  ๊ธฐ๊ฐ"์ด๋‚˜ "์ค‘์žฌ ์—†์Œ"์œผ๋กœ ํ˜๋Ÿฌ๊ฐ€๋˜ ๊ฒƒ์„ ์‹คํŒจ๋กœ ๋ฐ”๊พผ ๊ฒƒ์ด๋ผ ๋งž๋‹ค. - **์ˆœ์‘(compliance) ์žก `wait_for_job` ์‹คํŒจ โ†’ rc 1** (`:1392-1395`): ์˜๋„๋œ ๊ฐ•ํ™”๋กœ ํŒ๋‹จํ•œ๋‹ค. ๊ทผ๊ฑฐ๋Š” **์ •๊ทœ ์ˆ˜์ • ์žก๊ณผ์˜ ๋Œ€์นญ**์ด๋‹ค โ€” ์ผ๋ฐ˜ correction ์žก๋„ `if not correct_jid or not self.wait_for_job(correct_jid): return 1` (`:1323-1326`) ๋กœ ๋๋‚œ๋‹ค. ์ˆœ์‘ ์žก์€ "๋ฐ˜๋ก ์ด ๊ธฐ๊ฐ๋์œผ๋‹ˆ ๊ทธ๋Œ€๋กœ ๊ณ ์ณ๋ผ"๋Š” ์ˆ˜์ • ์žก์˜ ๋ณ€ํ˜•์ด๋ฏ€๋กœ, ์‹œ๊ฐ„ ์ดˆ๊ณผยท์—๋Ÿฌ๋กœ ๋‹ซํžŒ ์žก์„ ๋‘๊ณ  ๋‹ค์Œ ๋ฆฌ๋ทฐ ๋ผ์šด๋“œ๋กœ ๊ฐ€๋ฉด **๋ฐ”๋€Œ์ง€ ์•Š์€ ํŠธ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๋ฆฌ๋ทฐ**ํ•˜๊ฒŒ ๋œ๋‹ค. ๋ฃจํ”„๊ฐ€ `wait_for_job` ์‹คํŒจ๋ฅผ ํ†ต๊ณผ์‹œํ‚ค๋Š” ์ž๋ฆฌ๋Š” ์ด์ œ self-review(`:1187`)๋ฟ์ด๊ณ  ๊ทธ๊ฒƒ์€ ํŒ์ • ๋ฆฌํฌํŠธ๋กœ ๋”ฐ๋กœ ๊ฑธ๋Ÿฌ์ง„๋‹ค. S3c ๊ฐ€ ์„ธ ๊ฒฝ๋กœ(comply/adjudication/arbitration)์˜ ๋ฏธ๋“ฑ๋ก์„ ๊ณ ์ •ํ•œ๋‹ค. ## 3. `MAM_DIFF_MAX_BYTES`/`MAM_DIFF_MAX_LINES` (ํ•ญ๋ชฉ 3) - `diff_collect.sh:9-11` ์ฃผ์„์ด "์ฆ๊ฑฐ ํฌ๊ธฐ์˜ ์ƒํ•œ์ด์ง€ ์ „๋‹ฌ ์ƒํ•œ์ด ์•„๋‹ˆ๋‹ค"๋ฅผ ๋ช…์‹œํ•˜๊ณ , ์ƒํ•œ๊ฐ’ยท์ž˜๋ฆผ ๋งˆ์ปคยท`runner.py` ์˜ l15 ๊ทœ์น™(์ž˜๋ฆฐ diff ๋ฉด diff-only ์›๊ฒฉ ๋ฆฌ๋ทฐ์–ด ๊ฑฐ๋ถ€, ๋กœ์ปฌ ์ง„ํ–‰)์€ **๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค**(runner ์˜ ํ•ด๋‹น ๋ธ”๋ก์€ diff ๋ฐ–). S5 ๊ฐ€ "์˜› ์‚ฌ๊ฐ์ง€๋Œ€"(131,072 < diff < 200,000 ๋ฐ”์ดํŠธ)์˜ diff ๊ฐ€ ํ†ต์งธ๋กœ ์ „๋‹ฌ๋จ์„ ๊ณ ์ •ํ•œ๋‹ค. - **H2 (๋น„์ฐจ๋‹จ, ๋ฌธ์„œ)**: loop SKILL.md ์—๋Š” ์ด ๋‘ ๋ณ€์ˆ˜๋„, ์ž˜๋ฆผ ๋งˆ์ปค์˜ ์˜๋ฏธ๋„ ์ ํ˜€ ์žˆ์ง€ ์•Š๋‹ค(grep 0๊ฑด). delegate-job SKILL.md ๋Š” argv ์ƒํ•œ๋งŒ ๋งํ•œ๋‹ค. "์ „๋‹ฌ์€ ๋ฌด์ œํ•œ, ์ฆ๊ฑฐ๋Š” 200 KB/4,000 ์ค„์—์„œ ์ž˜๋ฆฌ๋ฉฐ ์ž˜๋ฆฐ diff ๋Š” diff-only ์›๊ฒฉ ๋ฆฌ๋ทฐ์–ด์—๊ฒŒ ์ฆ๊ฑฐ๊ฐ€ ๋ชป ๋œ๋‹ค"๋Š” ํ•œ ๋ฌธ๋‹จ์ด loop SKILL.md ์— ์žˆ์–ด์•ผ ํ•ญ๋ชฉ 3 ์˜ "์ผ๊ด€ ๋ฐ˜์˜"์ด ์™„์„ฑ๋œ๋‹ค. ## 4. `create_session.sh` (ํ•ญ๋ชฉ 4) - ์žก ๋“ฑ๋ก์€ ์ข…์ „๋Œ€๋กœ lib.sh ์˜ `delegate_submit_job`(ํŒŒ์ผ ๊ฒฝ์œ )์ด๊ณ , ๊ทธ ๋’ค `//brief.md` ์— ๊ณผ์ œ๋ฅผ ์“ฐ๊ณ  pane ์—๋Š” `Task: read the complete task in <์ ˆ๋Œ€๊ฒฝ๋กœ> and follow it.` ๋งŒ ์ฃผ์ž…ํ•œ๋‹ค(`:625-646`). `$pub`(`delegate_publish_cmd` ์˜ `--expect-dispatch-token`ยท`--attempt-id`)์™€ `started` ๊ธฐ๋ฐ˜ ํŒ์ •์€ **์†๋Œ€์ง€ ์•Š์•˜๋‹ค** โ€” #23 ๊ณ„์•ฝ ์œ ์ง€. S8 ์ด ์ฃผ์ž…๋ฌธ์— brief ๊ฒฝ๋กœ๋Š” ์žˆ๊ณ  ๊ณผ์ œ ๋ณธ๋ฌธ์€ ์—†์Œ, `--expect-dispatch-token`ยท`--event started` ๊ฐ€ ๋‚จ์•„ ์žˆ์Œ์„ ๋‹จ์–ธํ•œ๋‹ค. - ๊ฒฝ๋กœ: `${MAM_JOBS_DIR:-${WORKSPACE_ROOT:-$PWD}/.mam/jobs}` ๋ฅผ ์ ˆ๋Œ€ํ™”ํ•˜๋ฏ€๋กœ ์›ŒํฌํŠธ๋ฆฌ creator(์ œ์–ด ๋ฃจํŠธ ๋ฐ”์ธ๋”ฉ)๋„ ์ž๊ธฐ cwd ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. ๋ž˜ํผ๊ฐ€ ๋งŒ๋“œ๋Š” `brief.md` ์™€ ๊ฐ™์€ ์ž๋ฆฌ๋‹ค. - ์‹คํŒจ ์‹œ ์žก `error` + `JOB_TERMINALIZED=1` + exit 1 โ†’ ๊ธฐ์กด ํŠธ๋žฉ์ด ์„ธ์…˜์„ ๋˜๋Œ๋ฆฐ๋‹ค(์ดˆ๊ธฐํ™” ์‹คํŒจ์™€ ๊ฐ™์€ ์ทจ๊ธ‰). ## 5. ์ƒˆ ํ…Œ์ŠคํŠธ 22๊ฑด (ํ•ญ๋ชฉ 5) - **์‹ค์ œ ๊ฒฝ๋กœ๋ฅผ ์ง€๋‚˜๋Š”๊ฐ€**: S1 ์€ ์‹ค์ œ ๋ž˜ํผ(`bash multi-agent-mux-delegate-job submit --dry-run`)์™€ ์‹ค์ œ `registry.py` ๋กœ 140,000 ๋ฐ”์ดํŠธ๋ฅผ ๋“ฑ๋กํ•ด **๋ฐ”์ดํŠธ ๋‹จ์œ„ ๋™์ผ**์„ ๋‹จ์–ธํ•œ๋‹ค. S2/S3/S3b/S3c ๋Š” `python -m lib_py.loop` ๋ฅผ ํ•˜์œ„ ํ”„๋กœ์„ธ์Šค๋กœ ๋„์šฐ๊ณ  ๊ฐ€์งœ ๋ž˜ํผ๊ฐ€ ๋ฐ›์€ ์ธ์ž๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค. S7/S7b/S9 ๋Š” `run_loop.sh`(MAM_LOOP_PY=0)๋ฅผ ์‹ค์ œ๋กœ ๋ˆ๋‹ค. S8 ์€ mock herdr ์œ„์—์„œ `create_session.sh` ๋ฅผ ์‹ค์ œ๋กœ ๋ˆ๋‹ค. mock ์œผ๋กœ ์šฐํšŒํ•˜๋Š” ๊ฒƒ์€ S4/S4b(`subprocess.run` ์„ OSError ๋กœ ๋Œ€์ฒด โ€” ์ปค๋„ ๋Œ€์‹  ์ฝ”๋“œ ๊ฒฝ๋กœ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๊ฒƒ์ด ๋ชฉ์ )๋ฟ์ด๋‹ค. - **macOS**: `MAX_ARG_STRLEN` ์ด ์—†์–ด ๋‹จ์ผ ์ธ์ž 150 KB ๊ฐ€ ํ†ต๊ณผํ•˜๋ฏ€๋กœ S1b(์Œ์„ฑ ๋Œ€์กฐ๊ตฐ)๋Š” `linux_only` ๋กœ **skip** ๋˜๊ณ , S8 ์˜ `strace` ๊ฒ€์‚ฌ๋Š” Linux ์—์„œ๋งŒ ๋ถ™๋Š”๋‹ค. ์ฆ‰ ์ด ํ˜ธ์ŠคํŠธ์—์„œ ์Šค์œ„ํŠธ๋Š” **์ปค๋„ ์ƒํ•œ์ด ์•„๋‹ˆ๋ผ ์ฝ”๋“œ ๊ฒฝ๋กœ**(ํŒŒ์ผ๋กœ ์ „๋‹ฌ๋๋Š”๊ฐ€)๋ฅผ ๊ฒ€์ฆํ•œ๋‹ค โ€” ๋ธŒ๋ฆฌํ”„์˜ ์šฐ๋ ค ๊ทธ๋Œ€๋กœ์ด๋ฉฐ, ์„ค๊ณ„์ƒ ์˜ณ๋‹ค. ์‹ค์ œ ์ƒํ•œ ์žฌํ˜„์€ Linux CI ๋ชซ. - **๊ฒฉ๋ฆฌ**: `_env()` ๊ฐ€ `HOME`ยท`WORKSPACE_ROOT`ยท`DELEGATE_JOB_LOGS_DIR` ๋ฅผ `tmp_path` ๋กœ, ๋ธŒ๋กœ์ปค๋ฅผ `127.0.0.1:9` ๋กœ ๊ณ ์ •ํ•˜๊ณ  `MAM_JOBS_DIR`/`MAM_REAL_ROOT` ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค. ์‹ค์ œ `.mam`ยทํ™ˆ ์ ‘์ด‰ ์—†์Œ(ยง6 ์‹ค์ธก). - **์ˆ˜์ • ์—†์ด๋Š” ์‹คํŒจํ•˜๋Š”๊ฐ€ โ€” ํ™•์ธํ•จ**: ๊ฒ€์ฆ ๊ฒฝ๋กœ ์‚ฌ๋ณธ์—์„œ PR ์ด ๋ฐ”๊พผ ์†Œ์Šค 8ํŒŒ์ผ์„ `1debc7d` ํŒ์œผ๋กœ ๋˜๋Œ๋ฆฌ๊ณ  ์ƒˆ ํŒŒ์ผ์„ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ **18 failed / 3 passed / 1 skipped(S1b)**. ํ†ต๊ณผ 3๊ฑด์€ ์ •์ • ์ „์—๋„ ์„ฑ๋ฆฝํ•˜๋˜ ๊ฒƒ(๋ž˜ํผ ์‹คํŒจ โ†’ rc 1 ๋“ฑ)์ด๋‹ค. ## 6. ๊ฒ€์ฆ ๊ฒฝ๋กœ์—์„œ์˜ ํ…Œ์ŠคํŠธ ์‹คํ–‰ (ํ•ญ๋ชฉ 5ยท6) ``` tests/test_issue36_prompt_transport.py tests/test_issue5_phase1_delegation.py tests/test_issue14_delivery_ack.py tests/test_loop_cli.py tests/test_issue21_loop_b.py tests/test_issue21_acceptance.py tests/test_issue23_24_startup_path.py tests/test_issue25_plan_reuse.py โ†’ 1 failed, 237 passed, 1 skipped in 422.71s (0:07:02) ``` - **skip 1**: S1b(`linux_only`) โ€” ์„ค๊ณ„๋œ ๊ฒƒ(ยง5). - **failed 1: S9 โ€” ์ฝ”๋“œ ๊ฒฐํ•จ์ด ์•„๋‹ˆ๋ผ ํ…Œ์ŠคํŠธ์˜ macOS ์ด์‹์„ฑ ๋ฌธ์ œ(H5).** S9 ๋Š” `ulimit -f 1` ๋กœ ์“ฐ๊ธฐ๋ฅผ ์‹ค์ œ๋กœ ์‹คํŒจ์‹œํ‚จ ๋’ค ์„ธ ๊ฐ€์ง€๋ฅผ ๋‹จ์–ธํ•œ๋‹ค: rcโ‰ 0, stderr ์— `File too large`, ๋ถ€๋ถ„ ํŒŒ์ผ ์—†์Œ + ์›์ธ ๋ฌธ๊ตฌ. ๊ฐ™์€ ํ•˜๋„ค์Šค๋ฅผ scratchpad ์—์„œ ์ง์ ‘ ๋Œ๋ฆฐ ๊ฒฐ๊ณผ **rc=1, ๋ถ€๋ถ„ ํŒŒ์ผ ์—†์Œ, `delegate_job_safe: cannot write the prompt file` ์ถœ๋ ฅ** โ€” ์ฆ‰ PR ์ด ๊ณ ์นœ ๋™์ž‘(์ œ๊ฑฐ + ์›์ธ ํ‘œ์‹œ)์€ macOS ์—์„œ๋„ ์„ฑ๋ฆฝํ•œ๋‹ค. ์‹คํŒจํ•œ ๊ฒƒ์€ ๋‘ ๋ฒˆ์งธ ๋‹จ์–ธ๋ฟ์ด๋‹ค: macOS ์˜ `/bin/bash` 3.2 ๋Š” `printf` ์˜ ์“ฐ๊ธฐ ์‹คํŒจ์— ๋Œ€ํ•ด `printf: write error: File too large` ๋ฌธ์ž์—ด์„ ๋‚ด์ง€ ์•Š๋Š”๋‹ค(Linux bash 5 ์˜ ํ˜•์‹). `strerror(EFBIG)` ์ž์ฒด๋Š” macOS ์—์„œ๋„ "File too large" ์ด๋ฏ€๋กœ ์ˆœ์ˆ˜ํ•˜๊ฒŒ bash ๋ฒ„์ „ ์ฐจ์ด๋‹ค. S1b ์ฒ˜๋Ÿผ `linux_only` ๋กœ ๋‘๊ฑฐ๋‚˜, ๊ทธ ๋‹จ์–ธ์„ ๋นผ๊ณ  ์›์ธ ๋ฌธ๊ตฌ ๋‹จ์–ธ๋งŒ ๋‚จ๊ธฐ๋ฉด ๋œ๋‹ค. - ๊ธฐ์กด ๊ณ„์•ฝ ์Šค์œ„ํŠธ(issue5 phase1 ์˜ registry CLI ์Šค๋ƒ…์ƒทยทhelp ์บก์ฒ˜, issue14, loop_cli, issue21 loop Bยทacceptance, issue23/24 S7*, issue25)๋Š” **์ „๋ถ€ ํ†ต๊ณผ** โ€” `--prompt` ํ•˜์œ„ ํ˜ธํ™˜๊ณผ ์˜จ๋ณด๋”ฉ ๊ณ„์•ฝ์ด ์œ ์ง€๋œ๋‹ค(ํ•ญ๋ชฉ 4ยท6). ### ๊ฒฉ๋ฆฌยท์œ„์ƒ ์‹ค์ธก | ํ•ญ๋ชฉ | ๊ฒฐ๊ณผ | |---|---| | ์‹ค์ œ `.mam/jobs` / `.mam/delegate_job_logs` ์ „ํ›„ | **์ฐจ์ด 0 / ์ฐจ์ด 0** | | ์‹ค์ œ `.mam` ์˜ `prompt-*` ์ž”์กด | **0** | | ๊ฒ€์ฆ ๊ฒฝ๋กœ `.mam` ์˜ `prompt-*` ์ž”์กด | **0** (๋Ÿฌ๋„ˆยท์…ธ ๋Ÿฌ๋„ˆยทlib.sh ์˜ ์ •๋ฆฌ๊ฐ€ ์‹ค์ œ ์‹คํ–‰์—์„œ๋„ ์„ฑ๋ฆฝ) | | ๊ฒ€์ฆ ๊ฒฝ๋กœ tracked ํŒŒ์ผ | ๋ณ€ํ™” ์—†์Œ(HEAD `59be1c8`), ๋ณธ ์ฒดํฌ์•„์›ƒ `main 1debc7d` | | ์‹คํ–‰ ์‹œ๊ฐ„ | ์ƒˆ ํŒŒ์ผ 22๊ฑด์€ 34 s ์•ˆํŒŽ(๋˜๋Œ๋ฆฐ ์‚ฌ๋ณธ ๊ธฐ์ค€ 34.5 s); ์ „์ฒด 7 ๋ถ„์€ issue14/18 ๊ณ„์—ด์˜ ๋ฒฝ์‹œ๊ณ„ ์‹œํ—˜ ๋ชซ | ## 7. ๋ฌธ์„œ (ํ•ญ๋ชฉ 7) - delegate-job SKILL.md `:44-48`: `--prompt-file` ์˜ ์˜๋ฏธ์™€ argv ์ƒํ•œ, "๋ฃจํ”„๋Š” ํ•ญ์ƒ ํŒŒ์ผ์„ ์“ด๋‹ค" ๋ช…์‹œ โœ“. ๋ž˜ํผ usage(`:112-121`)๋„ ๊ฐฑ์‹  โœ“. - loop SKILL.md `:267`: ํŒŒ์ดํ”„๋ผ์ธ์—์„œ์˜ ์ข…๋ฃŒ ์ฝ”๋“œ(`pipefail`/`PIPESTATUS`) ์•ˆ๋‚ด โœ“. ๊ทธ๋Ÿฌ๋‚˜ `MAM_DIFF_MAX_*` ์˜ ์ƒˆ ์˜๋ฏธ๋Š” ์—†๋‹ค(H2). - `.claude/skills`: ๋ณธ ์ฒดํฌ์•„์›ƒ์˜ ๊ฒƒ์€ git ์— ์ถ”์ ๋˜์ง€ ์•Š๋Š” ๋กœ์ปฌ ์‹ฌ๋งํฌ(`../../.agents/skills/*`)๋ผ ์ž๋™ ๋™๊ธฐํ™”๋œ๋‹ค โ€” ๋ฐฐํฌ ์‚ฌ๋ณธ ์ •ํ•ฉ ๋ฌธ์ œ ์—†์Œ. ## 8. ๋ณ‘ํ•ฉ ์ฐจ๋‹จ ์—ฌ๋ถ€ (ํ•ญ๋ชฉ 8) ๋ฒ„์ „ ๋ฝ์Šคํ… bump ๋ถ€์žฌ(`lib.sh:32` `4.7.2`, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ๊ฐ€ 4.7.3 ์œผ๋กœ ์ฒ˜๋ฆฌ ์˜ˆ์ •) ์™ธ์— **๋ณ‘ํ•ฉ์„ ๋ง‰์„ ๊ฒฐํ•จ์€ ์—†๋‹ค**. ๋‹ค๋งŒ H1 ์€ ๋ฆด๋ฆฌ์Šค ์ปค๋ฐ‹์— ํ•จ๊ป˜ ๋„ฃ๊ฑฐ๋‚˜ ์ฆ‰์‹œ ํ›„์†์œผ๋กœ ๋‹ซ๊ธฐ๋ฅผ ๊ถŒํ•œ๋‹ค โ€” ์…ธ ์ชฝ๊ณผ ๊ฐ™์€ ๋ถ€๋ฅ˜์ด๊ณ  ์ˆ˜์ •์ด ์„ธ ์ค„์ด๋‹ค. | # | ์ง€์  | ์„ฑ๊ฒฉ | ๊ทผ๊ฑฐ | |---|---|---|---| | H1 | ๋Ÿฌ๋„ˆ์˜ ํ”„๋กฌํ”„ํŠธ ํŒŒ์ผ **์“ฐ๊ธฐ** ์‹คํŒจ ์‹œ ๋ถ€๋ถ„ ํŒŒ์ผ ์ž”์กด + ์˜ˆ์™ธ ์ „ํŒŒ(126 ์‹คํŒจ ์ œ์ถœ๋กœ ํ•ฉ๋ฅ˜ํ•˜์ง€ ์•Š์Œ) โ€” ์žฌํ˜„ | ๋น„์ฐจ๋‹จ(๊ฒฝ๊ณ„ ์ƒํ™ฉ), **ํ›„์† ๊ถŒ๊ณ  1์ˆœ์œ„** | `runner.py:472-477` vs `:490-502`; ยง1 H1 | | H2 | `MAM_DIFF_MAX_*` ์˜ "์ฆ๊ฑฐ ์ƒํ•œ, ์ „๋‹ฌ ๋ฌด์ œํ•œ" ์˜๋ฏธ๊ฐ€ loop SKILL.md ์— ์—†์Œ | ๋ฌธ์„œ | `diff_collect.sh:9-11` ์—๋งŒ ์žˆ์Œ | | H3 | ๋ž˜ํผ๋Š” **๋นˆ** `--prompt-file` ์„ ๋ฐ›์•„๋“ค์—ฌ ๋นˆ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋“ฑ๋กํ•œ๋‹ค(์‹ค์ธก) | ์‚ฌ์†Œ | `multi-agent-mux-delegate-job:195` ์˜ `-n "$PROMPT" \|\| -n "$PROMPT_FILE"` | | H4 | ๋ž˜ํผ์˜ `$PROMPT="$(