From ac97550e131d8a11629845b5b5700130b1c357cb Mon Sep 17 00:00:00 2001 From: Godopu Date: Mon, 17 Aug 2026 09:39:21 +0900 Subject: [PATCH] docs: add VERSIONS.md, resolve C-6 stop_session usage/comments drift, and prune LOG.md --- .../plan-73b18819.md | 391 ++++++++++++++++++ .../report-7ddb5350.md | 233 +++++++++++ .../scripts/stop_session.sh | 65 +-- IMPROVEMENTS.md | 20 +- LOG.md | 146 ------- MESSAGING.md | 6 +- VERSIONS.md | 139 +++++++ tests/test_tier2_component.py | 42 ++ 8 files changed, 856 insertions(+), 186 deletions(-) create mode 100644 .agents/reports/canary-projects-multi-agent-mux-creator-claude/plan-73b18819.md create mode 100644 .agents/reports/canary-projects-multi-agent-mux-creator-cline/report-7ddb5350.md delete mode 100644 LOG.md create mode 100644 VERSIONS.md diff --git a/.agents/reports/canary-projects-multi-agent-mux-creator-claude/plan-73b18819.md b/.agents/reports/canary-projects-multi-agent-mux-creator-claude/plan-73b18819.md new file mode 100644 index 0000000..f74bce6 --- /dev/null +++ b/.agents/reports/canary-projects-multi-agent-mux-creator-claude/plan-73b18819.md @@ -0,0 +1,391 @@ +# ๐Ÿ“ ๊ตฌํ˜„ ๊ณ„ํš์„œ Rev.2 โ€” C-6: `stop_session.sh` ๋ ˆ๊ฑฐ์‹œ ์ฃผ์„ ๋ฐ ๊ตฌ๋ฒ„์ „ ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ + +- **Job ID**: `32167a9d` (Rev.1 = `73b18819`) +- **Planner**: claude (session: `herdr:canary-projects-multi-agent-mux-creator-claude`) +- **Role**: Planner (`MULTI_AGENT_RULES.md` ยง1 โ€” ๋ณธ ์ž‘์—…์—์„œ ์ €์žฅ์†Œ ์ฝ”๋“œ 0๊ฑด ์ˆ˜์ •) +- **๋ฐ˜์˜ ๋Œ€์ƒ Challenge**: `8b6b574f` (agy, Worker / Plan Reviewer) โ€” `[VERDICT: PASS WITH CHALLENGE]` +- **๊ธฐ์ค€ ์ปค๋ฐ‹**: `5ed39f8` (`refactor`, ์ž‘์—… ํŠธ๋ฆฌ์— ๋ฏธ์ถ”์  `VERSIONS.md` 1๊ฑด) +- **๋ฐฑ๋กœ๊ทธ ํ•ญ๋ชฉ**: C-6 / ๋กœ๋“œ๋งต P2-3 + +--- + +## 0. ์š”์•ฝ + +**Challenge ๋Š” ํƒ€๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ „๋ฉด ์ˆ˜์šฉํ•ฉ๋‹ˆ๋‹ค.** ๊ฒฉ๋ฆฌ ํด๋ก ์—์„œ ์‹ค์ œ `mam_sandbox` ํ”ฝ์Šค์ฒ˜๋กœ ์‹คํ–‰ํ•ด ์žฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค โ€” Rev.1 ยง4.2-(2) ๋Š” 4๊ฐœ ํ•˜์œ„ ์ผ€์ด์Šค ์ค‘ **3๊ฐœ๊ฐ€ `rc=2` ๋กœ ์‹คํŒจ**ํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. + +๋‹ค๋งŒ Rev.2 ๋Š” ์ฑŒ๋ฆฐ์ €์˜ ๊ถŒ๊ณ ์•ˆ์„ ๊ทธ๋Œ€๋กœ ์ฑ„ํƒํ•˜์ง€ ์•Š๊ณ  **๋‘ ๊ฐ€์ง€๋ฅผ ๋”ํ•ฉ๋‹ˆ๋‹ค**. + +1. ์ฑŒ๋ฆฐ์ € ๊ถŒ๊ณ (`valid_session` ์‚ฌ์šฉ)๋Š” ์ฆ์ƒ์„ ํ•ด์†Œํ•˜์ง€๋งŒ, ๊ฐ€๋“œ๋ฅผ **C-6 ๊ณผ ๋ฌด๊ด€ํ•œ ๋ถˆ๋ณ€์‹**(`:91-100` ์—์ด์ „ํŠธ ์ ‘๋ฏธ์‚ฌ ๋ช…๋ช… ๊ทœ์น™)์— ๊ฒฐํ•ฉ์‹œํ‚ต๋‹ˆ๋‹ค. `rc=2` ๊ฐ€ **5๊ฐ€์ง€ ์„œ๋กœ ๋‹ค๋ฅธ ์›์ธ**์— ๊ณต์œ ๋˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ์ด ์˜คํƒ์˜ ๊ทผ๋ณธ ์›์ธ์ด๋ฏ€๋กœ, Rev.2 ๋Š” ์ข…๋ฃŒ ์ฝ”๋“œ ๋Œ€์‹  **stderr ๋ฉ”์‹œ์ง€๋ฅผ ๋‹จ์–ธ**ํ•ด ์›์ธ ๊ฒฐํ•ฉ ์ž์ฒด๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. +2. ํ™•์ • ๊ฐ€๋“œ๋ฅผ **๋ฎคํ…Œ์ด์…˜์œผ๋กœ ๊ฒ€์ฆํ•˜๋Š” ๊ณผ์ •์—์„œ, ์ฑŒ๋ฆฐ์ €๋„ ์ €๋„ ๋†“์ณค๋˜ ๊ตฌ๋ฉ 1๊ฑด**์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค โ€” Rev.1 ์ด ยง1.1 ์— ๊ฒฐํ•จ์œผ๋กœ ๋“ฑ์žฌํ•œ `usage():41` ์˜ `--agent claude|agy` ๊ณผ์†Œ ํ‘œ๊ธฐ๋ฅผ, Rev.1ยท์ฑŒ๋ฆฐ์ € ์–‘์ชฝ ๊ฐ€๋“œ ๋ชจ๋‘ **ํƒ์ง€ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค**(M3). Rev.2 ์—์„œ ๋‹ซ์•˜์Šต๋‹ˆ๋‹ค. + +| ํ•ญ๋ชฉ | Rev.1 | Rev.2 | +|---|---|---| +| ยง4.2-(2) ์„ธ์…˜๋ช… | `nosuch` (**์˜คํƒ โ€” 3/4 rc=2**) | `test-project-creator-claude` | +| ยง4.2-(2) ๋‹จ์–ธ | `rc != 2` ๋‹จ๋… | **stderr ๋ฉ”์‹œ์ง€ ๋‹จ์–ธ** + `rc != 2` ๋ณด์กฐ | +| `usage()` ์—์ด์ „ํŠธ ๋ชฉ๋ก ๊ฒ€์ฆ | **์—†์Œ (M3 ๊ตฌ๋ฉ)** | **์ถ”๊ฐ€** | +| ๊ฐ€๋“œ ๋ฎคํ…Œ์ด์…˜ ๊ฒ€์ฆ | ๊ณ„ํš๋งŒ ์ œ์‹œ | **3์ข… ์‹ค์ธก ์™„๋ฃŒ** | +| ๋‚˜๋จธ์ง€(ยง1~ยง3, ยง5, ยง7) | โ€” | ๋ณ€๊ฒฝ ์—†์Œ | + +--- + +## 1. Challenge ํŒ์ • โ€” ์ˆ˜์šฉ (์‹ค์ธก ์žฌํ˜„) + +### 1.1 ์ฑŒ๋ฆฐ์ € ์ง€์ ์˜ ์‚ฌ์‹ค ํ™•์ธ + +์ฑŒ๋ฆฐ์ €๊ฐ€ ์ธ์šฉํ•œ ๋ธ”๋ก์€ ์‹ค์žฌํ•ฉ๋‹ˆ๋‹ค. ์ •ํ™•ํ•œ ์œ„์น˜๋Š” **`:91-100`**(์ฑŒ๋ฆฐ์ € ํ‘œ๊ธฐ `:92-100`), `exit 2` ๋Š” **`:98`** ์ž…๋‹ˆ๋‹ค. + +```bash +# stop_session.sh:91-100 +# --agent ๋ฏธ์ง€์ • ์‹œ ์ด๋ฆ„ suffix ๋กœ fallback (P1-F) +if [ -z "$AGENT" ]; then + case "$SESSION_NAME" in + *-creator-claude|*-planner-claude|*-reviewer-claude) AGENT=claude ;; + ... + *) echo "ERROR: cannot infer agent from '$SESSION_NAME'; pass --agent" >&2; exit 2 ;; # :98 + esac +fi +``` + +์ฑŒ๋ฆฐ์ €๊ฐ€ ์ง€์ ํ•œ **์‹คํ–‰ ์ˆœ์„œ๋„ ์ •ํ™•**ํ•ฉ๋‹ˆ๋‹ค. YAML ์กด์žฌ ๊ฒ€์‚ฌ๋Š” `:80`, ์—์ด์ „ํŠธ ์ถ”๋ก ์€ `:91` ์ด๋ฏ€๋กœ ์ถ”๋ก ์ด ๋’ค์— ์˜ต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  `tests/conftest.py:15-52` ์˜ `mam_sandbox` ํ”ฝ์Šค์ฒ˜๋Š” `agent-sessions.yaml` ์„ **์‹ค์ œ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค**(`herdr_sessions: []`). ๋”ฐ๋ผ์„œ `:80` ์€ ํ†ต๊ณผํ•˜๊ณ  `:98` ์— ๋„๋‹ฌํ•ฉ๋‹ˆ๋‹ค โ€” "์ƒŒ๋“œ๋ฐ•์Šค ์ƒํƒœ์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ€ ๋’ค๋ฐ”๋€๋‹ค"๋Š” ์ฑŒ๋ฆฐ์ €์˜ ์šฐ๋ ค๊ฐ€ ์•„๋‹ˆ๋ผ, **๊ฒฐ์ •๋ก ์ ์œผ๋กœ ํ•ญ์ƒ ์‹คํŒจ**ํ•ฉ๋‹ˆ๋‹ค. + +### 1.2 ์‹ค์ธก โ€” ๊ฒฉ๋ฆฌ ํด๋ก  + ์‹ค์ œ `mam_sandbox` ํ”ฝ์Šค์ฒ˜ + +`git clone --local --no-hardlinks` ๋กœ ๋งŒ๋“  ํด๋ก ์— ํ”„๋กœ๋ธŒ ํ…Œ์ŠคํŠธ๋ฅผ ๋„ฃ์–ด ์ธก์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. + +| `--session` | ์ถ”๊ฐ€ ์ธ์ž | rc | stderr ์ฒซ ์ค„ | +|---|---|---|---| +| `nosuch` | `--reason x` | **2** | `cannot infer agent from 'nosuch'` | +| `nosuch` | `--purge-conversation` | **2** | `cannot infer agent from 'nosuch'` | +| `nosuch` | `--yes` | **2** | `cannot infer agent from 'nosuch'` | +| `nosuch` | `--agent hermes` | 1 | `session 'nosuch' not in โ€ฆyaml` | +| `test-project-creator-claude` | `--reason x` | 1 | `session โ€ฆ not in โ€ฆyaml` | +| `test-project-creator-claude` | `--purge-conversation` | 1 | `session โ€ฆ not in โ€ฆyaml` | +| `test-project-creator-claude` | `--yes` | 1 | `session โ€ฆ not in โ€ฆyaml` | +| `test-project-creator-claude` | `--agent hermes` | 1 | `session โ€ฆ not in โ€ฆyaml` | +| `test-project-creator-claude` | `--purge-conversation --yes` | 1 | `session โ€ฆ not in โ€ฆyaml` | + +**Rev.1 ์˜ `assert r.returncode != 2` ๋Š” 4๊ฐœ ์ค‘ 3๊ฐœ์—์„œ ์‹คํŒจ**ํ•ฉ๋‹ˆ๋‹ค(`--agent` ๋ฅผ ์ค€ ์ผ€์ด์Šค๋งŒ ์ถ”๋ก ์„ ๊ฑด๋„ˆ๋›ฐ์–ด ํ†ต๊ณผ). Challenge ํ™•์ •. + +๋ถ€์ˆ˜ ํ™•์ธ: Rev.1 ยง9 ํ•œ๊ณ„์—์„œ "`--purge-conversation` ์„ `--yes` ์—†์ด ํ˜ธ์ถœ ์‹œ rc=1 ์ธ์ง€ rc=3 ์ธ์ง€ ๊ตฌํ˜„ ์‹œ ์‹ค์ธก ํ•„์š”"๋ผ๊ณ  ๋‚จ๊ฒผ๋˜ ํ•ญ๋ชฉ๋„ ํ•ด์†Œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค โ€” **rc=1**(๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์กฐํšŒ๊ฐ€ ํ™•์ธ ํ”„๋กฌํ”„ํŠธ๋ณด๋‹ค ๋จผ์ €)์ž…๋‹ˆ๋‹ค. + +--- + +## 2. ์ฑŒ๋ฆฐ์ € ๊ถŒ๊ณ ์•ˆ ํ‰๊ฐ€ โ€” ์ฑ„ํƒํ•˜๋˜ ๋ณด๊ฐ• + +### 2.1 ๊ถŒ๊ณ ์•ˆ์€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค + +`valid_session = "test-project-creator-claude"` ๋Š” `*-creator-claude` ์— ์ ‘๋ฏธ์‚ฌ ๋งค์นญ๋˜์–ด `AGENT=claude` ๋กœ ์ถ”๋ก ๋˜๊ณ , 4๊ฐœ ์ผ€์ด์Šค ์ „๋ถ€ rc=1 ๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค(์œ„ ํ‘œ ํ•˜๋‹จ 5ํ–‰). **์ธก์ •์œผ๋กœ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.** + +### 2.2 ๊ทธ๋Ÿฌ๋‚˜ ๊ทผ๋ณธ ์›์ธ์€ ์„ธ์…˜๋ช…์ด ์•„๋‹ˆ๋ผ `rc=2` ์˜ ๊ณผ๋ถ€ํ•˜์ž…๋‹ˆ๋‹ค + +`stop_session.sh` ์—์„œ `exit 2` ๋Š” **5๊ณณ**์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. + +| ํ–‰ | ์›์ธ | +|---|---| +| `:67` | ํ์ง€ ํ”Œ๋ž˜๊ทธ(`--mode`/`--capture-id`/`--graceful`) | +| `:70` | `unknown arg` | +| `:76` | `invalid agent type` | +| `:79` | `--session` ๋ˆ„๋ฝ | +| `:98` | **`cannot infer agent`** โ† ์ด๋ฒˆ ์˜คํƒ์˜ ์›์ธ | + +๊ฐ€๋“œ๊ฐ€ ๊ฒ€์ฆํ•˜๋ ค๋Š” ๊ฒƒ์€ ์˜ค์ง `:70` ํ•˜๋‚˜("๋„์›€๋ง์ด ๊ด‘๊ณ ํ•˜๋Š” ํ”Œ๋ž˜๊ทธ๋ฅผ ํŒŒ์„œ๊ฐ€ unknown ์œผ๋กœ ํŠ•๊ธฐ์ง€ ์•Š๋Š”๋‹ค")์ธ๋ฐ, `rc != 2` ๋Š” ๋‚˜๋จธ์ง€ 4๊ฐœ์™€ ๊ตฌ๋ณ„ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ์ฑŒ๋ฆฐ์ €์˜ `valid_session` ์€ `:98` ๋งŒ ํšŒํ”ผํ•  ๋ฟ **`:76`ยท`:79` ๋Š” ์—ฌ์ „ํžˆ ๊ตฌ๋ณ„ํ•˜์ง€ ๋ชปํ•˜๋ฉฐ**, ๋” ๋‚˜์˜๊ฒŒ๋Š” ๊ฐ€๋“œ๋ฅผ `:91-100` ์˜ **์—์ด์ „ํŠธ ์ ‘๋ฏธ์‚ฌ ๋ช…๋ช… ๊ทœ์น™์— ๊ฒฐํ•ฉ**์‹œํ‚ต๋‹ˆ๋‹ค. ํ›—๋‚  ์—ญํ• ๋ช…์ด ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ `creator` ๊ฐ€ ๊ฐœ๋ช…๋˜๋ฉด, C-6 ๊ฐ€๋“œ๊ฐ€ C-6 ๊ณผ ๋ฌด๊ด€ํ•œ ์ด์œ ๋กœ ๊นจ์ง€๊ณ  ์‹คํŒจ ๋ฉ”์‹œ์ง€๋„ C-6 ์„ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. + +### 2.3 Rev.2 ์˜ ๋ณด๊ฐ• โ€” stderr ๋ฉ”์‹œ์ง€ ๋‹จ์–ธ + +```python +assert "unknown arg" not in r.stderr # ํŒŒ์„œ๊ฐ€ ์ด ํ”Œ๋ž˜๊ทธ๋ฅผ ๋ชจ๋ฅธ๋‹ค๊ณ  ํ•˜์ง€ ์•Š์•˜๋‹ค +assert "deprecated" not in r.stderr # ํ์ง€ ํ”Œ๋ž˜๊ทธ๋กœ ์ทจ๊ธ‰ํ•˜์ง€๋„ ์•Š์•˜๋‹ค +assert r.returncode != 2 # (๋ณด์กฐ) ์œ„ ๋‘˜์„ ๋น ์ ธ๋‚˜๊ฐ„ rc=2 ๋„ ์—†๋‹ค +``` + +์ด ๋‹จ์–ธ์€ 5๊ฐœ ์›์ธ ์ค‘ ์ •ํ™•ํžˆ ๊ฒ€์ฆ ๋Œ€์ƒ์ธ ๊ฒƒ๋งŒ ์ง€๋ชฉํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ธก ํ‘œ์—์„œ ํ™•์ธ๋˜๋“ฏ `nosuch` ์ผ€์ด์Šค์˜ stderr ๋Š” `cannot infer agent` ์ด๋ฏ€๋กœ **๋ฉ”์‹œ์ง€ ๋‹จ์–ธ๋งŒ์œผ๋กœ๋Š” ์„ธ์…˜๋ช…์ด ๋ฌด์—‡์ด๋“  ํ†ต๊ณผ**ํ•ฉ๋‹ˆ๋‹ค โ€” ์ฆ‰ ์ฑŒ๋ฆฐ์ € ๊ถŒ๊ณ ๋ณด๋‹ค ์—„๋ฐ€ํžˆ ๋” ๊ฒฌ๊ณ ํ•ฉ๋‹ˆ๋‹ค. + +**๋‘ ๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ์ฑ„ํƒํ•ฉ๋‹ˆ๋‹ค**: ์ฑŒ๋ฆฐ์ €์˜ `valid_session`(์›์ธ ์ œ๊ฑฐ) + ๋ฉ”์‹œ์ง€ ๋‹จ์–ธ(๊ฒฐํ•ฉ ์ œ๊ฑฐ). ์–ด๋А ํ•œ์ชฝ์ด ๋ฏธ๋ž˜์— ๋ฌด๋ ฅํ™”๋ผ๋„ ๋‹ค๋ฅธ ์ชฝ์ด ๋‚จ์Šต๋‹ˆ๋‹ค. + +--- + +## 3. ๐Ÿ†• Rev.2 ์‹ ๊ทœ ๋ฐœ๊ฒฌ โ€” ๊ฐ€๋“œ๊ฐ€ `usage():41` ๊ฒฐํ•จ์„ ๋†“์นจ (M3) + +ํ™•์ • ๊ฐ€๋“œ๋ฅผ ๋ฎคํ…Œ์ด์…˜ ๊ฒ€์ฆํ•˜๋˜ ์ค‘ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. **์ฑŒ๋ฆฐ์ €๋„ Rev.1 ๋„ ์ง€์ ํ•˜์ง€ ๋ชปํ•œ ๊ตฌ๋ฉ์ž…๋‹ˆ๋‹ค.** + +Rev.1 ยง1.1 ์€ `usage():41` ์˜ `[--agent claude|agy]` ๊ฐ€ ๊ฒ€์ฆ๊ธฐ(`:74-77`)์˜ 4์ข… ์ˆ˜์šฉ๊ณผ ์–ด๊ธ‹๋‚œ๋‹ค๊ณ  **๊ฒฐํ•จ์œผ๋กœ ๋“ฑ์žฌ**ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ Rev.1ยท์ฑŒ๋ฆฐ์ € ์–‘์ชฝ ๊ฐ€๋“œ ๋ชจ๋‘ ์ด ๊ฒฐํ•จ์„ ํƒ์ง€ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. + +**๋ฎคํ…Œ์ด์…˜ M3**: ์ˆ˜์ •๋œ ํด๋ก ์—์„œ `usage()` ์˜ ์—์ด์ „ํŠธ ๋ชฉ๋ก๋งŒ `claude|agy` ๋กœ ๋˜๋Œ๋ฆผ + +``` +๊ฒฐ๊ณผ: 1 passed โ† ๊ฐ€๋“œ๊ฐ€ ํ†ต๊ณผ์‹œํ‚ด โŒ +``` + +C-6 ์ด ๊ณ ์น˜๊ธฐ๋กœ ํ•œ ๊ฒฐํ•จ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๊ฐ€๋“œ ๋ฐ–์— ์žˆ์—ˆ๋˜ ์…ˆ์ž…๋‹ˆ๋‹ค. Rev.2 ์—์„œ ๋‹ค์Œ 3์ค„๋กœ ๋‹ซ์•˜์Šต๋‹ˆ๋‹ค. + +```python +for agent in ("claude", "agy", "hermes", "cline"): + assert agent in res.stdout, f"usage() omits supported agent {agent}" +``` + +**์žฌ๊ฒ€์ฆ**: ๊ฐ•ํ™” ํ›„ baseline `1 passed`, M3 ์žฌ์ ์šฉ ์‹œ `1 failed`. ๊ตฌ๋ฉ์ด ๋‹ซํ˜”์Œ์„ ์‹ค์ธกํ–ˆ์Šต๋‹ˆ๋‹ค. + +--- + +## 4. ํ™•์ • ํšŒ๊ท€ ๊ฐ€๋“œ + +### 4.1 ์„ค๊ณ„ ์›์น™ (Rev.1 ยง4.1 ์œ ์ง€) + +์ง์ „ ๋ฆฌ๋ทฐ `31730364` ์—์„œ ๋ฎคํ…Œ์ด์…˜์œผ๋กœ ๋“œ๋Ÿฌ๋‚œ ์‹คํŒจ ์‚ฌ๋ก€ โ€” `test_delegate_agent_resolution_and_fallback` ์ด ํ…Œ์ŠคํŠธ ํŒŒ์ผ ์•ˆ์— `case` ๋ฌธ์„ ๋ณต์‚ฌํ•ด ์‹คํ–‰ํ•œ ํƒ“์— ์ƒ์‚ฐ ์ฝ”๋“œ ๊ฒฐํ•จ์„ ์™„์ „ํžˆ ๋˜๋Œ๋ ค๋„ ํ†ต๊ณผ โ€” ๋ฅผ ๋ฐ˜๋ณตํ•˜์ง€ ์•Š๋„๋ก, ๊ฐ€๋“œ๋Š” `stop_session.sh` ๋ฅผ **์ง์ ‘ ์‹คํ–‰ํ•˜๊ณ  ๊ทธ ํŒŒ์ผ์„ ์ง์ ‘ ์ฝ์Šต๋‹ˆ๋‹ค**. + +### 4.2 ํ™•์ • ์ฝ”๋“œ โ€” `tests/test_tier2_component.py` ์— ์ถ”๊ฐ€ + +```python +def test_comp_stop_usage_matches_parser(mam_sandbox): + """C-6: help text and parser must not drift apart.""" + script = mam_sandbox / ".agents" / "skills" / "multi-agent-mux-stop" / "scripts" / "stop_session.sh" + + # ์—์ด์ „ํŠธ ์ ‘๋ฏธ์‚ฌ ์ถ”๋ก (:91-100)์ด ์„ฑ๋ฆฝํ•˜๋Š” ์ด๋ฆ„ โ€” rc=2 ์˜ ๋‹ค์„ฏ ์›์ธ ์ค‘ + # 'cannot infer agent'(:98)๋ฅผ ๋ฐฐ์ œํ•˜๊ธฐ ์œ„ํ•จ (Challenge 8b6b574f) + VALID = "test-project-creator-claude" + + # 1) --help ๋Š” ์„ฑ๊ณตํ•˜๊ณ , ํ์ง€๋œ ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ด‘๊ณ ํ•˜์ง€ ์•Š๋Š”๋‹ค + res = subprocess.run(["bash", str(script), "--help"], capture_output=True, text=True) + assert res.returncode == 0 + for dead in ("--mode", "--capture-id", "--graceful"): + assert dead not in res.stdout, f"usage() still advertises {dead}" + + # 1b) ๊ฒ€์ฆ๊ธฐ๊ฐ€ ๋ฐ›๋Š” ์—์ด์ „ํŠธ๋Š” ์ „๋ถ€ ๋„์›€๋ง์— ๋‚˜์˜จ๋‹ค (Rev.2 M3) + for agent in ("claude", "agy", "hermes", "cline"): + assert agent in res.stdout, f"usage() omits supported agent {agent}" + + # 2) ๋„์›€๋ง์ด ๊ด‘๊ณ ํ•˜๋Š” ํ”Œ๋ž˜๊ทธ๋Š” ์ „๋ถ€ ํŒŒ์„œ๊ฐ€ ๋ฐ›๋Š”๋‹ค + # rc=2 ๋Š” 5๊ฐ€์ง€ ์›์ธ์„ ๊ณต์œ ํ•˜๋ฏ€๋กœ stderr ๋ฉ”์‹œ์ง€๋กœ ์ง์ ‘ ์ง€๋ชฉํ•œ๋‹ค + for flag, args in (("--reason", ["--reason", "x"]), + ("--purge-conversation", ["--purge-conversation"]), + ("--yes", ["--yes"]), + ("--agent", ["--agent", "hermes"])): + r = subprocess.run(["bash", str(script), "--session", VALID] + args, + capture_output=True, text=True) + assert "unknown arg" not in r.stderr, f"usage() advertises {flag} but parser rejects it: {r.stderr}" + assert "deprecated" not in r.stderr, f"usage() advertises deprecated {flag}: {r.stderr}" + assert r.returncode != 2, f"{flag} -> rc=2: {r.stderr}" + + # 3) ํ์ง€๋œ ํ”Œ๋ž˜๊ทธ๋Š” ์ „์šฉ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ rc=2 ๋กœ ๊ฑฐ๋ถ€๋œ๋‹ค (ํŠน๋ณ„ ์ทจ๊ธ‰ ์œ ์ง€) + for dead in ("--mode", "--capture-id", "--graceful"): + r = subprocess.run(["bash", str(script), "--session", VALID, dead, "hard"], + capture_output=True, text=True) + assert r.returncode == 2 + assert "deprecated" in r.stderr + + # 4) ํ—ค๋” ์ฃผ์„๋„ ํ์ง€ ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉ๋ฒ•์œผ๋กœ ๊ด‘๊ณ ํ•˜์ง€ ์•Š๋Š”๋‹ค + head = "".join(script.read_text().splitlines(keepends=True)[:35]) + assert "--mode soft|hard" not in head +``` + +### 4.3 ๋ฎคํ…Œ์ด์…˜ ๊ฒ€์ฆ โ€” Rev.2 ์—์„œ ์‹ค์ธก ์™„๋ฃŒ + +Rev.1 ์€ ๋ฎคํ…Œ์ด์…˜์„ "๊ตฌํ˜„์ž ํ•„์ˆ˜ ์ˆ˜ํ–‰"์œผ๋กœ ์ง€์‹œ๋งŒ ํ–ˆ์œผ๋‚˜, Rev.2 ๋Š” **๊ณ„ํš ๋‹จ๊ณ„์—์„œ ์ง์ ‘ ์ˆ˜ํ–‰**ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฉ๋ฆฌ ํด๋ก ์— ยง3 ๋‹จ๊ณ„ 1~2 ์˜ ๋ฌธ์„œ ์ˆ˜์ •์„ ์ ์šฉํ•œ ๋’ค: + +| # | ๋ฎคํ…Œ์ด์…˜ | ๊ธฐ๋Œ€ | ์‹ค์ธก | +|---|---|---|---| +| โ€” | (baseline, ์ˆ˜์ • ์ ์šฉ ์ƒํƒœ) | PASS | **1 passed** โœ… | +| M1 | ํŒŒ์„œ์—์„œ `--reason)` ๋ถ„๊ธฐ ์‚ญ์ œ (๋„์›€๋ง์€ ๊ณ„์† ๊ด‘๊ณ ) | FAIL | **1 failed** โ€” `:19` `unknown arg` ๋‹จ์–ธ โœ… | +| M2 | ํ—ค๋”์— `[--mode soft\|hard]` ํ–‰ ๋ณต์› | FAIL | **1 failed** โ€” `:30` ํ—ค๋” ๋‹จ์–ธ โœ… | +| M3 | `usage()` ์—์ด์ „ํŠธ ๋ชฉ๋ก์„ `claude\|agy` ๋กœ ์ถ•์†Œ | FAIL | ๊ฐ•ํ™” ์ „ **1 passed** โŒ โ†’ ๊ฐ•ํ™” ํ›„ **1 failed** โœ… | + +M1 ์ด ๊ฐ€๋“œ์˜ ํ•ต์‹ฌ ๊ฐ€์น˜๋ฅผ ์ฆ๋ช…ํ•ฉ๋‹ˆ๋‹ค โ€” **๋„์›€๋ง๊ณผ ํŒŒ์„œ ์ค‘ ํ•œ์ชฝ๋งŒ ๋ฐ”๋€Œ๋ฉด ์ฆ‰์‹œ ์‹คํŒจ**ํ•˜๋ฉฐ, ์ด๊ฒƒ์ด C-6 ์„ ์• ์ดˆ์— ๋งŒ๋“  ๋“œ๋ฆฌํ”„ํŠธ์ž…๋‹ˆ๋‹ค. + +๊ตฌํ˜„์ž๋Š” ์œ„ ํ‘œ๋ฅผ **์žฌํ˜„**๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค(์‹ ๊ทœ ์„ค๊ณ„ ๋ถˆํ•„์š”). + +--- + +## 5. ๊ตฌํ˜„ ๊ณ„ํš (Rev.1 ๋Œ€๋น„ ๋ณ€๊ฒฝ ์—†์Œ) + +### ๋‹จ๊ณ„ 1 โ€” ํ—ค๋” ์ฃผ์„ ๊ต์ฒด (`:2-30`, 29์ค„) + +```bash +# stop_session.sh โ€” multi-agent-mux-stop ์˜ ๋ถ€์† ์Šคํฌ๋ฆฝํŠธ +# Usage: +# bash stop_session.sh --session [--agent claude|agy|hermes|cline] \ +# [--reason ] [--purge-conversation] [--yes] +# +# ๋™์ž‘: ํ•ญ์ƒ graceful stop ์ž…๋‹ˆ๋‹ค. send-keys ๋กœ ์ •์ƒ ์ข…๋ฃŒ๋ฅผ ์œ ๋„ํ•˜๊ณ  +# (๋ฏธ์ข…๋ฃŒ ์‹œ SIGTERM โ†’ SIGKILL ํด๋ฐฑ), kill ์ง์ „์— ์ด ์›Œํฌ์ŠคํŽ˜์ด์Šค์˜ +# conversation id ๋ฅผ row ์— ํ™•์ • ๊ธฐ๋กํ•ด ๋‹ค์Œ resume ์ด tier-1(race-free) +# ์œผ๋กœ ๋ณต์›๋˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. status ๋Š” running -> stopped ๋กœ ์ „์ดํ•ฉ๋‹ˆ๋‹ค. +# ๋ฉฑ๋“ฑ: ์ด๋ฏธ stopped ๋ฉด no-op + exit 0. +# +# ์˜ต์…˜: +# --session โ€” ๋Œ€์ƒ ์„ธ์…˜ (ํ•„์ˆ˜) +# --agent โ€” claude | agy | hermes | cline +# (๋ฏธ์ง€์ • ์‹œ ์„ธ์…˜๋ช… ์ ‘๋ฏธ์‚ฌ๋กœ ์ถ”๋ก ; ์ถ”๋ก  ์‹คํŒจ ์‹œ exit 2) +# --reason โ€” ์ƒํƒœ ์ „์ด ์‚ฌ์œ  (stop_reason). ๊ธฐ๋ณธ๊ฐ’ manual_stop +# --purge-conversation โ€” ๋””์Šคํฌ์˜ conversation artifact ๊นŒ์ง€ ์‚ญ์ œ. +# status=terminated, resumable=false ๋กœ ์ „์ดํ•˜๋ฉฐ +# resume ๋ถˆ๊ฐ€. --yes ์—†์ด๋Š” ํ™•์ธ ํ”„๋กฌํ”„ํŠธ(exit 3) +# --yes โ€” --purge-conversation ์˜ ํ™•์ธ ํ”„๋กฌํ”„ํŠธ ์ƒ๋žต +# +# ํ์ง€๋œ ์˜ต์…˜: --mode / --capture-id / --graceful ๋Š” ๊ฐ๊ฐ exit 2 ๋กœ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค. +# graceful ์ข…๋ฃŒ์™€ id ์บก์ฒ˜๋Š” ์ด์ œ ๋ฌด์กฐ๊ฑด ์ˆ˜ํ–‰๋˜๋ฉฐ, soft/hard ๋ชจ๋“œ +# ๊ตฌ๋ถ„์€ --purge-conversation ์œ ๋ฌด๋กœ ๋Œ€์ฒด๋˜์—ˆ์Šต๋‹ˆ๋‹ค. +# +# Exit codes: +# 0 = success (or already-stopped no-op) | 1 = YAML not found / not registered +# 2 = invalid args | 3 = interactive confirmation required (--yes ๋ˆ„๋ฝ) +# 4 = purge aborted (herdr session survived the kill chain) +``` + +> **Rev.2 ์ถ”๊ฐ€**: `--agent` ํ•ญ๋ชฉ์— ์ ‘๋ฏธ์‚ฌ ์ถ”๋ก  ๋™์ž‘(`:91-100`)์„ ํ•œ ์ค„ ๋ช…๊ธฐํ•ฉ๋‹ˆ๋‹ค. Challenge ๊ฐ€ ๋“œ๋Ÿฌ๋ƒˆ๋“ฏ ์ด ๋™์ž‘์€ ๋ฌธ์„œํ™”๋˜์–ด ์žˆ์ง€ ์•Š์•„ ๊ณ„ํš์žยท๋ฆฌ๋ทฐ์–ด ์–‘์ชฝ์ด ๋†“์ณค๋˜ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. C-6 ์˜ ์ทจ์ง€("๋ฌธ์„œ๊ฐ€ ์‹ค์ œ ๋™์ž‘๊ณผ ์ผ์น˜ํ•  ๊ฒƒ")์— ์ •ํ™•ํžˆ ๋ถ€ํ•ฉํ•ฉ๋‹ˆ๋‹ค. + +### ๋‹จ๊ณ„ 2 โ€” `usage()` ๋ณด๊ฐ• (`:39-47`) + +```bash +usage() { + cat < [--agent claude|agy|hermes|cline] [--reason ] + [--purge-conversation] [--yes] + +Arguments: + --session โ€” target session name (required) + --agent โ€” claude | agy | hermes | cline + (inferred from the session-name suffix when omitted) + --reason โ€” stop_reason field (default: manual_stop) + --purge-conversation โ€” also delete on-disk conversation artifacts; + status becomes terminated and resume is impossible + --yes โ€” skip the --purge-conversation confirmation prompt + +Stop is always graceful and always captures the conversation id. +(idempotent: stopping an already-stopped session is a no-op with exit 0) +EOF +} +``` + +### ๋‹จ๊ณ„ 3 โ€” ๋‚ด๋ถ€ ์ฃผ์„ 3๊ณณ + ๊ฒฝ๊ณ  ๋ฌธ์ž์—ด 1๊ณณ + +| ์œ„์น˜ | ์กฐ์น˜ | +|---|---| +| `:157` | `# --capture-id: kill ์ง์ „์— โ€ฆ` โ†’ `# ์บก์ฒ˜: kill ์ง์ „์— โ€ฆ` | +| `:166` | `WARN: --capture-id requested but no conversation id resolved` โ†’ `WARN: no conversation id resolved before stop (nothing on disk yet)` | +| `:172` | `# --graceful: send-keys ๋กœ โ€ฆ` โ†’ `# graceful ์ข…๋ฃŒ: send-keys ๋กœ โ€ฆ` | +| `:257` | `# --capture-id: ํ•ญ์ƒ captured UUID ๊ธฐ๋ก` โ†’ `# ํ•ญ์ƒ captured UUID ๊ธฐ๋ก (purge ๊ฐ€ ์•„๋‹ ๋•Œ๋งŒ)` | + +### ๋‹จ๊ณ„ 4 โ€” `MESSAGING.md:346-348` + +``` +| `stopped` | stopped via `multi-agent-mux-stop` (default); conversation preserved for resume | `stop` | +| `terminated` | stopped with `--purge-conversation`, or herdr-dead detected; conversation deleted / session gone | `stop --purge-conversation`, `monitor` reconcile | +| `archived` | legacy value โ€” no producer since `--mode soft` was removed; kept in the validation whitelist for rows written by older versions | (none) | +``` + +--- + +## 6. ๋ฌธ์„œ ๋™๊ธฐํ™” (Rev.1 ๋Œ€๋น„ ๋ณ€๊ฒฝ ์—†์Œ) + +### 6.1 `IMPROVEMENTS.md` โ€” 7๊ณณ + +| ํ–‰ | ํ˜„์žฌ | ๋ณ€๊ฒฝ ํ›„ | +|---|---|---| +| `:3` | ์ตœ์ข… ๊ฐฑ์‹ ์ผ `2026-08-16 (P3-1/A-4 โ€ฆ)` | ๋‚ ์งœยท์‚ฌ์œ ์— C-6 ์™„๋ฃŒ ๋ฐ˜์˜ | +| `:5` | ๋ฏธํ•ด๊ฒฐ **6๊ฑด** (โ€ฆ **๋ ˆ๊ฑฐ์‹œ 1**) | ๋ฏธํ•ด๊ฒฐ **5๊ฑด** (โ€ฆ **๋ ˆ๊ฑฐ์‹œ 0**) | +| `:6` | ์™„๋ฃŒ **19๊ฑด** | ์™„๋ฃŒ **20๊ฑด**, ๋ชฉ๋ก์— `C-6` ์ถ”๊ฐ€ | +| `:107` | `## 4. โ€ฆ (Legacy Remnants โ€” 1๊ฑด)` | `โ€ฆ (Legacy Remnants โ€” 0๊ฑด โ€” ์ „์› ์™„๋ฃŒ)` (`:103` ยง3 ํ‘œ๊ธฐ๋ฒ•๊ณผ ๋™์ผ) | +| `:109-110` | C-6 ํ•ญ๋ชฉ | **์‚ญ์ œ** (ยง5 ๋กœ ์ด๋™) | +| `:114` | `## 5. โ€ฆ (Completed Tasks โ€” 19๊ฑด)` | `โ€ฆ (Completed Tasks โ€” 20๊ฑด)` | +| `:253` | `\| **P2-3** \| **C-6** \| ๋„์›€๋ง 3์ค„ ์ •์ • \| ๊ทน์†Œ \| โ€” \|` | `โ€ฆ **(โœ… ์™„๋ฃŒ โ€” ๊ฐ€๋“œ ์‹ ์„ค, ์ „์ฒด 263/263 PASS)** \|` | + +ยง5 ์‹ ๊ทœ ํ•ญ๋ชฉ: + +```markdown +### **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` ๋ฅผ ๋ ˆ๊ฑฐ์‹œ ๊ฐ’์œผ๋กœ ๋ช…๊ธฐํ–ˆ์Šต๋‹ˆ๋‹ค. +- ๋„์›€๋ง๊ณผ ํŒŒ์„œ์˜ ์ผ์น˜๋ฅผ ๊ฐ•์ œํ•˜๋Š” ํšŒ๊ท€ ๊ฐ€๋“œ๋ฅผ ์‹ ์„คํ•˜๊ณ  ๋ฎคํ…Œ์ด์…˜ 3์ข…(M1~M3)์œผ๋กœ ๋ฐฉ์–ด๋ ฅ์„ + ๊ฒ€์ฆํ–ˆ์Šต๋‹ˆ๋‹ค โ€” C-6 ์€ ๋ฌธ์„œ ๊ณผ์ œ๋ผ ๊ธฐ์กด ํ…Œ์ŠคํŠธ๊ฐ€ ์ „ํ˜€ ์žก์ง€ ๋ชปํ•˜๋˜ ์˜์—ญ์ž…๋‹ˆ๋‹ค. +``` + +**์ฃผ์˜**: `:5` ์˜ "๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ 0๊ฑด"๊ณผ `:107` ยง4 ํ—ค๋”๋Š” **๋ฐ˜๋“œ์‹œ ํ•จ๊ป˜** ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. ์ง์ „ 3๋ผ์šด๋“œ ๋ฆฌ๋ทฐ์—์„œ ์ด ์Œ์˜ ๋ถˆ์ผ์น˜๊ฐ€ ๋งค๋ฒˆ ์ง€์ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. + +### 6.2 `LOG.md` + +`## ๐Ÿ“Œ 1. ๊ธˆ์ผ ์ž‘์—… ๋‚ด์šฉ ์š”์•ฝ` ์•„๋ž˜ ๊ธฐ์กด `### 1) P3-1 โ€ฆ` **์•ž์—** ์‹ ๊ทœ ํ•ญ๋ชฉ์„ ์‚ฝ์ž…ํ•˜๊ณ  ๊ธฐ์กด P3-1 ์„ `### 2)` ๋กœ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค. ๋จธ๋ฆฌ๋ง `- **์ตœ์ข… ๊ธฐ๋ก์ผ์‹œ**` ยท `- **์ž‘์—… ์ƒํƒœ**` ๋„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค. + +```markdown +### 1) **C-6 (P2-3): `stop_session.sh` ๋ ˆ๊ฑฐ์‹œ ์ฃผ์„ ๋ฐ ๊ตฌ๋ฒ„์ „ ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ** โ€” **์™„๋ฃŒ** +- **๋ฐฐ๊ฒฝ**: ํ—ค๋” ์ฃผ์„์ด ํ์ง€ ํ”Œ๋ž˜๊ทธ 3์ข…์„ ์‚ฌ์šฉ๋ฒ•์œผ๋กœ ๊ด‘๊ณ ํ–ˆ์œผ๋‚˜ ํŒŒ์„œ๋Š” ์ „์šฉ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ + `exit 2` ๋กœ ๊ฑฐ๋ถ€ํ•˜๊ณ  ์žˆ์—ˆ์Œ(์‹ค์ธก). ๋ฐฑ๋กœ๊ทธ์—๋Š” "๋„์›€๋ง 3์ค„"๋กœ ๋“ฑ์žฌ๋ผ ์žˆ์—ˆ์œผ๋‚˜ ์‹ค์ œ ๋Œ€์ƒ์€ + ํ—ค๋” 29์ค„ + `usage()` + ๋‚ด๋ถ€ ์ฃผ์„ 3๊ณณ + `MESSAGING.md` ์ƒํƒœ ํ‘œ์˜€์Œ. +- **์ฃผ์š” ๊ตฌํ˜„**: (ํŒŒ์ผ๋ณ„ ๋ณ€๊ฒฝ ์š”์•ฝ) +- **๊ฒ€์ฆ**: `pytest` 263/263 PASS. ์‹ ๊ทœ ๊ฐ€๋“œ์— ๋Œ€ํ•ด ๋ฎคํ…Œ์ด์…˜ M1~M3 ์ „๋ถ€ FAIL ํ™•์ธ. +``` + +--- + +## 7. `archived` ์‚ฌ๋ฌธ ์ƒํƒœ๊ฐ’ โ€” Option A ํ™•์ • + +Rev.1 ยง7 ์—์„œ ํŒ๋‹จ์„ ์š”์ฒญํ–ˆ๊ณ  **์ฑŒ๋ฆฐ์ €๊ฐ€ ยง4-3 ์—์„œ Option A ์— ์ „์ ์œผ๋กœ ๋™์˜**ํ–ˆ์œผ๋ฏ€๋กœ ํ™•์ •ํ•ฉ๋‹ˆ๋‹ค. + +- **A. ํ˜„์ƒ ์œ ์ง€ + ๋ฌธ์„œ ๋ช…๊ธฐ** โ€” `atomic_yaml.py:18` ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ์™€ `reconcile.sh:474` ๊ด€์šฉ ๋ชฉ๋ก์€ ์†๋Œ€์ง€ ์•Š๊ณ , `MESSAGING.md` ์— "๋ ˆ๊ฑฐ์‹œ ๊ฐ’, ํ˜„์žฌ ์ƒ์‚ฐ์ž ์—†์Œ"์„ ๋ช…๊ธฐ (ยง5 ๋‹จ๊ณ„ 4 ์— ๋ฐ˜์˜ ์™„๋ฃŒ). +- B(์™„์ „ ์€ํ‡ด)๋Š” ๊ธฐ์กด ๋ฐ์ดํ„ฐ์— `archived` ํ–‰์ด ์žˆ์œผ๋ฉด ๊ฒ€์ฆ ์‹คํŒจ๋กœ **์ „์ฒด ์“ฐ๊ธฐ๊ฐ€ ๋ง‰ํžˆ๋ฏ€๋กœ** ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค โ€” C-6("๊ทน์†Œ") ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚ฉ๋‹ˆ๋‹ค. + +`MESSAGING.md` ๋ฅผ C-6 ๋ฒ”์œ„์— ํฌํ•จํ•˜๋Š” ๊ฒƒ๋„ ์ฑŒ๋ฆฐ์ €๊ฐ€ ยง4-2 ์—์„œ ๋™์˜ํ–ˆ์œผ๋ฏ€๋กœ ํ™•์ •ํ•ฉ๋‹ˆ๋‹ค. + +--- + +## 8. ๊ฒ€์ฆ ์ ˆ์ฐจ + +| # | ๋ช…๋ น / ํ™•์ธ | ๊ธฐ๋Œ€ | +|---|---|---| +| 1 | `bash -n .../stop_session.sh` | OK | +| 2 | `bash stop_session.sh --help; echo $?` | rc=0, ํ์ง€ ํ”Œ๋ž˜๊ทธ ๋ฏธ๋…ธ์ถœ, 4๊ฐœ ์—์ด์ „ํŠธ ์ „๋ถ€ ๋…ธ์ถœ | +| 3 | `--mode` / `--capture-id` / `--graceful` | rc=2 + `deprecated` ๋ฉ”์‹œ์ง€ ์œ ์ง€ | +| 4 | `--agent bogus` | rc=2 (`invalid agent type`) | +| 5 | `grep -rn -- "--mode soft" .agents/ *.md` | 0๊ฑด | +| 6 | **๋ฎคํ…Œ์ด์…˜ M1** โ€” ํŒŒ์„œ์—์„œ `--reason)` ์‚ญ์ œ | ๊ฐ€๋“œ **FAIL** | +| 7 | **๋ฎคํ…Œ์ด์…˜ M2** โ€” ํ—ค๋”์— `--mode soft\|hard` ๋ณต์› | ๊ฐ€๋“œ **FAIL** | +| 8 | **๋ฎคํ…Œ์ด์…˜ M3** โ€” `usage()` ์—์ด์ „ํŠธ ๋ชฉ๋ก ์ถ•์†Œ | ๊ฐ€๋“œ **FAIL** | +| 9 | `pytest tests/ -q` | **263 passed** | +| 10 | `env -u PYTHONPATH pytest tests/test_tier2_component.py -q` | ์ „๋ถ€ ํ†ต๊ณผ (ํ™˜๊ฒฝ ๋น„์˜์กด) | +| 11 | `IMPROVEMENTS.md` `:5` โ†” `:107` ๋Œ€์กฐ | ๋ ˆ๊ฑฐ์‹œ ์นด์šดํŠธ ์ผ์น˜ | +| 12 | `IMPROVEMENTS.md` `:6` โ†” `:114` ๋Œ€์กฐ | ๋‘˜ ๋‹ค 20๊ฑด | + +9๋ฒˆ์€ ์•ฝ 6๋ถ„ 30์ดˆ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค(์ง์ „ ์‹ค์ธก 262 passed / 381.58s). ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹คํ–‰ ๊ถŒ์žฅ. + +10๋ฒˆ ๊ทผ๊ฑฐ: ์ง์ „ ๋ผ์šด๋“œ์—์„œ ์‹ ๊ทœ ํ…Œ์ŠคํŠธ๊ฐ€ ์ฃผ๋ณ€ ์…ธ์˜ `PYTHONPATH` ์— ์˜์กดํ•ด CI ๋ฅผ ์ ์ƒ‰์œผ๋กœ ๋งŒ๋“  ์‚ฌ๋ก€(N1)๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ™•์ • ๊ฐ€๋“œ๋Š” `subprocess.run(["bash", ...])` ๋งŒ ์“ฐ๋ฏ€๋กœ ํ•ด๋‹น ์œ„ํ—˜์ด ์—†์œผ๋‚˜ ํ™•์ธ ์ ˆ์ฐจ๋Š” ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค. + +--- + +## 9. ๋ณ€๊ฒฝ ๊ทœ๋ชจ ๋ฐ ๋ฆฌ์Šคํฌ + +| ํŒŒ์ผ | ๋ณ€๊ฒฝ | +|---|---| +| `stop_session.sh` | ํ—ค๋” 29์ค„ ๊ต์ฒด, `usage()` ์•ฝ +10์ค„, ๋‚ด๋ถ€ ์ฃผ์„ 3๊ณณ + ๊ฒฝ๊ณ  ๋ฌธ์ž์—ด 1๊ณณ | +| `MESSAGING.md` | 3์ค„ | +| `IMPROVEMENTS.md` | 7๊ณณ + ยง5 ์‹ ๊ทœ ํ•ญ๋ชฉ | +| `LOG.md` | 1๊ฐœ ๋ธ”๋ก + ๋จธ๋ฆฌ๋ง | +| `tests/test_tier2_component.py` | +1 test | +| **ํ…Œ์ŠคํŠธ ์ด๊ณ„** | 262 โ†’ **263** | + +| ๋ฆฌ์Šคํฌ | ํ‰๊ฐ€ | +|---|---| +| ๋™์ž‘ ํšŒ๊ท€ | **์—†์Œ.** ์‹คํ–‰ ๊ฒฝ๋กœ ๋ฌด๋ณ€๊ฒฝ. ์œ ์ผํ•œ ์˜ˆ์™ธ `:166` ๊ฒฝ๊ณ  ๋ฌธ์ž์—ด์€ ๋‹จ์–ธํ•˜๋Š” ํ…Œ์ŠคํŠธ 0๊ฑด ํ™•์ธ | +| ๊ฐ€๋“œ ์˜คํƒ | **ํ•ด์†Œ.** Challenge ์›์ธ(`:98`)์„ ์„ธ์…˜๋ช…์œผ๋กœ ์ œ๊ฑฐํ•˜๊ณ , `rc=2` ๊ณผ๋ถ€ํ•˜๋ฅผ ๋ฉ”์‹œ์ง€ ๋‹จ์–ธ์œผ๋กœ ์šฐํšŒ | +| ๊ฐ€๋“œ ๋ฌด๋ ฅํ™” | **ํ•ด์†Œ.** M1~M3 ์‹ค์ธก์œผ๋กœ ๋ฐฉ์–ด๋ ฅ ์ฆ๋ช… | +| ์นด์šดํŠธ ๋ถˆ์ผ์น˜ ์žฌ๋ฐœ | ยง8 ์˜ 11ยท12๋ฒˆ์œผ๋กœ ์ฐจ๋‹จ | + +### ๊ถŒ์žฅ ์ปค๋ฐ‹ ๋ถ„ํ•  + +1. `docs(stop): rewrite stop_session.sh header and usage to match the current CLI (C-6)` โ€” ๋‹จ๊ณ„ 1~3 +2. `test(stop): guard help text against parser drift (C-6)` โ€” ยง4 +3. `docs(messaging,improvements,log): sync status table and backlog for C-6` โ€” ๋‹จ๊ณ„ 4 + ยง6 + +2๋ฒˆ์„ 1๋ฒˆ ๋’ค์— ๋‘๋ฉด, ๊ฐ€๋“œ๊ฐ€ 1๋ฒˆ ์—†์ด ์‹คํŒจํ•˜๊ณ  1๋ฒˆ๊ณผ ํ•จ๊ป˜ ํ†ต๊ณผํ•จ์„ ์ปค๋ฐ‹ ์ˆœ์„œ๋กœ ์ฆ๋ช…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. + +--- + +## 10. ํ•œ๊ณ„ + +- ํ™•์ • ๊ฐ€๋“œ๋Š” **๊ฒฉ๋ฆฌ ํด๋ก ์—์„œ ์‹คํ–‰ ๊ฒ€์ฆ**ํ–ˆ์œผ๋‚˜, ์ €์žฅ์†Œ ๋ณธ์ฒด์—๋Š” ์ ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค(Planner ์—ญํ• ). ํด๋ก ์€ ๊ฒ€์ฆ ํ›„ ์‚ญ์ œํ–ˆ๊ณ  ์ž‘์—… ํŠธ๋ฆฌ๋Š” ๊ณ„ํš ์ˆ˜๋ฆฝ ์ „ํ›„ ๋™์ผ(`?? VERSIONS.md` 1๊ฑด)ํ•ฉ๋‹ˆ๋‹ค. +- ๋ฎคํ…Œ์ด์…˜ M1~M3 ์€ ยง5 ๋‹จ๊ณ„ 1~2 ์˜ ๋ฌธ์„œ ์ˆ˜์ •์„ ํด๋ก ์— **๋ถ€๋ถ„ ์ ์šฉ**ํ•œ ์ƒํƒœ์—์„œ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค(ํ—ค๋” `--mode` ํ–‰ ์‚ญ์ œ + `usage()` ํ™•์žฅ). ๋‹จ๊ณ„ 3ยท4 ๋Š” ๊ฐ€๋“œ ๋Œ€์ƒ์ด ์•„๋‹ˆ๋ฏ€๋กœ ์ ์šฉํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. +- ์ „์ฒด ํšŒ๊ท€(263)๋Š” ์žฌ์‹คํ–‰ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. 262 passed / 381.58s ๊ฐ€ ์œ ํšจ ๊ธฐ์ค€์ด๋ฉฐ HEAD ๊ฐ€ `5ed39f8` ๋กœ ์ง„ํ–‰๋˜์—ˆ์œผ๋ฏ€๋กœ ๊ตฌํ˜„ ์‹œ ์žฌ์ธก์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. +- `MESSAGING.md` ๋Š” ํ์ง€ ํ”Œ๋ž˜๊ทธ 3์ข… ๊ฒ€์ƒ‰์œผ๋กœ ๊ฑธ๋ฆฐ 3์ค„๋งŒ ํ™•์ธํ–ˆ๊ณ  ๋‚˜๋จธ์ง€๋Š” ๊ฐ์‚ฌํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. +- `:91-100` ์ ‘๋ฏธ์‚ฌ ์ถ”๋ก ์˜ ์—ญํ•  ๋ชฉ๋ก(`creator`/`planner`/`reviewer`)์ด ์‹ค์ œ ์‚ฌ์šฉ๋˜๋Š” ์—ญํ•  ์ „๋ถ€๋ฅผ ๋ฎ๋Š”์ง€๋Š” ํ™•์ธํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. C-6 ๋ฒ”์œ„ ๋ฐ–์ด๋ฉฐ, ๊ฐ€๋“œ๋Š” ์ด ๋ชฉ๋ก์— ์˜์กดํ•˜์ง€ ์•Š๋„๋ก(ยง2.3) ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค. diff --git a/.agents/reports/canary-projects-multi-agent-mux-creator-cline/report-7ddb5350.md b/.agents/reports/canary-projects-multi-agent-mux-creator-cline/report-7ddb5350.md new file mode 100644 index 0000000..4beb364 --- /dev/null +++ b/.agents/reports/canary-projects-multi-agent-mux-creator-cline/report-7ddb5350.md @@ -0,0 +1,233 @@ +# Cross-Code Review Report โ€” Job 7ddb5350 + +- **Job ID**: 7ddb5350 +- **Target**: C-6 (P2-3) โ€” `stop_session.sh` legacy comment and outdated usage text cleanup, `IMPROVEMENTS.md`/`LOG.md` synchronization, `MESSAGING.md` status table correction, regression guard addition, and `VERSIONS.md` creation +- **Reviewer**: cline +- **Output Report Path**: `.mam/jobs/7ddb5350/cline-reports/report-final.md` +- **Base commit**: `5ed39f8` (fix(agents): harden shell adapter bridge and address double-check review feedback) +- **Working-tree state**: 5 tracked modified files + 1 untracked new file (`VERSIONS.md`) + +--- + +## 1. Delta Description + +This changeset resolves backlog item C-6 (roadmap P2-3): cleaning up legacy comments and outdated usage text in `stop_session.sh` that advertised deprecated flags (`--mode soft|hard`, `--capture-id`, `--graceful`) as valid usage, while the parser rejects them with `exit 2`. The scope expanded beyond the brief's "3-line fix" estimate to cover all documentation surfaces with the same defect. + +| File | Change Summary | +|------|---------------| +| `.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh` | Header comment block (29 lines) rewritten to match current CLI; `usage()` expanded with full argument descriptions; 3 internal comments + 1 warning string modernized; removed "์›Œํฌ์ŠคํŽ˜์ด์Šค์— ๊ฒฉ๋ฆฌ๋œ" (Option B obsolete terminology) | +| `MESSAGING.md` | Session state table (3 rows) corrected: `stopped`/`terminated` now reference current CLI; `archived` marked as legacy with no producer | +| `IMPROVEMENTS.md` | C-6 moved from ยง4 (open) to ยง5 (completed); header counts updated (6โ†’5 open, 19โ†’20 completed); roadmap P2-3 row updated with verification status | +| `LOG.md` | New ยง1 entry for C-6 work; prior sections renumbered (duplicate "2)" numbering fixed); header timestamp updated | +| `tests/test_tier2_component.py` | New regression guard `test_comp_stop_usage_matches_parser` (+45 lines): verifies help-parser consistency across 4 dimensions | +| `VERSIONS.md` (new) | 135-line version history document covering v1.0.0โ€“v2.0.0 changelog, skills version matrix, and verification standards | + +**Net diff**: 5 files changed, 107 insertions(+), 45 deletions(-) + 1 new untracked file (135 lines). + +--- + +## 2. Review Methodology + +This review examines the changeset from three perspectives as required by the brief: + +1. **Lint (์ •์  ๊ฒ€์‚ฌ)**: Syntax validation, comment-code consistency, orphaned reference detection +2. **Operability (๋™์ž‘์„ฑ)**: Runtime behavior verification, parser-help alignment, exit code correctness +3. **Loss (์œ ์‹ค)**: Completeness of cleanup, documentation-code drift, regression guard effectiveness + +--- + +## 3. Findings + +### 3.1 Lint (์ •์  ๊ฒ€์‚ฌ) โ€” PASS + +**V1: Bash syntax validation** +- `bash -n stop_session.sh` โ†’ **OK** โœ… +- `bash -n lib.sh` โ†’ **OK** โœ… + +**V2: Header comment โ†” parser consistency** +The header (lines 3โ€“25) now documents exactly the 5 current CLI arguments and lists the 3 deprecated flags with their rejection behavior: + +| Header advertises | Parser handles (line) | Match? | +|---|---|---| +| `--session ` | `:69` `--session) SESSION_NAME="$2"; shift 2` | โœ… | +| `--agent claude\|agy\|hermes\|cline` | `:70` `--agent) AGENT="$2"; shift 2` + `:84` validation case | โœ… | +| `--reason ` | `:73` `--reason) REASON="$2"; shift 2` | โœ… | +| `--purge-conversation` | `:71` `--purge-conversation) PURGE=1; shift` | โœ… | +| `--yes` | `:72` `--yes) YES=1; shift` | โœ… | +| Deprecated: `--mode`/`--capture-id`/`--graceful` โ†’ exit 2 | `:74-77` case โ†’ exit 2 | โœ… | + +**V3: Orphaned deprecated-flag references in production code** +- `grep -rn '--mode soft' .agents/ *.md` (excluding `.mam/` and `.agents/reports/`): **3 hits, all correct**: + - `IMPROVEMENTS.md:114` โ€” C-6 completed entry *describing* what was fixed (historical record) โœ… + - `LOG.md:12` โ€” C-6 work log *describing* what was fixed (historical record) โœ… + - `MESSAGING.md:348` โ€” `archived` row explaining `--mode soft` was removed (legacy documentation) โœ… +- **Zero orphaned references in production `.agents/` scripts** advertising deprecated flags as valid usage โœ… + +### 3.2 Operability (๋™์ž‘์„ฑ) โ€” PASS + +**V4: `--help` output verification** +``` +$ stop_session.sh --help; echo $? +Usage: ... --session [--agent claude|agy|hermes|cline] [--reason ] + [--purge-conversation] [--yes] +Arguments: + --session โ€” target session name (required) + --agent โ€” claude | agy | hermes | cline + --reason โ€” stop_reason field (default: manual_stop) + --purge-conversation โ€” also delete on-disk conversation artifacts; ... + --yes โ€” skip the --purge-conversation confirmation prompt +Stop is always graceful and always captures the conversation id. +rc=0 +``` +- rc=0 โœ… +- No deprecated flags (`--mode`, `--capture-id`, `--graceful`) advertised โœ… +- All 4 agents (claude, agy, hermes, cline) listed โœ… + +**V5: Deprecated flag rejection** +``` +$ stop_session.sh --session x --mode hard; echo $? +rc=2 +``` +- `--mode`/`--capture-id`/`--graceful` all rejected with rc=2 and "deprecated" message โœ… + +**V6: MESSAGING.md โ†” code alignment** +| MESSAGING.md state | Code behavior | Match? | +|---|---|---| +| `stopped` โ€” "stopped via multi-agent-mux-stop (default)" | `stop_session.sh:257` `target['status'] = 'stopped'` (non-purge path) | โœ… | +| `terminated` โ€” "stopped with --purge-conversation" | `stop_session.sh:296-297` purge path removes entry, status becomes terminated | โœ… | +| `archived` โ€” "legacy value, no producer" | `atomic_yaml.py:18` whitelist retains `archived`; no code path produces it | โœ… | + +**V7: `archived` whitelist retention (Option A)** +- `atomic_yaml.py:18`: `valid = {'running', 'terminated', 'archived', 'stopped'}` โ€” `archived` retained โœ… +- `reconcile.sh:474`: `if s.get('status') in ('terminated', 'archived', 'stopped'):` โ€” `archived` retained โœ… +- MESSAGING.md documents this as intentional for backward compatibility with older rows โœ… + +### 3.3 Loss (์œ ์‹ค) โ€” PASS + +**V8: Regression guard effectiveness** +The new test `test_comp_stop_usage_matches_parser` verifies 4 dimensions of help-parser consistency: +1. `--help` succeeds (rc=0) and does NOT advertise deprecated flags โœ… +2. All 4 supported agents appear in help text โœ… +3. All advertised flags (`--reason`, `--purge-conversation`, `--yes`, `--agent`) are accepted by parser (rcโ‰ 2, no "unknown arg"/"deprecated" in stderr) โœ… +4. Deprecated flags (`--mode`, `--capture-id`, `--graceful`) are rejected with rc=2 and "deprecated" message โœ… +5. Header comments (first 35 lines) do not contain `--mode soft|hard` โœ… + +The test uses `subprocess.run(["bash", ...])` only โ€” no ambient `PYTHONPATH` dependency (N1 guard satisfied). + +**V9: Clean-environment test** +``` +$ env -u PYTHONPATH pytest tests/test_tier2_component.py::test_comp_stop_usage_matches_parser -v +1 passed in 0.79s +``` +Environment-independent โœ… + +**V10: IMPROVEMENTS.md count consistency** +- Line 5: "์ด ์ถ”์  ๋ฏธํ•ด๊ฒฐ ๊ณผ์ œ: 5๊ฑด (์•„ํ‚คํ…์ฒ˜ 1๊ฑด, ์—ฃ์ง€์ผ€์ด์Šค 4๊ฑด, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ 0๊ฑด, ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ 0๊ฑด)" โ†’ 1+4+0+0 = 5 โœ… +- Line 107: "Legacy Remnants โ€” 0๊ฑด โ€” ์ „์› ์™„๋ฃŒ" โ†’ matches header "๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ 0๊ฑด" โœ… +- Line 6: "์™„๋ฃŒ๋œ ๊ณผ์ œ: 20๊ฑด" โ†’ listed items count: 20 โœ… +- Line 111: "Completed Tasks โ€” 20๊ฑด" โ†’ matches header โœ… +- C-6 present in completed list (line 6) โœ… + +**V11: LOG.md section numbering fix** +The old LOG.md had duplicate "### 2)" numbering (3 sections all numbered "2)"). The new LOG.md correctly numbers sections 1โ€“5 sequentially. This is a welcome cleanup beyond the brief scope. โœ… + +**V12: VERSIONS.md (new file)** +The new `VERSIONS.md` (135 lines) provides a structured version history covering: +- Current release overview (v2.0.0) +- Skills version matrix (8 skills, all v2.0.0) +- Changelog for v1.0.0โ€“v2.0.0 +- Verification standards (4-step QA process) + +Content is consistent with the existing IMPROVEMENTS.md and LOG.md records. The file is currently untracked (`??`). + +--- + +## 4. Full Test Suite Execution + +**V13: Complete regression test** +``` +$ pytest tests/ -q --tb=short +........................................................................ [ 27%] +........................................................................ [ 54%] +........................................................................ [ 82%] +........................................................................ [100%] +263 passed in 384.59s (0:06:24) +``` + +**Result: 263/263 PASS (100%)** โ€” matches the IMPROVEMENTS.md and LOG.md claims exactly. โœ… + +Previous review (Job e7b9812b) had 259/259; this changeset adds 1 new test (262โ†’263, with +3 from commit `5ed39f8` between reviews). + +--- + +## 5. Minor Observations (Non-blocking) + +### 5.1 MESSAGING.md "lib.sh valid-status set" reference (pre-existing) +Line 341 says "Valid values (see `lib.sh` valid-status set)" but the actual validation is in `atomic_yaml.py:18`, not `lib.sh`. This is a pre-existing inaccuracy **not introduced by C-6** โ€” the C-6 diff only changed the table rows, not this reference line. Mentioning for awareness; no action required for this job. + +### 5.2 `CAPTURE_ID`/`GRACEFUL`/`STOP_MODE` variables remain hardcoded +Lines 62โ€“65 still hardcode `CAPTURE_ID=1`, `GRACEFUL=1`, `STOP_MODE=1`. The comment cleanup removed references to these as user-facing flags, but the variables themselves remain in the code (always-on). This is correct for C-6 scope โ€” the task was documentation cleanup, not code refactoring. The variables are harmless (always-true conditions) and removing them would expand scope beyond "๊ทน์†Œ" difficulty. + +### 5.3 VERSIONS.md untracked +`VERSIONS.md` is currently an untracked file (`??` in git status). It should be committed alongside the other changes. The Planner's recommended commit split (ยง9 of Job 73b18819) does not explicitly mention VERSIONS.md โ€” it may need to be added to the commit plan. + +--- + +## 6. Scope Assessment + +The brief described C-6 as "๋„์›€๋ง 3์ค„ ์ •์ •" (3-line help text fix). The actual implementation correctly identified that the defect spans: +- Header comments: 29 lines (not 3) +- `usage()` function: +10 lines expansion +- Internal comments: 3 locations +- Warning string: 1 location +- `MESSAGING.md`: 3 rows (scope expansion, justified โ€” same defect type) +- Regression guard: 1 new test (justified โ€” C-6 is a documentation task that no existing test covered) + +The scope expansion is well-justified and documented in the Planner's report (Job 73b18819 ยง0). The Challenger (Job 8b6b574f) agreed to include `MESSAGING.md` and to adopt Option A for `archived`. All changes trace directly to the C-6 defect (help text advertising deprecated flags). + +--- + +## 7. Risk Assessment + +| Risk | Assessment | +|---|---| +| Behavior regression | **None.** No execution paths changed. Only comments, help text, and documentation modified. Warning string at `:175` changed but no test asserts on it. | +| Guard false-positive | **Resolved.** Test uses valid session name (`test-project-creator-claude`) to avoid rc=2 from agent inference failure; uses stderr message assertions instead of brittle rc=2 overloading. | +| Guard powerlessness | **Resolved.** Mutation testing M1โ€“M3 (per Planner report) confirmed all 3 mutations cause FAIL. | +| Count inconsistency | **Resolved.** IMPROVEMENTS.md header counts match section headers (V10). | +| Environment dependency | **Resolved.** Clean-environment test passes (V9, N1 guard). | + +--- + +## 8. Verification Summary + +| # | Verification | Expected | Result | +|---|---|---|---| +| V1 | `bash -n stop_session.sh` | OK | โœ… OK | +| V2 | Header โ†” parser consistency | All 5 flags + 3 deprecated match | โœ… Match | +| V3 | Orphaned deprecated refs in production | 0 | โœ… 0 | +| V4 | `--help` output | rc=0, no deprecated flags, 4 agents | โœ… Pass | +| V5 | `--mode hard` rejection | rc=2 + deprecated | โœ… Pass | +| V6 | MESSAGING.md โ†” code alignment | 3 states match | โœ… Pass | +| V7 | `archived` whitelist retention | Retained + documented | โœ… Pass | +| V8 | Regression guard (4 dimensions) | All pass | โœ… Pass | +| V9 | Clean-environment test (N1) | Pass without PYTHONPATH | โœ… Pass | +| V10 | IMPROVEMENTS.md count consistency | 5 open, 20 completed, 0 remnants | โœ… Pass | +| V11 | LOG.md section numbering | Sequential 1โ€“5 | โœ… Pass | +| V12 | VERSIONS.md content | Consistent with records | โœ… Pass | +| V13 | Full test suite | 263/263 PASS | โœ… 263 passed in 384.59s | + +--- + +## 9. Verdict + +The C-6 implementation is a thorough and well-executed documentation cleanup that: +- Correctly identifies the full scope of the defect (29-line header, not 3 lines) +- Aligns all documentation surfaces (header, `usage()`, internal comments, `MESSAGING.md`) with the actual parser behavior +- Adds a meaningful regression guard that prevents future help-parser drift +- Retains `archived` in the validation whitelist with proper documentation (Option A) +- Passes the complete test suite (263/263, 100%) + +No behavior regression, no orphaned references, no count inconsistencies, and no environment dependencies. The three minor observations (ยง5) are pre-existing or out-of-scope and do not block the verdict. + +[VERDICT: PASS] \ No newline at end of file diff --git a/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh b/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh index 77a738b..f19fb1d 100755 --- a/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh +++ b/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh @@ -1,28 +1,28 @@ #!/usr/bin/env bash # stop_session.sh โ€” multi-agent-mux-stop ์˜ ๋ถ€์† ์Šคํฌ๋ฆฝํŠธ # Usage: -# bash stop_session.sh --session [--agent claude|agy] \ -# [--mode soft|hard] [--purge-conversation] [--yes] +# bash stop_session.sh --session [--agent claude|agy|hermes|cline] \ +# [--reason ] [--purge-conversation] [--yes] # -# mode: -# soft โ€” YAML ์„ status=archived ๋กœ ๋งˆํฌ, herdr ์„ธ์…˜์€ ๊ทธ๋Œ€๋กœ ๋‘  (P1-A: -# terminated ๋Š” herdr ๊ฐ€ ์‹ค์ œ๋กœ ์ฃฝ์€ ์ƒํƒœ์—๋งŒ ์‚ฌ์šฉ) -# hard โ€” herdr kill-session + YAML status=terminated -# --purge-conversation: --mode hard ์ผ ๋•Œ๋งŒ. ์‚ญ์ œ ๋Œ€์ƒ ์„ธ์…˜์˜ *์›Œํฌ์ŠคํŽ˜์ด์Šค์— -# ๊ฒฉ๋ฆฌ๋œ* conversation artifact ๋งŒ ์‚ญ์ œ (P0-C). ์ „์—ญ -# agent_identities ๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š์Œ. resume ๋ถˆ๊ฐ€. +# ๋™์ž‘: ํ•ญ์ƒ graceful stop ์ž…๋‹ˆ๋‹ค. send-keys ๋กœ ์ •์ƒ ์ข…๋ฃŒ๋ฅผ ์œ ๋„ํ•˜๊ณ  +# (๋ฏธ์ข…๋ฃŒ ์‹œ SIGTERM โ†’ SIGKILL ํด๋ฐฑ), kill ์ง์ „์— ์ด ์›Œํฌ์ŠคํŽ˜์ด์Šค์˜ +# conversation id ๋ฅผ row ์— ํ™•์ • ๊ธฐ๋กํ•ด ๋‹ค์Œ resume ์ด tier-1(race-free) +# ์œผ๋กœ ๋ณต์›๋˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. status ๋Š” running -> stopped ๋กœ ์ „์ดํ•ฉ๋‹ˆ๋‹ค. +# ๋ฉฑ๋“ฑ: ์ด๋ฏธ stopped ๋ฉด no-op + exit 0. # -# Stop extension (Option A โ€” stop ํ™•์žฅ, ์ƒˆ 6๋ฒˆ์งธ ์Šคํ‚ฌ ์—†์ด stop ์˜๋ฏธ๋ก  ํก์ˆ˜): -# --capture-id โ€” kill ์ง์ „์— ์ด ์›Œํฌ์ŠคํŽ˜์ด์Šค์˜ conversation id ๋ฅผ row ์— ํ™•์ • -# ๊ธฐ๋ก (claude_session_id_own / agy_conversation_id_own) โ†’ -# ๋‹ค์Œ resume ์ด tier-1(race-free) ๋กœ ๋ณต์›. find_workspace_uuid -# ์žฌ์‚ฌ์šฉ (per-row -> workspace-scoped disk scan -> cache). -# --reason R โ€” ์ƒํƒœ ์ „์ด ์‚ฌ์œ  (stop_reason). ๊ธฐ๋ณธ๊ฐ’ manual_stop. -# --graceful โ€” kill-session ์ฆ‰์‹œ ์ข…๋ฃŒ ๋Œ€์‹  send-keys ๋กœ ์ •์ƒ ์ข…๋ฃŒ ์œ ๋„ โ†’ -# 3์ดˆ ๋Œ€๊ธฐ โ†’ ๋ฏธ์ข…๋ฃŒ ์‹œ kill-session(SIGTERM) โ†’ 5์ดˆ โ†’ SIGKILL. -# ์œ„ ์„ธ ์˜ต์…˜ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ฃผ๋ฉด STOP ๋ชจ๋“œ: status ๊ฐ€ terminated ๊ฐ€ ์•„๋‹ˆ๋ผ stopped -# ๋กœ ์ „์ด (running -> stopped). ๋ฉฑ๋“ฑ: ์ด๋ฏธ stopped ๋ฉด no-op + exit 0. -# ์˜ต์…˜ ๋ฏธ์ง€์ • ์‹œ ๊ธฐ์กด hard/soft ๋™์ž‘ ๊ทธ๋Œ€๋กœ (backward compatible). +# ์˜ต์…˜: +# --session โ€” ๋Œ€์ƒ ์„ธ์…˜ (ํ•„์ˆ˜) +# --agent โ€” claude | agy | hermes | cline +# (๋ฏธ์ง€์ • ์‹œ ์„ธ์…˜๋ช… ์ ‘๋ฏธ์‚ฌ๋กœ ์ถ”๋ก ; ์ถ”๋ก  ์‹คํŒจ ์‹œ exit 2) +# --reason โ€” ์ƒํƒœ ์ „์ด ์‚ฌ์œ  (stop_reason). ๊ธฐ๋ณธ๊ฐ’ manual_stop +# --purge-conversation โ€” ๋””์Šคํฌ์˜ conversation artifact ๊นŒ์ง€ ์‚ญ์ œ. +# status=terminated, resumable=false ๋กœ ์ „์ดํ•˜๋ฉฐ +# resume ๋ถˆ๊ฐ€. --yes ์—†์ด๋Š” ํ™•์ธ ํ”„๋กฌํ”„ํŠธ(exit 3) +# --yes โ€” --purge-conversation ์˜ ํ™•์ธ ํ”„๋กฌํ”„ํŠธ ์ƒ๋žต +# +# ํ์ง€๋œ ์˜ต์…˜: --mode / --capture-id / --graceful ๋Š” ๊ฐ๊ฐ exit 2 ๋กœ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค. +# graceful ์ข…๋ฃŒ์™€ id ์บก์ฒ˜๋Š” ์ด์ œ ๋ฌด์กฐ๊ฑด ์ˆ˜ํ–‰๋˜๋ฉฐ, soft/hard ๋ชจ๋“œ +# ๊ตฌ๋ถ„์€ --purge-conversation ์œ ๋ฌด๋กœ ๋Œ€์ฒด๋˜์—ˆ์Šต๋‹ˆ๋‹ค. # # Exit codes: # 0 = success (or already-stopped no-op) | 1 = YAML not found / not registered @@ -38,11 +38,20 @@ source "$_lib_sh" usage() { cat < [--agent claude|agy] [--purge-conversation] [--yes] [--reason ] +Usage: $0 --session [--agent claude|agy|hermes|cline] [--reason ] + [--purge-conversation] [--yes] -Stop arguments: - --reason โ€” stop_reason field (default: manual_stop) - (idempotent: stopping an already-stopped session is a no-op with exit 0) +Arguments: + --session โ€” target session name (required) + --agent โ€” claude | agy | hermes | cline + (inferred from the session-name suffix when omitted) + --reason โ€” stop_reason field (default: manual_stop) + --purge-conversation โ€” also delete on-disk conversation artifacts; + status becomes terminated and resume is impossible + --yes โ€” skip the --purge-conversation confirmation prompt + +Stop is always graceful and always captures the conversation id. +(idempotent: stopping an already-stopped session is a no-op with exit 0) EOF } @@ -154,7 +163,7 @@ if herdr has-session -t "$SESSION_NAME" 2>/dev/null; then LAST_STATUS=$(herdr capture-pane -t "$SESSION_NAME" -p -S -10 2>/dev/null | tr '\n' ' ' | head -c 500 || true) fi -# --capture-id: kill ์ง์ „์— conversation id ๋ฅผ ํ•ด๊ฒฐ (process/jsonl ์ด ์•„์ง ์‚ด์•„์žˆ์„ ๋•Œ). +# ์บก์ฒ˜: kill ์ง์ „์— conversation id ๋ฅผ ํ•ด๊ฒฐ (process/jsonl ์ด ์•„์ง ์‚ด์•„์žˆ์„ ๋•Œ). # find_workspace_uuid ๊ฐ€ tier-1(row) -> tier-2(workspace-scoped disk scan) -> tier-3(cache) # ๋ฅผ ์•Œ์•„์„œ ์‹œ๋„ํ•˜๋ฏ€๋กœ herdr ์ƒ์‚ฌ์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋™์ž‘. CAPTURED_UUID="" @@ -163,13 +172,13 @@ if [ "$CAPTURE_ID" = "1" ] && [ -n "$TARGET_CWD" ]; then if [ -n "$CAPTURED_UUID" ]; then echo "captured conversation id: $CAPTURED_UUID" else - echo "WARN: --capture-id requested but no conversation id resolved (nothing on disk yet)" + echo "WARN: no conversation id resolved before stop (nothing on disk yet)" fi fi delegate_publish_event "$DELEGATE_JOB_ID" progress "terminating" -# --graceful: send-keys ๋กœ ์ •์ƒ ์ข…๋ฃŒ ์œ ๋„ โ†’ ํด๋ฐฑ ์ฒด์ธ (SIGTERM โ†’ SIGKILL). +# graceful ์ข…๋ฃŒ: send-keys ๋กœ ์ •์ƒ ์ข…๋ฃŒ ์œ ๋„ โ†’ ํด๋ฐฑ ์ฒด์ธ (SIGTERM โ†’ SIGKILL). graceful_stop() { local pane_pid exitkey pane_pid=$(herdr list-panes -t "$SESSION_NAME" -F '#{pane_pid}' 2>/dev/null | head -1 || true) @@ -254,7 +263,7 @@ if not purge: if last_status: target['last_visible_status_at_termination'] = last_status -# --capture-id: ํ•ญ์ƒ captured UUID ๊ธฐ๋ก (purge๊ฐ€ ์•„๋‹ ๋•Œ๋งŒ) +# ํ•ญ์ƒ captured UUID ๊ธฐ๋ก (purge ๊ฐ€ ์•„๋‹ ๋•Œ๋งŒ) if captured and not purge: if agent == 'claude': target['claude_session_id_own'] = captured diff --git a/IMPROVEMENTS.md b/IMPROVEMENTS.md index 163edde..50d541a 100644 --- a/IMPROVEMENTS.md +++ b/IMPROVEMENTS.md @@ -1,9 +1,9 @@ # ๐Ÿ› ๏ธ Multi-Agent Mux ์ข…ํ•ฉ ๊ฐœ์„  ๋ฐ ๋ฏธํ•ด๊ฒฐ ๊ณผ์ œ ๋ฐฑ๋กœ๊ทธ (`IMPROVEMENTS.md`) -- **์ตœ์ข… ๊ฐฑ์‹ ์ผ**: 2026-08-16 (P3-1/A-4 Phase 2 M2~M7 ์—์ด์ „ํŠธ ์ง€์‹ ๊ณ„์ธต ๋ฐ Option B / C-3b ์™„๋ฃŒ, Reviewer ํ”ผ๋“œ๋ฐฑ ๋ฐ˜์˜, ์ „์ฒด 259/259 ํšŒ๊ท€ ํ†ต๊ณผ ๋ฐ˜์˜) +- **์ตœ์ข… ๊ฐฑ์‹ ์ผ**: 2026-08-17 (C-6/P2-3 stop_session.sh ๋ ˆ๊ฑฐ์‹œ ์ฃผ์„ ๋ฐ ๊ตฌ๋ฒ„์ „ ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ ์™„๋ฃŒ, ํšŒ๊ท€ ๊ฐ€๋“œ ์‹ ์„ค, ์ „์ฒด 263/263 ํšŒ๊ท€ ํ†ต๊ณผ ๋ฐ˜์˜) - **ํ†ตํ•ฉ ๊ด€๋ฆฌ ๋Œ€์ƒ**: ๊ธฐ์กด `CODEBASE_REVIEW_REPORT.md` + `OPTIMIZATION.md` -- **์ด ์ถ”์  ๋ฏธํ•ด๊ฒฐ ๊ณผ์ œ**: **6๊ฑด** (์•„ํ‚คํ…์ฒ˜ 1๊ฑด, ์—ฃ์ง€์ผ€์ด์Šค 4๊ฑด, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ 0๊ฑด, ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ 1๊ฑด) -- **์™„๋ฃŒ๋œ ๊ณผ์ œ**: **19๊ฑด** (A-1, A-3, A-4, A-5, B-1, B-3, B-4, B-7, B-8, C-1, C-2, C-3b, O-1, O-2, O-3, O-4-OrcOnboard, Herdr-0.8.0-Compat-SanitizeHash, P2-1-DelegateJobSafe-TrapFix, P2-2-C3a-C4-LegacyCleanup) +- **์ด ์ถ”์  ๋ฏธํ•ด๊ฒฐ ๊ณผ์ œ**: **5๊ฑด** (์•„ํ‚คํ…์ฒ˜ 1๊ฑด, ์—ฃ์ง€์ผ€์ด์Šค 4๊ฑด, ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ 0๊ฑด, ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ 0๊ฑด) +- **์™„๋ฃŒ๋œ ๊ณผ์ œ**: **20๊ฑด** (A-1, A-3, A-4, A-5, B-1, B-3, B-4, B-7, B-8, C-1, C-2, C-3b, C-6, O-1, O-2, O-3, O-4-OrcOnboard, Herdr-0.8.0-Compat-SanitizeHash, P2-1-DelegateJobSafe-TrapFix, P2-2-C3a-C4-LegacyCleanup) --- @@ -104,14 +104,16 @@ --- -## 4. โšช ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ ๋ฐ ์ฃฝ์€ ์ฝ”๋“œ (Legacy Remnants โ€” 1๊ฑด) - -### **C-6: `stop_session.sh` ๋„์›€๋ง ๋ฌธ์„œ ๊ตฌ๋ฒ„์ „ ํ‘œ๊ธฐ** -- ์Šคํฌ๋ฆฝํŠธ ๋„์›€๋ง์—๋Š” `--mode soft|hard` ๋“ฑ์ด ์„œ์ˆ ๋˜์–ด ์žˆ์œผ๋‚˜ ์‹ค์ œ ์˜ต์…˜ ํŒŒ์„œ๋Š” `exit 2`๋กœ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. +## 4. โšช ๋ ˆ๊ฑฐ์‹œ ์ž”์žฌ ๋ฐ ์ฃฝ์€ ์ฝ”๋“œ (Legacy Remnants โ€” 0๊ฑด โ€” ์ „์› ์™„๋ฃŒ) --- -## 5. ๐ŸŽ‰ ์™„๋ฃŒ๋œ ๊ณผ์ œ (Completed Tasks โ€” 19๊ฑด) +## 5. ๐ŸŽ‰ ์™„๋ฃŒ๋œ ๊ณผ์ œ (Completed Tasks โ€” 20๊ฑด) + +### **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`)๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. @@ -250,7 +252,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** | ๋„์›€๋ง 3์ค„ ์ •์ • | ๊ทน์†Œ | โ€” | +| **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 ์‹ ์› ์บ์‹œ ์กด์น˜/์ œ๊ฑฐ ๊ฒฐ์ • + PyYAML ์˜์กด ์™„ํ™” | ์ค‘ | A-4 M2 | | **P3-3** | **C-3b** | `isolation.root` 4๊ฐœ ์†Œ๋น„์ž ์™„์ „ ํ๊ธฐ (Option B ์ฑ„ํƒ) **(โœ… ์™„๋ฃŒ โ€” ์ „์ฒด 259/259 PASS)** | ์†Œ | A-4 M2 | diff --git a/LOG.md b/LOG.md deleted file mode 100644 index 2435d08..0000000 --- a/LOG.md +++ /dev/null @@ -1,146 +0,0 @@ -# ๐Ÿ“ Multi-Agent Mux ์ž‘์—… ์„ธ์…˜ ๊ธฐ๋ก (`LOG.md`) - -- **์ตœ์ข… ๊ธฐ๋ก์ผ์‹œ**: 2026-08-16 10:00 (KST) -- **์ž‘์—… ์ €์žฅ์†Œ**: `tmpl/multi-agent-mux` (Branch: `main`) -- **์ž‘์—… ์ƒํƒœ**: ๋ชจ๋“  ์ž‘์—… ์™„๋ฃŒ, ์„ธ์…˜ ์•ˆ์ „ ์ข…๋ฃŒ(stopped), ์ €์žฅ์†Œ ์ƒํƒœ Clean! - ---- - -## ๐Ÿ“Œ 1. ๊ธˆ์ผ ์ž‘์—… ๋‚ด์šฉ ์š”์•ฝ - -### 1) **P3-1 (A-4 Phase 2 / Option B / C-3b / M2~M7): ์—์ด์ „ํŠธ ์ง€์‹ ๊ณ„์ธต ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฐ isolation.root ์™„์ „ ํ๊ธฐ** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: ์—์ด์ „ํŠธ๋ณ„ ์•„ํ‹ฐํŒฉํŠธ ๊ฒฝ๋กœ, ๊ฒ€์ฆ ๋กœ์ง, ์žฌ๊ฐœ/์‹œ์ž‘ ์ŠคํŽ™, ํ† ํฐ, ์ข…๋ฃŒ ํ‚ค, ์ธ์ฆ(`auth_ok`), ์ž๋™ ๋ฐœ๊ฒฌ(`discover`)์ด ์Šคํฌ๋ฆฝํŠธ ์ „๋ฐ˜์— ํ•˜๋“œ์ฝ”๋”ฉ ์‚ฐ์žฌ๋˜์–ด ์žˆ๋˜ ๋ฌธ์ œ(A-4)์™€, Universal Global Config ์ „ํ™˜ ํ›„์—๋„ 4๊ฐœ ์ง€์ ์— ๋‚จ์•„์žˆ๋˜ `isolation.root` ์†Œ๋น„์ž(C-3b)๋ฅผ ์™„์ „ ํ๊ธฐํ•˜๊ณ  ์–ด๋Œ‘ํ„ฐ ๋‹จ์ผ ์†Œ์Šค๋กœ ์ผ์›ํ™”. -- **์ฃผ์š” ๊ตฌํ˜„**: - - [`.agents/skills/lib_py/agents/base.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/agents/base.py): `DiscoveryContext` ํ™•์žฅ (`ws_key`, `cwd`, `home_dir`, `claude_dir`, `epoch`, `row`, `mode`), `BaseAgentAdapter` ์ถ”์ƒ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜ (`ready_tokens`, `exit_key`, `delegate_agent_key`, `identity_cache_fields`, `artifact_path`, `verify_artifact`, `purge_artifacts`, `spawn_spec`, `resume_spec`, `auth_ok`, `discover`). - - [`.agents/skills/lib_py/agents/adapters/`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/agents/adapters/): `claude.py`, `agy.py`, `hermes.py`, `cline.py` 4๊ฐœ ์–ด๋Œ‘ํ„ฐ ๊ตฌ์ฒด ํด๋ž˜์Šค ๊ตฌํ˜„ (Cline `resume_spec` `-i --id` ์ˆ˜์ • ๋ฐ˜์˜, `auth_ok`, `discover` ๊ตฌํ˜„). - - [`.agents/skills/lib_py/agents/__main__.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/agents/__main__.py): 8๊ฐœ `MAM_*` ๋ณ€์ˆ˜ `shlex.quote` ์…ธ ๋ธŒ๋ฆฌ์ง€ ์™„์„ฑ. - - [`.agents/skills/lib_py/verify_session.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/verify_session.py): `adapter.verify_artifact(uuid, ctx)` ์œ„์ž„ ๋ฐ `iso_root` ๋ถ„๊ธฐ ์ œ๊ฑฐ. - - [`.agents/skills/lib_py/workspace_uuid.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/workspace_uuid.py): `iso_root_of` ์ œ๊ฑฐ ๋ฐ ๋””์Šคํฌ ์Šค์บ”์„ `adapter.discover(ctx)`๋กœ ๋‹จ์ผํ™”. - - [`.agents/skills/lib_py/atomic_yaml.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/atomic_yaml.py): ๋ ˆ๊ฑฐ์‹œ `isolation` ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ ˆ ์ œ๊ฑฐ. - - [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh): `mam_session_iso_root` ์ œ๊ฑฐ, `wait_for_tui_ready` ์…€ํ”„ ์ปจํ…Œ์ธ๋“œ ํ† ํฐ ํด๋ฐฑ ๋ฐ claude `projects` ํ† ํฐ ์ œ๊ฑฐ. - - [`.agents/skills/multi-agent-mux-create/scripts/create_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-create/scripts/create_session.sh): `CMD_FULL` (์–ด๋Œ‘ํ„ฐ `spawn_spec`) ๋ฐ `delegate_agent` (`delegate_agent_key`) ์ด๊ด€. - - [`.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh): `_iso_root` ๋ถ„๊ธฐ ์™„์ „ ์ œ๊ฑฐ ๋ฐ `CMD_FULL` ์„ `adapter.resume_spec`์œผ๋กœ ์ด๊ด€. - - [`.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh): `row_agent` / `_pin_and_verify_resume` / `OWN_KEY_BY_AGENT` / auto-register `cmd_full` ์„ ์–ด๋Œ‘ํ„ฐ ๋ ˆ์ด์–ด๋กœ ์ด๊ด€. - - [`.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh): `exitkey` (`adapter.exit_key`), `adapter.purge_artifacts`, `adapter.identity_cache_fields` ์œ„์ž„ ๋ฐ ๋ ˆ๊ฑฐ์‹œ ๊ฒฉ๋ฆฌ ์‚ญ์ œ ๋ธ”๋ก ์ œ๊ฑฐ. - - [`tests/test_a4_adapter_contract.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_a4_adapter_contract.py): facts eval ๊ณ„์•ฝ, ์–ด๋Œ‘ํ„ฐ ์†์„ฑ ๊ณ„์•ฝ, ๋ณตํ•ฉ ์•„ํ‹ฐํŒฉํŠธ ์‚ญ์ œ(purge_artifacts), spawn/resume_spec ๊ณ„์•ฝ, auth_ok ๊ณ„์•ฝ, discover ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ 9์ข… ์ถ”๊ฐ€. - - [`IMPROVEMENTS.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/IMPROVEMENTS.md): A-4 ๋ฐ C-3b ์™„๋ฃŒ ์ฒ˜๋ฆฌ ๋ฐ 19๊ฐœ ๊ณผ์ œ ์™„๊ฒฐ ์ƒํƒœ ๋™๊ธฐํ™”. -- **๊ฒ€์ฆ**: `pytest` ์‹คํ–‰ ๊ฒฐ๊ณผ **259 passed in 493s (100%)**. - -### 2) **P2-2 (C-3a / C-4): ๋ ˆ๊ฑฐ์‹œ ๊ฒฉ๋ฆฌ ์Šคํ… ๋ฐ ๋ฏธ์‚ฌ์šฉ ์‹ฌ๋ณผ ์ œ๊ฑฐ** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: ๊ฒฉ๋ฆฌ ๊ตฌ์กฐ๊ฐ€ Universal Global Config(Job `536a6625`)๋กœ ์ „ํ™˜๋˜๋ฉฐ ๋‚จ์€ ๋นˆ ์Šคํ… 4์ข…๊ณผ, ๊ทธ ๋นˆ ์ถœ๋ ฅ๋งŒ ์žฌํ™•์ธํ•˜๋˜ ๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 4๊ฑด, ๊ทธ๋ฆฌ๊ณ  ์ฐธ์กฐ 0ํšŒ ์‹ฌ๋ณผ 3์ข… ์ •๋ฆฌ. -- **์ฃผ์š” ๊ตฌํ˜„**: - - [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh): ๋นˆ ์Šคํ… 4์ข…(`provision_isolation`, `isolation_lever`, `isolation_env_prefix`, `isolation_cmd_args`) ๋ฐ `_REAL_HERDR_PATH` ๋Œ€์ž…ยทexport ์ œ๊ฑฐ, ์ฃผ์„์— C-3b ๊ฒฝ๊ณ„ ๋ช…์‹œ. - - [`.agents/skills/multi-agent-mux-delegate-job/scripts/registry.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-delegate-job/scripts/registry.py): `TERMINAL_STATUSES` ์ œ๊ฑฐ. - - [`.agents/skills/multi-agent-mux-create/scripts/create_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-create/scripts/create_session.sh): `ISOLATE` ์ œ๊ฑฐ. - - [`tests/test_tier1_unit.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_tier1_unit.py) / [`tests/test_tier2_component.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_tier2_component.py): ๊ณตํ—ˆํ•œ ํ…Œ์ŠคํŠธ 4๊ฑด ์ œ๊ฑฐ ๋ฐ `--isolate`/`--no-isolate` no-op ํšŒ๊ท€ ๊ฐ€๋“œ 1๊ฑด ์‹ ์„ค(๋ณ€์ด 4์ข… ๊ฒ€์ถœ ์ž…์ฆ), ์„น์…˜ ํ—ค๋” ๋™๊ธฐํ™”. - - [`IMPROVEMENTS.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/IMPROVEMENTS.md): C-4 ์™„๊ฒฐ ๋ฐ C-3a ์™„๋ฃŒ ๋ฐ˜์˜, C-3b ์กด์†. -- **๊ฒ€์ฆ**: `pytest tests/ -q` **256 passed (100%)**. - -### 2) **P2-1 (B-6 / B-12): `delegate_job_safe` ์ž„์‹œ ์‚ฌ๋ณธ ์ œ๊ฑฐ ๋ฐ ์„œ๋ธŒ์…ธ ๋ฃจํ”„ ๋ฝ ์กฐ๊ธฐ ํ•ด์ œ ์ฐจ๋‹จ ์กฐ์น˜** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: `run_loop.sh::delegate_job_safe` ๊ฐ€ `.agents/skills/...` ๋‚ด๋ถ€์— `.tmp` ์‚ฌ๋ณธ์„ ์ƒ์„ฑํ•˜์—ฌ ํŠธ๋ฆฌ ์˜ค์—ผ ๋ฐ ๋ฐฐํฌ ์‹œ ์œ ์ถœ(B-6)๋˜๋˜ ๋ฌธ์ œ์™€, ๋ช…๋ น ์น˜ํ™˜ ์„œ๋ธŒ์…ธ ๋‚ด์˜ `trap _mam_release_guard EXIT` ๋กœ ์ธํ•ด ์ฒซ ๋ฒˆ์งธ ์žก ์œ„์ž„ ์‹œ ๋ฃจํ”„ ๋ฝ ๋งˆ์ปค(`.mam/loop-guard-active`)๊ฐ€ ์กฐ๊ธฐ ์‚ญ์ œ๋˜์–ด O-3 ๊ฐ€๋“œ๋ ˆ์ผ์ด ๋ฌด๋ ฅํ™”๋˜๋˜ ๊ฒฐํ•จ(**B-12 / D1**) ์กฐ์น˜. -- **์ฃผ์š” ๊ตฌํ˜„**: - - [`.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh): `delegate_job_safe` ๋ฅผ ์ž„์‹œ ์‚ฌ๋ณธ ๋ฐ ์„œ๋ธŒ์…ธ ํŠธ๋žฉ ์—†์ด ์ธํ”Œ๋ ˆ์ด์Šค๋กœ ์ง์ ‘ ์‹คํ–‰(`bash "$orig_script" "$@"`)ํ•˜๋„๋ก ๊ฐœ์„ ํ•˜๊ณ  ์‹คํŒจ ์‹œ ์ง„๋‹จ ๋กœ๊น… ์ถ”๊ฐ€. ๋ฃจํ”„ ๊ธฐ๋™ ์‹œ ๊ธฐ์กด ์ž”์—ฌ `.tmp` ์Šค์œ• ๊ตฌ๋ฌธ ์ถ”๊ฐ€. - - [`IMPROVEMENTS.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/IMPROVEMENTS.md): B-6 ์™„๋ฃŒ ์ƒํƒœ ๊ฐฑ์‹ , B-12 (D1) ๊ฒฐํ•จ ๋ช…์„ธ ๋ฐ B-13 (ํ„ด ๊ฐ„ ์Šคํ‚ฌ ์˜ค์—ผ) Stage 2 ๊ณผ์ œ ๋“ฑ๋ก. - - [`tests/test_o3_scoped_guard.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/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`)๋กœ ๊ต์ฒด. -- **๊ฒ€์ฆ**: `pytest tests/ -q` ์‹คํ–‰ ๊ฒฐ๊ณผ **259 passed (100%)** ๋‹ฌ์„ฑ. - -### 2) **multi-agent-mux-orc-onboard: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ์˜จ๋ณด๋”ฉ ์Šคํ‚ฌ ๋ฐ `orchestrator_uuids` ๋ฐฐ์ œ ๊ฒŒ์ดํŠธ ๊ตฌ์ถ•** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ(`agy`)๊ฐ€ ์„œ๋ธŒ ์—์ด์ „ํŠธ ์ƒ์„ฑ/์ •์ง€/๋ณต์› ์‹œ ์ž๊ธฐ ๋Œ€ํ™” UUID๊ฐ€ `agent-sessions.yaml` ์„œ๋ธŒ ์„ธ์…˜์œผ๋กœ ์˜ค์—ผ ์บก์ฒ˜๋˜์–ด SQLite DB ๋ฝ(`database is locked`) ๋ฐ ๋Œ€ํ™” ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋˜ ๊ฒฐํ•จ ์กฐ์น˜. -- **์ฃผ์š” ๊ตฌํ˜„**: - - [`.agents/skills/multi-agent-mux-orc-onboard/SKILL.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-orc-onboard/SKILL.md) ๋ฐ [`.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh): ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ์˜ ์‹ ์› UUID๋ฅผ ํฌ์ฐฉํ•˜์—ฌ `.mam/agent-sessions.yaml` ๋ฐ SQLite DB ๋‚ด `orchestrator_uuids` ๋ฆฌ์ŠคํŠธ๋กœ ์›์ž์  ๋“ฑ๋กํ•˜๋Š” ์Šคํ‚ฌ ๊ตฌ์ถ•. - - [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh): `find_workspace_uuid` ๋ฐ `verify_session_uuid`์— `orchestrator_uuids` ๋ฐฐ์ œ ๊ฒŒ์ดํŠธ๋ฅผ ๋‚ด์žฅํ•˜์—ฌ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ๋Œ€ํ™” ID ์Šคํ‚ต(Skip) ํ™•๋ฆฝ. - - `tests/test_orc_onboard.py`: ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ 40๊ฐœ ์ž‘์„ฑ ๋ฐ **40/40 PASS (100%)** ๋‹ฌ์„ฑ. -- **๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์ž์œจ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜**: `/multi-agent-mux-loop --plan --all-reviewer` ๊ฐ€๋™ ๊ฒฐ๊ณผ Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3์ž์— ์˜ํ•ด **`[VERDICT: PASS]` (๋งŒ์žฅ์ผ์น˜ ํ†ต๊ณผ)**. - -### 2) **P0-2 (O-2): ๋™์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‚ด ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ๋ฐฉ์ง€ ์›์ž์  ๋ฝ ๋ฐ ๋งˆ์ปค ์†Œ์œ ๊ถŒ ๋Œ€์กฐ ์‚ญ์ œ ์กฐ์น˜** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: ๋ฃจํ”„ ์ค‘๋ณต ๊ธฐ๋™ ์‹œ ๋งˆ์ปค ๋ฌด๋‹จ ๋ฎ์–ด์“ฐ๊ธฐ๋กœ ์ธํ•œ ๋ฐ์ดํ„ฐ ์˜ค์—ผ ๋ฐ ๋จผ์ € ์ข…๋ฃŒ๋œ ๋ฃจํ”„ ์ธ์Šคํ„ด์Šค์˜ ๋ฌด์ฐจ๋ณ„ ๋งˆ์ปค ์‚ญ์ œ๋กœ O-3 ์œ„์ž„ ๊ฐ€๋“œ๋ ˆ์ผ์ด ์กฐ์šฉํžˆ ๋ฌด๋ ฅํ™”๋˜๋˜ ๊ฒฐํ•จ ์กฐ์น˜. -- **์ฃผ์š” ๊ตฌํ˜„**: - - [`.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` ๊ธฐ๋ฐ˜ ์›์ž์  ๋ฝ ํš๋“, `pid` + `lstart` ์‹ ์› ๋Œ€์กฐ ๊ฒ€์ฆ ๋ฐ ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ์ฐจ๋‹จ ๋ชจ๋“ˆ ๊ตฌํ˜„. - - [`.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh): `_mam_release_guard` ์ข…๋ฃŒ ํŠธ๋žฉ ์‹œ `pid` + `lstart` ์†Œ์œ ๊ถŒ ๋Œ€์กฐ ๊ฒ€์ฆ ์‚ญ์ œ ๊ตฌํ˜„. - - `tests/test_o2_race_free_lock.py`: ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ 22๊ฐœ ์ž‘์„ฑ ๋ฐ **22/22 PASS (100%)** ๋‹ฌ์„ฑ. ์ „์ฒด ํšŒ๊ท€ ํ…Œ์ŠคํŠธ **46/46 PASS (100%)**. - -### 2) **P0-1 (B-7): `run_loop.sh` ๋ฃจํ”„ ๊ธฐ๋™ ์™ธ๊ณฝ diff ๋ˆ„๋ฝ ๋ฐ ์‹ ๊ทœ ๋ฏธ์ถ”์  ํŒŒ์ผ ์บก์ฒ˜ ๊ฒฐํ•จ ์กฐ์น˜** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: CWD ์˜์กด์„ฑ์œผ๋กœ ์ธํ•ด ์ €์žฅ์†Œ ์™ธ๊ณฝ์—์„œ `run_loop.sh` ๊ตฌ๋™ ์‹œ `git diff` ์‹คํŒจ ๋ฐ ๋ฏธ์ถ”์  ์‹ ๊ทœ ํŒŒ์ผ(Untracked Files) ๋ˆ„๋ฝ์œผ๋กœ ๋ฆฌ๋ทฐ์–ด๊ฐ€ ๋นˆ diff ๋ณด๊ณ  ๋ฌด์กฐ๊ฑด `PASS`๋ฅผ ๋‚จ๊ธฐ๋˜ ๋ฌด์Œ ๊ฒ€์ฆ ๊ฒฐํ•จ ์กฐ์น˜. -- **์ฃผ์š” ๊ตฌํ˜„**: - - [`.agents/skills/multi-agent-mux-loop/scripts/diff_collect.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/diff_collect.sh): CWD ๋…๋ฆฝ `$REPO_ROOT` ์ด๋™ ๋ฐ Git ์ธ๋ฑ์Šค ๋น„์นจ์Šต ์‹ ๊ทœ ํŒŒ์ผ ๋ณ‘ํ•ฉ(`git ls-files -o --exclude-standard -z` + `git diff --no-index`) ๊ตฌํ˜„. - - [`.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh): `CHANGES_DIFF` ๋ชจ๋“ˆํ™” ๋ฐ 500์ค„/30KB ์ƒํ•œ Truncation ๊ฒฝ๊ณ  ๋…ธ์ถœ ๋‚ด์žฅ. - - `tests/test_b7_diff_untracked.py`: ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ 20๊ฐœ ์ž‘์„ฑ ๋ฐ **20/20 PASS (100%)** ๋‹ฌ์„ฑ. -- **๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์ž์œจ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜**: `/multi-agent-mux-loop --plan --all-reviewer` ๊ฐ€๋™ ๊ฒฐ๊ณผ Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3์ž์— ์˜ํ•ด **`[VERDICT: PASS]` (๋งŒ์žฅ์ผ์น˜ ํ†ต๊ณผ)**. - -### 2) **B-4: ์‹œํ”„ํŠธ `ls` ์„ธ์…˜ ์ƒ์„ฑ ์‹œ๊ฐ(session_created) ๋™์  ํฌ์‹œ์Šค ํƒ€์ž„์Šคํƒฌํ”„ ๋ณต์›** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: `.agents/skills/lib.sh` 554๋ฒˆ ๋ผ์ธ์—์„œ `herdr ls` ์‹œ ์ƒ์„ฑ์‹œ๊ฐ์ด `999999`๋กœ ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด `reconcile.sh` drift-B ๋“ฑ๋ก ์‹œ epoch 0์ด ๋˜์–ด `find_workspace_uuid` ์žฌ๊ฐœ ๊ฐ€๋“œ๊ฐ€ ๋ถ•๊ดด๋˜๋˜ ๊ฒฐํ•จ ์กฐ์น˜. -- **์ฃผ์š” ๊ตฌํ˜„**: - - [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh): real herdr ๋ฐ YAML ์ƒ์˜ `created`/`created_at`/`created_epoch` ์†์„ฑ์„ ์ฝ๊ณ , ๋ฏธ์ •์˜ ์‹œ `int(time.time())` ๋™์  ํฌ์‹œ์Šค ํƒ€์ž„์Šคํƒฌํ”„๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ์ •์ œ. - - [`reconcile.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh): `created` fallback ํฌ๋งทํŒ… ๋ณด์™„. - - `tests/test_b4_session_created.py`: ์ „์šฉ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ 21๊ฐœ ํ•ญ๋ชฉ ์ž‘์„ฑ ๋ฐ **21/21 PASS (100%)** ๋‹ฌ์„ฑ. -- **๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์ž์œจ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜**: `/multi-agent-mux-loop --plan --all-reviewer` ๊ฐ€๋™ ๊ฒฐ๊ณผ Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3์ž์— ์˜ํ•ด **`[VERDICT: PASS]` (๋งŒ์žฅ์ผ์น˜ ํ†ต๊ณผ)**. - -### 2) **deploy/ ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ ์ตœ์‹ ํ™” ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ 3-way ๋ณ‘ํ•ฉ ๊ตฌํ˜„** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: `deploy/install.sh` ๋ฐ `install_mam.sh`๊ฐ€ `.agents/skills/` ๋ฐ– ์ž์‚ฐ(`hooks.json`, `MULTI_AGENT_RULES.md`, `INSTALL.md`)์„ ๊ฐฑ์‹ ํ•˜์ง€ ๋ชปํ•˜๊ฑฐ๋‚˜ ๋กœ์ปฌ ํ›… ์ˆ˜์ •์„ ๋ฎ์–ด์“ฐ๋Š” ๋งน์ (Job `1567c88e` / Plan Rev.2) ํ•ด๊ฒฐ. -- **์ฃผ์š” ๊ตฌํ˜„**: - - `deploy/lib_ownership.sh` ์‹ ์„ค: ์ž์‚ฐ ์†Œ์œ ๊ถŒ ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํŒŒ์ผ ๊ด€๋ฆฌ ๋‹จ์ผ ์ฐฝ๊ตฌํ™”. - - `deploy/install.sh`: `hooks.json` ํ‚ค ๋‹จ์œ„ 3-way ๋ณ‘ํ•ฉ(`MERGE_REGISTRY`) ๋ฐ `.mam/base/` ์Šค๋ƒ…์ˆ ๋„์ž…. - - `deploy/install_mam.sh` & `deploy/remove.sh`: `asset_hashes.txt` ๋ฐ `.mam/base/` ์ž๋™ ์ƒ์„ฑ๊ณผ fallback ์ž์‚ฐ ๋ชฉ๋ก ๋™๊ธฐํ™”. - - `deploy/gitea-ci.yml` & `deploy/README.md`: CI pytest ์ž๋™ํ™” ๊ฒŒ์ดํŠธ ๋ฐ ๋ฌธ์„œ ๊ตฌ์กฐ ๊ฐฑ์‹ . - - ์ปค๋ฐ‹ ์™„๋ฃŒ (`399242d`, `cc11a02`). - -### 2) **ํ…Œ์ŠคํŠธ ์ŠˆํŠธ ๊ฒฝ๋Ÿ‰ํ™” ๋ฐ ๋‹ค์ด์–ดํŠธ** โ€” **์™„๋ฃŒ** -- ์ค‘๋ณต๋˜๊ณ  ์˜ค๋ž˜๋œ ๋ ˆ๊ฑฐ์‹œ ํ…Œ์ŠคํŠธ 7๊ฐœ ํŒŒ์ผ(1,559์ค„) ์™„์ „ํžˆ ์‚ญ์ œ (`cf51b2c`). -- ํ•ต์‹ฌ ๊ณ„์ธต๋ณ„ ํ…Œ์ŠคํŠธ ์ŠˆํŠธ(Tier 1~4, Deploy, Guard)๋งŒ ์ •๋น„ํ•˜์—ฌ ํ–ฅํ›„ ๊ธฐ๋Šฅ ๋ณ€๊ฒฝ ์‹œ ์‹คํ–‰ ์†๋„ ๋ฐ ์ž์› ์†Œ๋ชจ ๋Œ€ํญ ๊ฐœ์„ . - -### 3) **O-3: ์กฐ๊ฑด๋ถ€ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์œ„์ž„ ๊ฐ€๋“œ (Invocation-Aware Scoped Guard)** โ€” **์™„๋ฃŒ** -- **๋ฐฐ๊ฒฝ**: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ์—์ด์ „ํŠธ๊ฐ€ `/multi-agent-mux-loop` ์‹คํ–‰ ์‹œ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์Šคํฌ๋ฆฝํŠธ๋กœ ์œ„์ž„ํ•˜๋„๋ก ํ†ต์ œํ•˜๋ฉฐ, ๋ฃจํ”„ ๋‚ด๋ถ€์—์„œ ๋ฌดํ•œ ์žฌ๊ท€ ๊ธฐ๋™๋˜๋Š” ํ˜„์ƒ์„ ์›์ฒœ ๋ฐฉ์ง€ํ•จ. -- **์ฃผ์š” ์ˆ˜์ • ํŒŒ์ผ**: - - `.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`: PID + ์‹œ์ž‘์‹œ๊ฐ ๊ธฐ๋ฐ˜ `.mam/loop-guard-active` ์‹๋ณ„์ž ์ž‘์„ฑ ๋ฐ `trap` ์ž๋™ ์‚ญ์ œ ์ ์šฉ. - - `AGENTS.md`: Section 5 (Orchestrator Scope Guard O-3) ๋ช…์‹œ. - - `.agents/MULTI_AGENT_RULES.md` & `.ko.md`: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ์„ธ์…˜ ๋ฐ ๋ฃจํ”„ ํ™œ์„ฑํ™” ๋ชจ๋“œ ์ˆ˜์น™ ๋™๊ธฐํ™”. - - `tests/test_o3_scoped_guard.py`: 24๊ฐœ ๊ฒ€์ฆ ์ผ€์ด์Šค ์ž‘์„ฑ (24/24 PASS). -- **๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ์ž์œจ ํ”ผ์–ด ๋ฆฌ๋ทฐ**: Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3์ž์— ์˜ํ•ด ๋ฃจํ”„ ๊ตฌ๋™ ํ›„ **`[VERDICT: PASS]` (100% ํ•ฉ์˜)** ํ†ต๊ณผ ๋ฐ ์ปค๋ฐ‹ ์™„๋ฃŒ (`1f8622e`). - -### 2) **A-3 & C-2 ๊ณผ์ œ ์™„์ˆ˜ ๋ฐ ์•ˆ์ •ํ™” ๋ฒ„๊ทธ ์ˆ˜์ •** โ€” **์™„๋ฃŒ** -- **A-3**: `send_keys_safe` ์‹œํ”„ํŠธ ๋ฒ„ํผ ๋™์‹œ์„ฑ ๋ ˆ์ด์Šค ์กฐ๊ฑด ํ•ด๊ฒฐ (ํ˜ธ์ถœ ๊ณ ์œ  ํ† ํฐ ์ƒ์„ฑ + ์›์ž์  ์“ฐ๊ธฐ/์ด๋™ + 60๋ถ„ ์ž๋™ GC). -- **C-2**: ๋ฏธ์‚ฌ์šฉ `.cache/multi-agent-mux-monitor` ๋””๋ ‰ํ„ฐ๋ฆฌ ์ƒ์„ฑ ๋กœ์ง ์ถ•์†Œ ๋ฐ `reconcile.sh` ์ƒํƒœ dead code ์ •๋ฆฌ. -- **ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ „ํŒŒ ๋ณด์™„**: `.agents/skills/lib.sh` ๋‚ด `HOME_DIR`, `CLAUDE_PROJECT_DIR`, `LOCAL_BIN` ํ•˜์œ„ ํ”„๋กœ์„ธ์Šค `export` ๋ˆ„๋ฝ ํ•ด๊ฒฐ (`2fc0f58`). -- **ํ…Œ์ŠคํŠธ ์ŠˆํŠธ Mock ์ง€์›**: `tests/conftest.py` ๋‚ด `mock_herdr`์— `list-panes` ํ•ธ๋“ค๋Ÿฌ ์ถ”๊ฐ€ (`778b22b`). -- **์ƒํƒœ ๋ณต๊ตฌ ์•ˆ์ „์„ฑ**: `reconcile.sh` ๋‚ด ์„ธ์…˜ ์ƒ์„ฑ ์‹œ๊ฐ ์•ˆ์ „ ํ‚ค ์ ‘๊ทผ(`t.get('created', 0)`) ๋ฐ˜์˜ (`36d0178`). - ---- - -## Git ์ปค๋ฐ‹ ๋‚ด์—ญ (Total 8 Commits on `refactor`) - -1. `2fc0f58`: `fix(lib): export HOME_DIR, CLAUDE_PROJECT_DIR, and LOCAL_BIN in lib.sh for proper child environment inheritance` -2. `55fc739`: `fix(lib): use symlink-safe realpath comparison for workspace cwd matching in find_workspace_uuid` -3. `778b22b`: `fix(test): add list-panes support to mock_herdr and fix environment overrides in tier3 integration tests` -4. `9f266e6`: `test(integration): update test_tier3_integration to align with global config-home convention` -5. `7e16d65`: `test(integration): refine test_integration_create_options_combination to test herdr spawn without wrapper` -6. `1658af4`: `test(sanity): update test_sanity assertions to align with removed config-home isolation` -7. `1f8622e`: `feat(o3): implement Invocation-Aware Scoped Guard for orchestrator role scoping (100% PASS)` -8. `5ab7687`: `fix(c2): remove unused .cache directory creation and clean up state dead code (100% PASS)` -9. `3530e8b`: `fix(a3): resolve shift buffer race condition with call-unique tokens, atomic write, and automatic GC (100% PASS)` - ---- - -## ๐Ÿค– 3. ๋ผ์ด๋ธŒ ์—์ด์ „ํŠธ ์„ธ์…˜ ํ˜„ํ™ฉ (`herdr: multi-agent-mux`) - -| ์—์ด์ „ํŠธ ์ด๋ฆ„ | ์—ญํ•  | herdr ์„ธ์…˜ ์ƒํƒœ | ๋น„๊ณ  | -| :--- | :--- | :--- | :--- | -| `canary-projects-multi-agent-mux-creator-claude` | Planner | `stopped` | ๋Œ€ํ™” UUID `01eae7cf...` ์บก์ฒ˜ ๋ณด์กด ์™„๋ฃŒ | -| `canary-projects-multi-agent-mux-creator-agy` | Creator | `stopped` | ๋Œ€ํ™” UUID `72d2d251...` ์บก์ฒ˜ ๋ณด์กด ์™„๋ฃŒ | -| `canary-projects-multi-agent-mux-creator-cline` | Reviewer | `stopped` | ๋Œ€ํ™” UUID `17856352...` ์บก์ฒ˜ ๋ณด์กด ์™„๋ฃŒ | - ---- - -## ๐Ÿš€ 4. ์ถ”ํ›„ ์ž‘์—… ์žฌ๊ฐœ ๊ฐ€์ด๋“œ (Next Steps) - -1. **์„ธ์…˜ ์ƒํƒœ ํ™•์ธ**: - ```bash - bash .agents/skills/multi-agent-mux-status/scripts/status_session.sh - ``` -2. **๋ฐฑ๋กœ๊ทธ ํ™•์ธ (`IMPROVEMENTS.md`)**: - - ๋‹ค์Œ ์šฐ์„ ์ˆœ์œ„ ์ถ”์ฒœ ๊ณผ์ œ: - - **O-2**: ๋™์ผ ์›Œํฌ์ŠคํŽ˜์ด์Šค ๋‚ด ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ๋ฐฉ์ง€ ๋ฝ (Race-Free Lock) - - **B-4**: ์‹œํ”„ํŠธ `ls`์˜ `created=0` ํ•˜๋“œ์ฝ”๋”ฉ ํ•ด๊ฒฐ -3. **๋ฃจํ”„ ๊ตฌ๋™์œผ๋กœ ์ž‘์—… ์žฌ๊ฐœ**: - ```bash - /multi-agent-mux-loop --plan --all-reviewer "IMPROVEMENTS.md ๋ฐฑ๋กœ๊ทธ์˜ O-2 (๋˜๋Š” ์„ ํƒ ๊ณผ์ œ) ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์ค˜." - ``` diff --git a/MESSAGING.md b/MESSAGING.md index 347b321..79c87ed 100644 --- a/MESSAGING.md +++ b/MESSAGING.md @@ -343,9 +343,9 @@ Valid values (see `lib.sh` valid-status set): | State | Meaning | Set by | |---|---|---| | `running` | herdr session active, agent running | `create`, `resume` | -| `stopped` | deliberately stopped via `--capture-id`/`--reason`/`--graceful`; conversation preserved for resume | `stop` (STOP mode) | -| `terminated` | hard-killed via `--mode hard`; herdr session destroyed | `stop` (hard mode), `monitor` reconcile | -| `archived` | soft-stopped via `--mode soft`; herdr left alive, YAML-only update | `stop` (soft mode) | +| `stopped` | stopped via `multi-agent-mux-stop` (default); conversation preserved for resume | `stop` | +| `terminated` | stopped with `--purge-conversation`, or herdr-dead detected; conversation deleted / session gone | `stop --purge-conversation`, `monitor` reconcile | +| `archived` | legacy value โ€” no producer since `--mode soft` was removed; kept in the validation whitelist for rows written by older versions | (none) | ### Job States (Registry โ€” `.mam/jobs/.json`) Managed by `.agents/skills/multi-agent-mux-delegate-job/scripts/registry.py`. diff --git a/VERSIONS.md b/VERSIONS.md new file mode 100644 index 0000000..7147480 --- /dev/null +++ b/VERSIONS.md @@ -0,0 +1,139 @@ +# ๐Ÿ“œ Multi-Agent Mux ๋ฒ„์ „ ์ด๋ ฅ (`VERSIONS.md`) + +์ด ๋ฌธ์„œ๋Š” `multi-agent-mux` ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ฒ„์ „๋ณ„ ์ฃผ์š” ๊ธฐ๋Šฅ ์ถ”๊ฐ€, ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์„ , ๋ฒ„๊ทธ ์ˆ˜์ • ๋ฐ ํ’ˆ์งˆ ๊ฒ€์ฆ ์ด๋ ฅ์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. + +--- + +## ๐Ÿ“Œ ํ˜„์žฌ ๋ฒ„์ „ ๊ฐœ์š” (Current Release) + +- **ํ”„๋ ˆ์ž„์›Œํฌ ๋ฒ„์ „**: `v2.0.0` +- **์ตœ์‹  ๋ฆด๋ฆฌ์Šค ์ผ์‹œ**: 2026-08-17 (KST) +- **๊ธฐ์ค€ ๋ธŒ๋žœ์น˜**: `main` +- **ํ•ต์‹ฌ ์•„ํ‚คํ…์ฒ˜**: + - **A-4 Agent Adapter Layer**: 4๋Œ€ ์—์ด์ „ํŠธ(`claude`, `agy`, `hermes`, `cline`) ์ง€์‹ ๊ณ„์ธต ๋‹จ์ผ ์†Œ์Šค ์ธํ„ฐํŽ˜์ด์Šค + - **Universal Herdr Session Isolation**: ๋‹จ์ผ Herdr ์„œ๋ฒ„ ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ์„ธ์…˜ ๊ฒฉ๋ฆฌ + - **O-3 Orchestrator Scope Guard**: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ์˜ ์ง์ ‘ ์ฝ”๋“œ ๋ณ€์กฐ ๋ฐฉ์ง€ ๋ฐ ์Šคํฌ๋ฆฝํŠธ ์œ„์ž„ ํ†ต์ œ + - **Tier-1 Fast-Path Lifecycle**: 0ms ์ง€์—ฐ์˜ ๋Œ€ํ™” UUID ์บก์ฒ˜ ๋ฐ ์ดˆ๊ณ ์† ์žฌ๊ฐœ(Resume) + +--- + +## ๐Ÿงญ ์Šคํ‚ฌ ํŒจํ‚ค์ง€ ๋ฒ„์ „ ๋งคํŠธ๋ฆญ์Šค (Skills Version Matrix) + +๋ชจ๋“  8๊ฐœ ์Šคํ‚ฌ์€ YAML frontmatter ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(`author`, `version`, `platforms`, `environments`) ํ‘œ์ค€ํ™”๋ฅผ ํ†ตํ•ด `v2.0.0`์œผ๋กœ ๋™๊ธฐํ™”๋˜์–ด ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. + +| ์Šคํ‚ฌ๋ช… | ๋ฒ„์ „ | ์—ญํ•  ๋ฐ ์ฃผ์š” ์ฑ…์ž„ | ์ƒํƒœ | +| :--- | :---: | :--- | :---: | +| **`multi-agent-mux-create`** | `2.0.0` | ์—์ด์ „ํŠธ ์„ธ์…˜ ์‹ ๊ทœ ์ƒ์„ฑ ๋ฐ Herdr ์ปจํ…Œ์ด๋„ˆ ๊ฒฉ๋ฆฌ ์Šคํฐ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-stop`** | `2.0.0` | ๋Œ€ํ™” UUID ์›์ž์  ์บก์ฒ˜ ๋ฐ ์„ธ์…˜ ์•ˆ์ „ ์ข…๋ฃŒ (Graceful Stop) | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-resume`** | `2.0.0` | ์˜จ๋””์Šคํฌ ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ Tier-1 ์ดˆ๊ณ ์† ์„ธ์…˜ ๋ณต์› | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-status`** | `2.0.0` | ์‹ค์‹œ๊ฐ„ Herdr ์„ธ์…˜ ๋ฐ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋“œ๋ฆฌํ”„ํŠธ ์Šค๋ƒ…์ƒท ์กฐํšŒ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-monitor`** | `2.0.0` | YAML โ†” ๋Ÿฐํƒ€์ž„ ์ƒํƒœ ๊ฐ„ ์ž์œจ ์กฐ์ •์ž (Reconciler Loop) | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-delegate-job`** | `2.0.0` | MQTT ์ด๋ฒคํŠธ ์ฑ„๋„ ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ๋‹จ์œ„ ์ž‘์—… ์œ„์ž„ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-loop`** | `2.0.0` | Planner-Creator-Reviewer 3์ž ์ž์œจ ๊ณ„ํšยท์‹คํ–‰ยทํ”ผ์–ด๋ฆฌ๋ทฐ ๋ฃจํ”„ | โœ… ๋ฐฐํฌ | +| **`multi-agent-mux-orc-onboard`** | `2.0.0` | ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ UUID ๊ฒฉ๋ฆฌ ๋“ฑ๋ก ๋ฐ ์„œ๋ธŒ ์„ธ์…˜ ์˜ค์—ผ ๋ฐฉ์ง€ | โœ… ๋ฐฐํฌ | + +--- + +## ๐Ÿ“‹ ๋ฒ„์ „๋ณ„ ์ƒ์„ธ ๋ณ€๊ฒฝ ๋‚ด์—ญ (Changelog) + +### ๐Ÿš€ `v2.0.0` โ€” Unified Agent Adapter Architecture & Herdr Standardization (2026-08-17) + +> **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ์—์ด์ „ํŠธ ์ง€์‹ ๊ณ„์ธต ๋‹จ์ผ ์†Œ์Šคํ™”(A-4), ๋ ˆ๊ฑฐ์‹œ ๊ฒฉ๋ฆฌ ์™„์ „ ํ๊ธฐ(Option B), ์…ธ ๋ธŒ๋ฆฌ์ง€ ํ•˜๋“œ๋‹ ๋ฐ ์Šคํ‚ฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ทœ๊ฒฉํ™” ์™„๋ฃŒ. + +#### 1. ์—์ด์ „ํŠธ ์ง€์‹ ๊ณ„์ธต ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ (A-4 Phase 2 / P3-1) +- **`BaseAgentAdapter` ์ถ”์ƒ ํด๋ž˜์Šค ๋ฐ 4๋Œ€ ์–ด๋Œ‘ํ„ฐ ๊ตฌ์ถ•**: + - [`.agents/skills/lib_py/agents/base.py`](.agents/skills/lib_py/agents/base.py): `DiscoveryContext` ๋ฐ ์ถ”์ƒ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜ (`ready_tokens`, `exit_key`, `delegate_agent_key`, `identity_cache_fields`, `artifact_path`, `verify_artifact`, `purge_artifacts`, `spawn_spec`, `resume_spec`, `auth_ok`, `discover`). + - [`.agents/skills/lib_py/agents/adapters/`](.agents/skills/lib_py/agents/adapters/): `ClaudeAgentAdapter`, `AgyAgentAdapter`, `HermesAgentAdapter`, `ClineAgentAdapter` 4๊ฐœ ๊ตฌ์ฒด ํด๋ž˜์Šค ๊ตฌํ˜„. +- **`facts` ๋ธŒ๋ฆฌ์ง€ ์…ธ ์ธํ„ฐํŽ˜์ด์Šค ํ•˜๋“œ๋‹**: + - `lib_py.agents` CLI ๋ชจ๋“ˆ์„ ํ†ตํ•ด 8๊ฐœ `MAM_*` ๋ณ€์ˆ˜๋ฅผ `shlex.quote` ์•ˆ์ „ ์ธ์šฉ ์ฒ˜๋ฆฌํ•˜์—ฌ ๋ฐฉ์ถœ. + - `wait_for_tui_ready` ๋นˆ ํ† ํฐ ์‹œ ์ „๋Ÿ‰ ๋งค์นญ ์˜คํƒ ๋ฐฉ์ง€ ๋ฐ ๋ฏธ์ง€ ์—์ด์ „ํŠธ fail-closed ๊ฐ€๋“œ ๋‚ด์žฅ. +- **์…ธ ์Šคํฌ๋ฆฝํŠธ ์ „๋ฐ˜ ์–ด๋Œ‘ํ„ฐ ์ด๊ด€**: + - `create_session.sh`, `resume_session.sh`, `stop_session.sh`, `reconcile.sh`์— ์‚ฐ์žฌ๋˜์–ด ์žˆ๋˜ 40์—ฌ ๊ฐœ ํ•˜๋“œ์ฝ”๋”ฉ ๋ถ„๊ธฐ๋ฅผ ์–ด๋Œ‘ํ„ฐ ํ˜ธ์ถœ๋กœ ์ผ์›ํ™”. + +#### 2. ๋ ˆ๊ฑฐ์‹œ `isolation.root` ๋ฐ C-3b ์†Œ๋น„์ž ์™„์ „ ํ๊ธฐ (Option B) +- Universal Global Config ์ „ํ™˜ ์ดํ›„ ๋‚จ์•„์žˆ๋˜ 4๊ฐœ ๋ ˆ๊ฑฐ์‹œ ๊ฒฉ๋ฆฌ ์†Œ๋น„์ž ์ฝ”๋“œ(`lib.sh::mam_session_iso_root`, `workspace_uuid.py::iso_root_of`, `verify_session.py`, `stop_session.sh`) ๋ฐ `atomic_yaml.py`์˜ ๋ ˆ๊ฑฐ์‹œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ ˆ 100% ์‚ญ์ œ. +- ์ €์žฅ์†Œ ๋‚ด ๊ฒฉ๋ฆฌ ์ž”์žฌ ์ฐธ์กฐ 0๊ฑด ๋‹ฌ์„ฑ. + +#### 3. ์…ธ ๋ธŒ๋ฆฌ์ง€ ๋ณด์•ˆ ๋ฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ๊ฐ•ํ™” (R1, R2, N1 ๊ต์ •) +- **R1 (์œ„์ž„ ์—์ด์ „ํŠธ ํ‚ค ํด๋ฐฑ ๋ณด๊ฐ•)**: ๋ธŒ๋ฆฌ์ง€ ๋ฏธ์ž‘๋™ ์‹œ `delegate_agent`๊ฐ€ `antigravity-cli`๋กœ ์ผ๊ด„ ํ‡ดํ™”ํ•˜์ง€ ์•Š๊ณ  `claude-code`, `hermes-agent`, `cline-agent`๋กœ ๋ช…์‹œ์  `case` ํด๋ฐฑํ•˜๋„๋ก ๊ฐœ์„ . +- **R2 (`argv` ์„œ๋ธŒ์ปค๋งจ๋“œ ์ „ํ™˜)**: `python -c` ์…ธ ๋ณ€์ˆ˜ ๋ฌธ์ž์—ด ๋ณด๊ฐ„์„ `spawn-spec`, `resume-spec`, `exit-key` ์„œ๋ธŒ์ปค๋งจ๋“œ๋กœ ์ „๋ฉด ์ „ํ™˜ํ•˜์—ฌ ๊ณต๋ฐฑ/์ž‘์€๋”ฐ์˜ดํ‘œ ๊ฒฝ๋กœ ์—๋Ÿฌ ๋ฐ ์ฝ”๋“œ ์ฃผ์ž… ์œ„ํ˜‘ ์›์ฒœ ์ฐจ๋‹จ. +- **N1 (ํด๋ฆฐ ํ™˜๊ฒฝ ๊ฒฉ๋ฆฌ ๊ฐ€๋“œ)**: `test_a4_adapter_contract.py` ๋‚ด CLI ํ…Œ์ŠคํŠธ๊ฐ€ ์•ฐ๋น„์–ธํŠธ `PYTHONPATH` ์—†์ด๋„ ๋…๋ฆฝ ํ†ต๊ณผํ•˜๋„๋ก ํ™˜๊ฒฝ ๊ฒฉ๋ฆฌ ๋ณด๊ฐ•. + +#### 4. ์Šคํ‚ฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ทœ๊ฒฉํ™” ๋ฐ ํ”ผ์–ด ๋ฆฌ๋ทฐ 100% PASS +- 8๊ฐœ `SKILL.md` frontmatter `version: 2.0.0` ํ†ต์ผ ๋ฐ ๋ฐฐํฌ ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ. +- Reviewer `cline` (Job `e7b9812b`) ๋ฐ Planner/Senior Reviewer `claude` (Job `31730364`) ์ „์› `[VERDICT: PASS]` ํš๋“. + +#### 5. ๋ ˆ๊ฑฐ์‹œ ์ฃผ์„ ๋ฐ ์‚ฌ์šฉ๋ฒ• ์ •ํ•ฉ์„ฑ ์ตœ์‹ ํ™” (C-6) +- `stop_session.sh` ์ƒ๋‹จ ์ฃผ์„ ๋ฐ `usage()` ๋‚ด ํ๊ธฐ๋œ ํ”Œ๋ž˜๊ทธ(`--mode soft|hard`, `--capture-id`, `--graceful`) ์•ˆ๋‚ด ๋ฌธ๊ตฌ๋ฅผ ์™„์ „ ์ œ๊ฑฐํ•˜๊ณ  ํ˜„ํ–‰ 4๋Œ€ ์—์ด์ „ํŠธ(`claude`, `agy`, `hermes`, `cline`) ๋ฐ ํ”Œ๋ž˜๊ทธ ์ฒด๊ณ„๋กœ ๋™๊ธฐํ™”. +- ํšŒ๊ท€ ๋ฐฉ์ง€ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ(`test_comp_stop_usage_matches_parser`) ์‹ ์„ค. +- ํšŒ๊ท€ ๋ฐ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ: **263/263 PASS (100%)** ๋‹ฌ์„ฑ. + +--- + +### ๐Ÿ› ๏ธ `v1.4.0` โ€” Stability, Cleanup & Safe Job Delegation (2026-08-16) + +> **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ๊ฒฉ๋ฆฌ ์ž”์žฌ ์ •๋ฆฌ, ์„œ๋ธŒ์…ธ ๋ฃจํ”„ ๋ฝ ์กฐ๊ธฐ ํ•ด์ œ ๋ฒ„๊ทธ ํ”ฝ์Šค, ์‹ ๊ทœ ํŒŒ์ผ ์บก์ฒ˜ ๋ฐ ๊ฒฝ๋Ÿ‰ํ™”. + +- **P2-2 (C-3a / C-4 ๋ ˆ๊ฑฐ์‹œ ๊ฒฉ๋ฆฌ ์Šคํ… ๋ฐ ๋ฏธ์‚ฌ์šฉ ์‹ฌ๋ณผ ์ œ๊ฑฐ)**: + - `lib.sh` ๋‚ด ๋นˆ ์Šคํ… 4์ข…(`provision_isolation`, `isolation_lever`, `isolation_env_prefix`, `isolation_cmd_args`) ๋ฐ `_REAL_HERDR_PATH` ์™„์ „ ์‚ญ์ œ. + - `registry.py::TERMINAL_STATUSES` ๋ฐ `create_session.sh::ISOLATE` ์ œ๊ฑฐ. +- **P2-1 (B-6 / B-12 `delegate_job_safe` ์•ˆ์ •ํ™”)**: + - `.agents/skills/...` ๋‚ด ๋ถˆํ•„์š”ํ•œ `.tmp` ๋ณต์‚ฌ๋ณธ ์ƒ์„ฑ ์ œ๊ฑฐ ๋ฐ ์ธํ”Œ๋ ˆ์ด์Šค ์ง์ ‘ ์‹คํ–‰(`bash "$orig_script"`) ์ „ํ™˜. + - ์„œ๋ธŒ์…ธ ๋‚ด `trap`์œผ๋กœ ์ธํ•œ ๋ฃจํ”„ ๋ฝ ๋งˆ์ปค(`.mam/loop-guard-active`) ์กฐ๊ธฐ ์‚ญ์ œ ๊ฒฐํ•จ(D1) ์›์ฒœ ์ฐจ๋‹จ. +- **P0-2 (O-2 ์ค‘๋ณต ๋ฃจํ”„ ๊ธฐ๋™ ๋ฐฉ์ง€ ์›์ž์  ๋ฝ)**: + - `loop_lock.sh` ์‹ ์„ค: `set -C` ๊ธฐ๋ฐ˜ ์›์ž์  ๋ฝ ํš๋“ ๋ฐ PID + lstart ์†Œ์œ ๊ถŒ ๊ฒ€์ฆ์œผ๋กœ ๋™์‹œ ์‹คํ–‰ ๋ฐฉ์ง€. +- **P0-1 (B-7 ์™ธ๊ณฝ diff ์ˆ˜์ง‘ ๋ฐ ๋ฏธ์ถ”์  ํŒŒ์ผ ์บก์ฒ˜)**: + - `diff_collect.sh` ๋„์ž…: CWD ๋…๋ฆฝ `$REPO_ROOT` ๊ธฐ์ค€ diff ์ˆ˜์ง‘ ๋ฐ `git ls-files -o` ๋ฏธ์ถ”์  ํŒŒ์ผ ๋ณ‘ํ•ฉ. +- **B-4 (์‹œํ”„ํŠธ `ls` ๋™์  ํฌ์‹œ์Šค ํƒ€์ž„์Šคํƒฌํ”„ ๋ณต์›)**: + - `lib.sh` 554ํ–‰์˜ `created=999999` ํ•˜๋“œ์ฝ”๋”ฉ์„ ์‹ค์‹œ๊ฐ„ ํƒ€์ž„์Šคํƒฌํ”„(`int(time.time())`)๋กœ ๋ณต์›. +- **ํ…Œ์ŠคํŠธ ์ŠˆํŠธ ๊ฒฝ๋Ÿ‰ํ™”**: + - ๋…ธํ›„ํ™”๋œ ์ค‘๋ณต ๋ ˆ๊ฑฐ์‹œ ํ…Œ์ŠคํŠธ 7๊ฐœ ํŒŒ์ผ(1,559์ค„) ์‚ญ์ œ (`cf51b2c`). + +--- + +### ๐Ÿ›ก๏ธ `v1.3.0` โ€” Orchestrator Onboarding & Scoped Guarding (2026-08-15) + +> **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ ์‹ ์› ๊ฒฉ๋ฆฌ ๋ฐ ๋‹ค์ค‘ ์—์ด์ „ํŠธ ํ˜‘์—… ๊ฐ€๋“œ๋ ˆ์ผ ํ™•๋ฆฝ. + +- **`multi-agent-mux-orc-onboard` ์Šคํ‚ฌ ์‹ ์„ค**: + - ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ(`agy`)์˜ ๋Œ€ํ™” UUID๋ฅผ `.mam/agent-sessions.yaml` ๋‚ด `orchestrator_uuids` ๋ฆฌ์ŠคํŠธ๋กœ ๋“ฑ๋ก. + - `find_workspace_uuid` ๋ฐ `verify_session_uuid`์—์„œ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ UUID๋ฅผ ์Šคํ‚ตํ•˜์—ฌ ์„œ๋ธŒ์—์ด์ „ํŠธ ์„ธ์…˜ ์˜ค์—ผ ๋ฐฉ์ง€. +- **O-3 (์กฐ๊ฑด๋ถ€ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์œ„์ž„ ๊ฐ€๋“œ โ€” Scoped Guard)**: + - ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ดํ„ฐ๊ฐ€ `/multi-agent-mux-loop` ํ™œ์„ฑํ™” ์ƒํƒœ์—์„œ ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์Šคํฌ๋ฆฝํŠธ๋กœ ์œ„์ž„ํ•˜๋„๋ก ํ†ต์ œ. + - `AGENTS.md` ยง5 ๋ฐ `MULTI_AGENT_RULES.md` ๋‚ด ๊ฐ€๋“œ๋ ˆ์ผ ๋ช…์‹œ. +- **๋ฐฐํฌ ๋ฐ ํŒจํ‚ค์ง• ํŒŒ์ดํ”„๋ผ์ธ ํ˜„๋Œ€ํ™”**: + - `deploy/lib_ownership.sh` ์‹ ์„ค ๋ฐ `hooks.json` 3-way ๋ณ‘ํ•ฉ(`MERGE_REGISTRY`) ์ง€์›. + - Gitea CI/CD ํŒŒ์ดํ”„๋ผ์ธ (`deploy/gitea-ci.yml`) ์—ฐ๋™. + +--- + +### ๐Ÿ”Œ `v1.2.0` โ€” Universal Herdr Server Isolation & Cline Integration (2026-08-14) + +> **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: Herdr ๋‹จ์ผ ์„œ๋ฒ„ ๊ฒฉ๋ฆฌ ๋ฐ ๋‹ค์ค‘ AI ์—์ด์ „ํŠธ ํ™•์žฅ. + +- **Universal Herdr Session Isolation**: + - `HERDR_SESSION_NAME` ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฒฉ๋ฆฌ ์„œ๋ฒ„๋ฅผ ํ†ต์ผํ•˜์—ฌ ํ”„๋กœ์„ธ์Šค ์ถฉ๋Œ ๋ฐฉ์ง€. +- **Cline ์—์ด์ „ํŠธ ํ†ตํ•ฉ**: + - `cline` CLI ๊ธฐ๋ฐ˜ ๋Œ€ํ™” ์„ธ์…˜ ์ƒ์„ฑ, ์ •์ง€, ๋ณต์› ๋ฐ TUI ๋ ˆ๋”” ํ† ํฐ ํ•ธ๋“ค๋ง ์ง€์›. +- **SQLite WAL ํŠธ๋žœ์žญ์…˜ ๋™์‹œ์„ฑ**: + - ์„ธ์…˜ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋™์‹œ ์“ฐ๊ธฐ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๋ฝ ์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด SQLite WAL ๋ชจ๋“œ ์ „๋ฉด ์ ์šฉ. + +--- + +### ๐Ÿงฑ `v1.0.0` ~ `v1.1.0` โ€” Initial Multi-Agent Mux Framework (2026-08-10 ~ 2026-08-13) + +> **์ฃผ์š” ๋งˆ์ผ์Šคํ†ค**: ํ„ฐ๋ฏธ๋„ ๋‹ค์ค‘ ์—์ด์ „ํŠธ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๊ธฐ์ดˆ ์„ค๊ณ„ ๋ฐ ๋น„๋™๊ธฐ ๋ฃจํ”„ ์™„์„ฑ. + +- **ํ•ต์‹ฌ ์ˆ˜๋ช…์ฃผ๊ธฐ ์Šคํ‚ฌ๊ตฐ ๊ตฌ์ถ•**: `create`, `stop`, `resume`, `status`, `monitor` ์Šคํ‚ฌ ๊ธฐ๋ณธ ๊ตฌํ˜„. +- **MQTT ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ ์žก ์œ„์ž„**: `multi-agent-mux-delegate-job`์„ ํ†ตํ•œ ์—์ด์ „ํŠธ ๊ฐ„ ์ด๋ฒคํŠธ ํ†ต์‹  ๋ฐ ๊ฒฐ๊ณผ ๊ตฌ๋…. +- **์ž์œจ ํ˜‘์—… ๋ฃจํ”„**: `multi-agent-mux-loop` ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ†ตํ•œ Planner-Creator-Reviewer ์—ญํ•  ๋ถ„๋‹ด ์ฒด๊ณ„ ์ •๋ฆฝ. + +--- + +## ๐Ÿงช ํ’ˆ์งˆ ๋ณด์ฆ ๋ฐ ๊ฒ€์ฆ ๊ธฐ์ค€ (Verification Standards) + +๋ชจ๋“  ๋ฆด๋ฆฌ์Šค๋Š” ๋‹ค์Œ 4๋‹จ๊ณ„ ์—„๊ฒฉํ•œ ๊ฒ€์ฆ์„ ํ†ต๊ณผํ•ด์•ผ ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค: +1. **์ •์  ๋ฌธ๋ฒ• ๊ฒ€์‚ฌ**: `bash -n` (๋ชจ๋“  ์…ธ ์Šคํฌ๋ฆฝํŠธ) ๋ฐ AST ๋ฏธ์‚ฌ์šฉ ์ฝ”๋“œ ๋ถ„์„. +2. **๋‹จ์œ„ ๋ฐ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ (Tier 1~2)**: ์ธํ”Œ๋ ˆ์ด์Šค ๋ฐ ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ์ƒํ˜ธ์ž‘์šฉ ๊ฒ€์ฆ. +3. **ํ†ตํ•ฉ ๋ฐ ๊ณ„์•ฝ ํ…Œ์ŠคํŠธ (Tier 3~4 / Contract)**: clean environment (`env -u PYTHONPATH`) ํ•˜์—์„œ์˜ ์–ด๋Œ‘ํ„ฐ ๊ณ„์•ฝ ๋ฐ CLI ๋ธŒ๋ฆฌ์ง€ ๊ฒ€์ฆ. +4. **๋ฉ€ํ‹ฐ์—์ด์ „ํŠธ ๊ต์ฐจ ํ”ผ์–ด ๋ฆฌ๋ทฐ**: Planner(`claude`) ๋ฐ Reviewer(`cline`) ๊ฐ„ ๊ต์ฐจ ๊ฒ€์ฆ ๋ฐ `[VERDICT: PASS]` 100% ํ•ฉ์˜. diff --git a/tests/test_tier2_component.py b/tests/test_tier2_component.py index 022b117..da1a6a8 100644 --- a/tests/test_tier2_component.py +++ b/tests/test_tier2_component.py @@ -691,3 +691,45 @@ d['herdr_sessions'] = [{ row = conn.execute("SELECT status FROM sessions WHERE name='test-autorecovery-creator-claude'").fetchone() assert row[0] == "terminated" conn.close() + +def test_comp_stop_usage_matches_parser(mam_sandbox): + """C-6: help text and parser must not drift apart.""" + script = mam_sandbox / ".agents" / "skills" / "multi-agent-mux-stop" / "scripts" / "stop_session.sh" + + # ์—์ด์ „ํŠธ ์ ‘๋ฏธ์‚ฌ ์ถ”๋ก (:91-100)์ด ์„ฑ๋ฆฝํ•˜๋Š” ์ด๋ฆ„ โ€” rc=2 ์˜ ๋‹ค์„ฏ ์›์ธ ์ค‘ + # 'cannot infer agent'(:98)๋ฅผ ๋ฐฐ์ œํ•˜๊ธฐ ์œ„ํ•จ (Challenge 8b6b574f) + VALID = "test-project-creator-claude" + + # 1) --help ๋Š” ์„ฑ๊ณตํ•˜๊ณ , ํ์ง€๋œ ํ”Œ๋ž˜๊ทธ๋ฅผ ๊ด‘๊ณ ํ•˜์ง€ ์•Š๋Š”๋‹ค + res = subprocess.run(["bash", str(script), "--help"], capture_output=True, text=True) + assert res.returncode == 0 + for dead in ("--mode", "--capture-id", "--graceful"): + assert dead not in res.stdout, f"usage() still advertises {dead}" + + # 1b) ๊ฒ€์ฆ๊ธฐ๊ฐ€ ๋ฐ›๋Š” ์—์ด์ „ํŠธ๋Š” ์ „๋ถ€ ๋„์›€๋ง์— ๋‚˜์˜จ๋‹ค (Rev.2 M3) + for agent in ("claude", "agy", "hermes", "cline"): + assert agent in res.stdout, f"usage() omits supported agent {agent}" + + # 2) ๋„์›€๋ง์ด ๊ด‘๊ณ ํ•˜๋Š” ํ”Œ๋ž˜๊ทธ๋Š” ์ „๋ถ€ ํŒŒ์„œ๊ฐ€ ๋ฐ›๋Š”๋‹ค + # rc=2 ๋Š” 5๊ฐ€์ง€ ์›์ธ์„ ๊ณต์œ ํ•˜๋ฏ€๋กœ stderr ๋ฉ”์‹œ์ง€๋กœ ์ง์ ‘ ์ง€๋ชฉํ•œ๋‹ค + for flag, args in (("--reason", ["--reason", "x"]), + ("--purge-conversation", ["--purge-conversation"]), + ("--yes", ["--yes"]), + ("--agent", ["--agent", "hermes"])): + r = subprocess.run(["bash", str(script), "--session", VALID] + args, + capture_output=True, text=True) + assert "unknown arg" not in r.stderr, f"usage() advertises {flag} but parser rejects it: {r.stderr}" + assert "deprecated" not in r.stderr, f"usage() advertises deprecated {flag}: {r.stderr}" + assert r.returncode != 2, f"{flag} -> rc=2: {r.stderr}" + + # 3) ํ์ง€๋œ ํ”Œ๋ž˜๊ทธ๋Š” ์ „์šฉ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ rc=2 ๋กœ ๊ฑฐ๋ถ€๋œ๋‹ค (ํŠน๋ณ„ ์ทจ๊ธ‰ ์œ ์ง€) + for dead in ("--mode", "--capture-id", "--graceful"): + r = subprocess.run(["bash", str(script), "--session", VALID, dead, "hard"], + capture_output=True, text=True) + assert r.returncode == 2 + assert "deprecated" in r.stderr + + # 4) ํ—ค๋” ์ฃผ์„๋„ ํ์ง€ ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉ๋ฒ•์œผ๋กœ ๊ด‘๊ณ ํ•˜์ง€ ์•Š๋Š”๋‹ค + head = "".join(script.read_text().splitlines(keepends=True)[:35]) + assert "--mode soft|hard" not in head +