# ๐Ÿ“‘ Issue #5 Phase 2b โ€” ์ž๋™์™„๋ฃŒ ์šด์˜ ๋…ธํŠธ (Flag-Gated / Opt-In) - **๋ฌธ์„œ ๋ฒ„์ „**: Rev.1 - **์ƒํƒœ**: ๊ตฌํ˜„ ์™„๋ฃŒ, **๊ธฐ๋ณธ ๋น„ํ™œ์„ฑ(`MAM_AUTO_COMPLETE=0`)** --- ## 1. ํ•œ ๋ฌธ์žฅ ์š”์•ฝ **๋๋‚ฌ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•„๋Š” ์ชฝ(์—์ด์ „ํŠธ)์ด ํ™•์ •์„ ์„ ์–ธํ•˜๊ณ , ์ฝ๋Š” ์ชฝ์€ ๊ทธ ์„ ์–ธ์„ ๋ฏฟ์ง€ ์•Š๊ณ  ํ•ด์‹œ๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ๋‹ค.** ์›Œ์ฒ˜๊ฐ€ ์Šค์Šค๋กœ ํ•ด์‹œ๋ฅผ ๊ณ„์‚ฐํ•ด ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๋งŒ๋“ค๋ฉด ๊ทธ๊ฒƒ์€ "์›Œ์ฒ˜๊ฐ€ ์•ˆ์ •๋œ ํŒŒ์ผ์„ ๋ดค๋‹ค"๋Š” ์ž๊ธฐ ์ฆ๋ช…์ผ ๋ฟ์ด๋‹ค. ์ด ์ด์Šˆ์˜ ์•ž์„  ๋ผ์šด๋“œ์—์„œ ๋ฆฌ๋ทฐ์–ด๊ฐ€ ๊ธฐ๊ฐํ•œ ์ฆ๊ฑฐ ํ˜•ํƒœ์ด๋ฉฐ, ๊ฐ™์€ ์‹ค์ˆ˜๋ฅผ ๋ฐ˜๋ณตํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•œ ์„ค๊ณ„ ๊ฒฐ์ •์ด๋‹ค. ## 2. ๊ทธ๋ž˜์„œ ๋ฏธ์ง€์› ์—์ด์ „ํŠธ๋Š” ์ž๋™์œผ๋กœ ์•ˆ์ „ํ•˜๋‹ค ํ™•์ •์„ ์„ ์–ธํ•˜์ง€ ์•Š์€ ์—์ด์ „ํŠธ๋Š” ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ๋‚จ๊ธฐ์ง€ ์•Š๋Š”๋‹ค. ๋งค๋‹ˆํŽ˜์ŠคํŠธ๊ฐ€ ์—†์œผ๋ฉด ์ •์ฑ…์ด ์ด๋ฏธ `hold`ํ•œ๋‹ค(Phase 2a์—์„œ ๊ตฌํ˜„ยทํ…Œ์ŠคํŠธ ์™„๋ฃŒ). **"๋ฏธ์ง€์› ๊ฒฝ๋กœ 100% ๋ณด์กด"์€ ์ƒˆ ๋ถ„๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ธฐ์กด ๋™์ž‘์˜ ๊ท€๊ฒฐ์ด๋‹ค.** ## 2-1. โš ๏ธ ์•„์ง ๋ฐฐ์„ ๋˜์ง€ ์•Š์•˜๋‹ค (์ •์งํ•œ ํ˜„ํ™ฉ) **`autocomplete.evaluate`์™€ `notifier.recover`๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ”„๋กœ๋•์…˜ ๊ฒฝ๋กœ๋Š” ์•„์ง ์—†๋‹ค.** `daemon.py`/`job_subscriber.py`/`cli.py`/`service.py` ์–ด๋””๋„ ์ด๋“ค์„ ์ž„ํฌํŠธํ•˜์ง€ ์•Š์œผ๋ฉฐ, `register`์— `auto_complete` opt-in ์˜ต์…˜๋„ ์—†๋‹ค. ์ฆ‰ **ํ˜„์žฌ ๋ผ์ด๋ธŒ ์…ธ ๋ฃจํ”„์—์„œ `MAM_AUTO_COMPLETE=1`์€ ๋ฌด๋™์ž‘(no-op)์ด๋‹ค.** Phase 2b๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์€ **๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฒŒ์ดํŠธ**์ด๋ฉฐ, ์ด๋ฅผ ๊ฐ์‹œ ๋ฃจํ”„์— ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐฐ์„ ์€ Phase 3์˜ ๋ชซ์ด๋‹ค. ์ดˆ๊ธฐ ๋ฌธ์„œ๊ฐ€ "๊ธฐ๋™ ์‹œ ์žฌ๋ฐœํ–‰์ด ๊ตฌ๋…์ž์—์„œ ์ˆ˜ํ–‰๋œ๋‹ค"๊ณ  ์ ์—ˆ๋˜ ๊ฒƒ์€ ์‚ฌ์‹ค์ด ์•„๋‹ˆ์—ˆ์œผ๋ฉฐ ์—ฌ๊ธฐ์„œ ์ •์ •ํ•œ๋‹ค(๊ต์ฐจ ๋ฆฌ๋ทฐ `3fa76e08` O-1, `a0de0e5e` ์ž”์—ฌ 1ยท2). ๋ฐฐ์„  ์‹œ ํ•„์š”ํ•œ ๊ฒƒ: 1. ๊ฐ์‹œ ๋ฃจํ”„์—์„œ `evaluate(...)` ํ˜ธ์ถœ โ€” **`report_dir`๋Š” ํ•„์ˆ˜ ์ธ์ž๋‹ค.** 2. ์ปค๋ฐ‹ ํ›„ `notifier.flush(...)` ํ˜ธ์ถœ โ€” `evaluate`๋Š” intent๋ฅผ ๋‚จ๊ธธ ๋ฟ ๋ฐœํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. 3. ๊ธฐ๋™ ์‹œ `notifier.recover(...)` ํ˜ธ์ถœ. 4. `register`์— ์žก๋ณ„ opt-in ๊ฒฝ๋กœ ์ถ”๊ฐ€. ## 3. 3์ค‘ ๊ฒŒ์ดํŠธ (์ „๋ถ€ ์ฐธ์ผ ๋•Œ๋งŒ ์ปค๋ฐ‹) | ๊ฒŒ์ดํŠธ | ๊ธฐ๋ณธ๊ฐ’ | ๊ทผ๊ฑฐ | |---|---|---| | `MAM_AUTO_COMPLETE=1` | **`0` (OFF)** | ์ „์—ญ ํ‚ฌ ์Šค์œ„์น˜ | | `MAM_ENGINE_CAS=1` | `1` | `0`์ด๋ฉด ์ž๋™์™„๋ฃŒ๋„ ํ•จ๊ป˜ ์ค‘๋‹จ๋œ๋‹ค. ์ถ”๋ก  ์™„๋ฃŒ๋Š” CAS ๊ฒฝ๊ณ„ ์œ„์— ์„œ ์žˆ์œผ๋ฏ€๋กœ, ๊ฒฝ๊ณ„๊ฐ€ ๋กค๋ฐฑ๋œ ์ƒํƒœ์˜ ์ปค๋ฐ‹์€ ๊ทธ ๊ฒฝ๊ณ„๋ฅผ ์šฐํšŒํ•˜๋Š” ๊ฒƒ์ด๋‹ค | | ๋ฐฑ์—”๋“œ ํ—ˆ์šฉ๋ชฉ๋ก | `claude,grok,codex` (+ `-code`/`-build`/`-cli` ์ •์‹ ํ‚ค) | ์ •์ง€ ์ƒํƒœ(`idle`/`done`) **๊ด€์ธก ์ฆ๊ฑฐ๊ฐ€ ์žˆ๋Š” ๋ฐฑ์—”๋“œ๋งŒ**. `agy`๋Š” `working`๋งŒ ๊ด€์ธก, `hermes`ยท`opencode`๋Š” ๊ด€์ธก 0๊ฑด. **์ •ํ™• ์ผ์น˜**๋กœ ๋น„๊ตํ•œ๋‹ค โ€” ์ ‘๋‘ ์ผ์น˜๋ผ๋ฉด ๋ฏธ๋ž˜์˜ `claude-experimental`์ด ์ˆ˜์ง‘๋œ ์  ์—†๋Š” ์ฆ๊ฑฐ๋ฅผ ๋ฌผ๋ ค๋ฐ›๋Š”๋‹ค | | ์žก๋ณ„ opt-in | ๋ ˆ์ฝ”๋“œ `auto_complete: true` | ์žก ๋‹จ์œ„ ๋™์˜ | `MAM_AUTO_COMPLETE_BACKENDS`๋กœ ๋ชฉ๋ก์„ **์ขํž ์ˆ˜๋งŒ** ์žˆ๋‹ค. ๊ด€์ธก๋œ ์  ์—†๋Š” ์ด๋ฆ„์€ ๋ฌด์‹œ๋œ๋‹ค โ€” ๋„“ํžˆ๋ ค๋ฉด ์„ค์ •์ด ์•„๋‹ˆ๋ผ ์ฆ๊ฑฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ## 4. ํ™•์ • ๊ณ„์•ฝ (P2B-01) ``` ์—์ด์ „ํŠธ: publish_event.py --job --event completed \ --finalize-report [--side-effect =] ... โ‘  .tmp โ†’ ์›์ž์  rename (๋ฐ˜์ฏค ์“ฐ์ธ ๋ฆฌํฌํŠธ๋ฅผ ์ตœ์ข…๋ณธ์œผ๋กœ ๋ณผ ์ˆ˜ ์—†๊ฒŒ) โ‘ก SHA-256 ๊ณ„์‚ฐ โ‘ข report-manifest.json ์›์ž์  ๊ธฐ๋ก (job_id, attempt_id, sha256, side_effects, declared_by) ``` - **๋ฆฌํฌํŠธ๋ฅผ ๋‹ค์‹œ ์“ฐ๋ฉด ์„ ์–ธ์€ ์ฆ‰์‹œ ๋ฌดํšจ**๊ฐ€ ๋œ๋‹ค. ํ•ด์‹œ๋ฅผ ๋‹ค์‹œ ๊ณ„์‚ฐํ•ด ๋Œ€์กฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ƒˆ ๋ณธ๋ฌธ์—๋Š” ์ƒˆ ํ™•์ •์ด ํ•„์š”ํ•˜๋‹ค. - **์„ ์–ธํ•œ ๋ถ€์ˆ˜ํšจ๊ณผ๋Š” ์ „๋ถ€ ์ฆ๊ฑฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.** ์ผ๋ถ€๋งŒ ์žˆ๋Š” ๊ฒƒ์€ ์—†๋Š” ๊ฒƒ์œผ๋กœ ์ทจ๊ธ‰ํ•œ๋‹ค โ€” ์ž‘์—…์ด ๋๋‚ฌ๋‹ค๊ณ  ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. - ํ™•์ •์€ ๋ฐœํ–‰ **์•ž์—** ์ผ์–ด๋‚œ๋‹ค. ๋ฆฌํฌํŠธ๋ฅผ ์•„์ง ์“ฐ๋Š” ์ค‘์ธ `completed` ์ด๋ฒคํŠธ๋Š” ๊ณ„์•ฝ์ด ๊ธˆ์ง€ํ•˜๋Š” ๋ถ€๋ถ„ ๋ฆฌํฌํŠธ ์ฑ„ํƒ์„ ๋ถ€๋ฅธ๋‹ค. ## 5. ์ง€์—ฐ ์•Œ๋ฆผ (P2B-02) ``` ๋ฝ ์•ˆ: ์ƒํƒœ ์ปค๋ฐ‹ + pending_notification ๊ธฐ๋ก โ† ํ•˜๋‚˜์˜ ์›์ž์  ์“ฐ๊ธฐ ๋ฝ ๋ฐ–: ๋ฐœํ–‰ โ†’ ์„ฑ๊ณต ์‹œ notification_settled ์ „์ด๋กœ ์ •๋ฆฌ ๊ธฐ๋™ ์‹œ: pending_notification์ด ๋‚จ์€ ๋ ˆ์ฝ”๋“œ๋ฅผ ์žฌ๋ฐœํ–‰ (๋ฉฑ๋“ฑ: ๊ตฌ๋…์ž๊ฐ€ seq๋กœ ์ค‘๋ณต ์ œ๊ฑฐ) ``` - **๋…๋ฆฝ Outbox ์ €์žฅ์†Œ๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค**(`state-transitions.md` ยง5 ๋ช…์‹œ). ์ด๋ฏธ ์“ฐ๋Š” ๋ ˆ์ฝ”๋“œ์— ํ•„๋“œ ํ•˜๋‚˜๋ฅผ ๋” ์“ด๋‹ค. - **๋ฐœํ–‰ ์‹คํŒจ๋Š” ์˜๋„์ ์œผ๋กœ intent๋ฅผ ๋‚จ๊ธด๋‹ค.** ๋ณด๋‚ด์ง€ ์•Š์€ ์•Œ๋ฆผ์ด ๋ณด๋‚ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ํŽธ์ด, ์žฌ์‹œ๋„๋˜๋Š” ํŽธ๋ณด๋‹ค ๋‚˜์˜๋‹ค. - `notification_settled`๋Š” **์ƒํƒœ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๋Š” bookkeeping ์š”์ฒญ**์ด๋ผ terminal ์ƒํƒœ์—์„œ๋„ ํ—ˆ์šฉ๋˜๋ฉฐ, **`pending_notification` ์™ธ์˜ ํ•„๋“œ๋Š” ์“ธ ์ˆ˜ ์—†๋‹ค**(๊ฒฝ๊ณ„์—์„œ ๊ฑฐ๋ถ€ โ€” ํ˜„์žฌ ํ˜ธ์ถœ์ž๊ฐ€ ๊ทธ๊ฒƒ๋งŒ ๋„˜๊ธด๋‹ค๋Š” ์‚ฌ์‹ค์— ์˜์กดํ•˜์ง€ ์•Š๋Š”๋‹ค). - ์ •๋ฆฌ๋Š” **์‹ค์ œ๋กœ ๋ณด๋‚ธ intent์™€ ์ผ์น˜ํ•  ๋•Œ๋งŒ** ์ด๋ฃจ์–ด์ง„๋‹ค. ๋ฐœํ–‰์€ ๋ฝ ๋ฐ–์—์„œ ์ผ์–ด๋‚˜๋ฏ€๋กœ ๊ทธ ์‚ฌ์ด์— ์ƒˆ intent๊ฐ€ ์ •๋‹นํ•˜๊ฒŒ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๊ณ , ๋ฌด์กฐ๊ฑด ์ง€์šฐ๋ฉด ์•„๋ฌด๋„ ๋ณด๋‚ด์ง€ ์•Š์€ ์•Œ๋ฆผ์ด ์‚ฌ๋ผ์ง„๋‹ค. - ๋ฐœํ–‰ payload์— intent์˜ `seq`/`event`/`timestamp`๋ฅผ ์‹ค์–ด ๋ณด๋‚ธ๋‹ค. **์ „์†ก ๊ณ„์ธต seq๋Š” ๊ฐ™์€ intent์˜ ์žฌ์‹œ๋„๋ฅผ ์‹๋ณ„ํ•˜์ง€ ๋ชปํ•˜๋ฏ€๋กœ**, ์†Œ๋น„์ž๋Š” `notification_intent`๋กœ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•œ๋‹ค. ์•Œ๋ฆผ์€ terminal์— *๊ด€ํ•œ* ๊ฒƒ์ด๋ฏ€๋กœ, terminal์ด ๊ฑฐ๋ถ€ํ•˜๋Š” ์š”์ฒญ์œผ๋กœ๋Š” ์˜์›ํžˆ ์ •๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค. ## 5-1. ํ•„์ˆ˜ ๊ฒ€์ฆ (๊ต์ฐจ ๋ฆฌ๋ทฐ ๋ฐ˜์˜, ์ „๋ถ€ ๋ฏธ์ถฉ์กฑ ์‹œ `hold`) | ๊ฒ€์ฆ | ์—†์œผ๋ฉด | |---|---| | `report_dir` ์ธ์ž | `hold` โ€” **์„ ํƒ์ด ์•„๋‹ˆ๋‹ค.** ์ƒ๋žตํ•˜๋ฉด ๋””์Šคํฌ ๋Œ€์กฐ๊ฐ€ ํ†ต์งธ๋กœ ๊ฑด๋„ˆ๋›ฐ์–ด์ ธ ์ˆ˜์ง‘๊ธฐ์˜ ์ž๊ธฐ ์‹ ๊ณ ๊ฐ€ ๋‹ค์‹œ ํŒ๋‹จ ์ฃผ์ฒด๊ฐ€ ๋œ๋‹ค | | ๊ธฐ๋ก๋œ dispatch | `hold` โ€” ๊ท€์†์‹œํ‚ฌ ๋Œ€์ƒ์ด ์—†๋‹ค | | ์ฆ๊ฑฐ์˜ **๋Œ€์ƒ ์ผ์น˜** | `hold` โ€” ์‹œ๋‚˜๋ฆฌ์˜ค์˜ `job_id`ยทattemptยทsessionยทpane์ด ๊ธฐ๋ก๋œ dispatch์™€ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค. ์ •์ฑ…์€ ์‹œ๋‚˜๋ฆฌ์˜ค **๋‚ด๋ถ€**์˜ dispatch_context์™€๋งŒ ๋น„๊ตํ•˜๋ฏ€๋กœ ๊ตฌ์กฐ์ƒ ํ•ญ์ƒ ์ž๊ธฐ ์ผ๊ด€์ ์ด๋‹ค | | ๋งค๋‹ˆํŽ˜์ŠคํŠธ ์žฌ๊ณ„์‚ฐ ๋Œ€์กฐ | `hold` | | Reviewer ์—ญํ• ์˜ ํŒ์ • ํ† ํฐ | `hold` โ€” Phase 0 ์•ˆ์ „ ๊ณ„์•ฝ. ํŒ์ •์„ ์•„์ง ์“ฐ์ง€ ์•Š์€ ๋ฆฌ๋ทฐ์–ด๋Š” ๊ฒ€ํ† ๋ฅผ ๋๋‚ด์ง€ ์•Š์€ ๊ฒƒ์ด๋‹ค | ## 6. ๋ฌดํŒ์ • fail-closed ๋งค๋‹ˆํŽ˜์ŠคํŠธ๋ฅผ ์ฝ์ง€ ๋ชปํ•จ, ์ •์ฑ…์ด ์˜ˆ์™ธ๋ฅผ ๋˜์ง, ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒฐ์ • โ€” ์ „๋ถ€ `hold`๋‹ค. **"ํŒ์ •ํ•˜์ง€ ๋ชปํ•จ"์€ ๊ฒฐ์ฝ” "์™„๋ฃŒ"๊ฐ€ ์•„๋‹ˆ๋‹ค.** ๋Šฆ๊ฒŒ ๋„์ฐฉํ•œ ๋ช…์‹œ terminal์ด ์žˆ์œผ๋ฉด ์ „์ด ๊ฒฝ๊ณ„๊ฐ€ ์ถ”๋ก  ์™„๋ฃŒ๋ฅผ ๊ฑฐ๋ถ€ํ•˜๋ฉฐ, ๊ทธ๊ฒƒ์€ ๊ฒฝ๊ณ„๊ฐ€ ์ œ ์ผ์„ ํ•œ ๊ฒƒ์ด์ง€ ๊ฒŒ์ดํŠธ์˜ ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋‹ค. ## 7. ๊ฐ์‚ฌ ํ‘œ์‹ ์ž๋™์™„๋ฃŒ๋กœ ๋“ค์–ด๊ฐ„ terminal์—๋Š” `completed_by: "auto_complete"`์™€ ํŒ์ • ์‚ฌ์œ ๊ฐ€ ๋‚จ๋Š”๋‹ค. ๊ตฌ๋…์ž์™€ ๋ž˜ํผ๋Š” ์ž๋™/๋ช…์‹œ ์™„๋ฃŒ๋ฅผ ๊ตฌ๋ณ„ํ•˜์ง€ ๋ชปํ•˜๋ฏ€๋กœ(`job_subscriber._check_disk_fallback`์€ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ status๋งŒ ๋ณธ๋‹ค), **์‚ฌํ›„์— ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ์ˆ˜๋‹จ**์ด๋‹ค. ## 8. ๋กค๋ฐฑ 1. `MAM_AUTO_COMPLETE=0` โ€” ์‹ ๊ทœ ์ž๋™์™„๋ฃŒ๋งŒ ์ค‘๋‹จ. **์ด๋ฏธ ํ™•์ •๋œ terminal ๋ ˆ์ฝ”๋“œ๋Š” ๋ณด์กด**ํ•œ๋‹ค. 2. `MAM_ENGINE_CAS=0` โ€” Phase 2a ๊ฒฝ๋กœ๊นŒ์ง€ ๋˜๋Œ๋ฆฐ๋‹ค(์ž๋™์™„๋ฃŒ๋Š” ๊ทธ ์œ„์— ์žˆ์œผ๋ฏ€๋กœ ํ•จ๊ป˜ ๋ฌด๋ ฅํ™”). 3. `.mam/shadow/`๋Š” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์™€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์–ด ์‚ญ์ œํ•ด๋„ job ์ƒํƒœ์— ์˜ํ–ฅ์ด ์—†๋‹ค. ## 9. ๊ณ„ํš ๋Œ€๋น„ ์ดํƒˆ 1๊ฑด (๋ ˆ์ฝ”๋“œ ์Šคํ‚ค๋งˆ ๋ฏธ๋ณ€๊ฒฝ) ๊ณ„ํš์„œ ยงD2๋Š” `attempt_id`๋ฅผ job ๋ ˆ์ฝ”๋“œ์˜ 1๊ธ‰ ํ•„๋“œ๋กœ ์Šน๊ฒฉํ•  ๊ฒƒ์„ ๊ถŒ๊ณ ํ•˜๊ณ , Phase 1์ด ๋™๊ฒฐํ•œ "๋ ˆ์ฝ”๋“œ ํ•„๋“œ ๋ถˆ๋ณ€" ๊ณ„์•ฝ์˜ ๋ณ€๊ฒฝ์ด๋ฏ€๋กœ **๋ฆฌ๋ทฐ์–ด ์Šน์ธ์„ ์„ ํ–‰ ์กฐ๊ฑด**์œผ๋กœ ๊ฑธ์—ˆ๋‹ค. ๊ตฌํ˜„ ์ค‘ ์‹ค์ธกํ•œ ๊ฒฐ๊ณผ **๊ทธ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜์ง€ ์•Š์•˜๋‹ค**: - ์—”์ง„์˜ `expected_attempt`๋Š” ๋ ˆ์ฝ”๋“œ์˜ `attempt_id`(์—†์Œ)๋ฅผ `iteration`(๋ฃจํ”„ ํšŒ์ฐจ)์œผ๋กœ ๋Œ€์ฒด ๋น„๊ตํ•œ๋‹ค โ€” ๋‘ ๊ฐœ๋…์ด ๋‹ฌ๋ผ ์˜๋ฏธ๊ฐ€ ์„ฑ๋ฆฝํ•˜์ง€ ์•Š๋Š”๋‹ค. - ๋ฐ˜๋ฉด **์‹œ๋„ ์‹๋ณ„์€ ์ด๋ฏธ ์ฆ๊ฑฐ ๊ณ„์ธต์—์„œ ๊ฒ€์ฆ๋œ๋‹ค**: `policy`๊ฐ€ ๊ด€์ธก ์‹๋ณ„์ž์™€ shadow ์ €์žฅ์†Œ์˜ dispatch ๋ ˆ์ฝ”๋“œ๋ฅผ ๋Œ€์กฐํ•˜๋ฉฐ, ์‹œ๋„๊ฐ€ ์–ด๊ธ‹๋‚˜๋ฉด `hold`ํ•œ๋‹ค(์‹ค์ธก ํ™•์ธ). ๋”ฐ๋ผ์„œ ์ž๋™์™„๋ฃŒ๋Š” ์—”์ง„์— `expected_attempt`๋ฅผ ๋„˜๊ธฐ์ง€ ์•Š๊ณ  `expected_status="running"`(์—”์ง„์˜ ๊ณ ์œ  ์˜์—ญ์ธ ์ƒํƒœ)๋งŒ ์ „์ œ์กฐ๊ฑด์œผ๋กœ ์ค€๋‹ค. **์‹œ๋„ ๋ณด์ฆ์€ ์‹œ๋„ ์ •์ฒด์„ฑ์ด ์‹ค์ œ๋กœ ์‚ฌ๋Š” ๊ณณ์— ๋‘”๋‹ค.** ๋ ˆ์ฝ”๋“œ ์Šคํ‚ค๋งˆ๋Š” ๋ฐ”๋€Œ์ง€ ์•Š์•˜๊ณ , Phase 1 ๊ณ„์•ฝ๋„ ์œ ์ง€๋œ๋‹ค. `attempt_id` ์Šน๊ฒฉ์€ ์—ด๋ฆฐ ์งˆ๋ฌธ์œผ๋กœ ๋‚จ๊ธด๋‹ค. ์Šน๊ฒฉํ•˜๋ฉด ์—”์ง„์— 2์ฐจ ๋ฐฉ์–ด์„ ์ด ์ƒ๊ธฐ์ง€๋งŒ ๋™๊ฒฐ ๊ณ„์•ฝ์„ ๋ฐ”๊ฟ”์•ผ ํ•˜๋ฉฐ, ํ˜„์žฌ๋Š” ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค. `test_x03_the_record_carries_iteration_not_an_attempt_id`๊ฐ€ ์ด ์ „์ œ๋ฅผ ๊ฐ์‹œํ•œ๋‹ค โ€” ๋ ˆ์ฝ”๋“œ๊ฐ€ `attempt_id`๋ฅผ ๊ฐ–๊ฒŒ ๋˜๋Š” ์ˆœ๊ฐ„ ์‹คํŒจํ•˜๋ฉฐ, ๊ทธ๋•Œ๊ฐ€ ์žฌ๊ฒ€ํ†  ์‹œ์ ์ด๋‹ค. ## 9-1. ๊ตฌํ˜„ ์ค‘ ์ •์ • 1๊ฑด โ€” `finalize`์˜ ํŒจํ‚ค์ง€ ์œ„์น˜ ์ฒ˜์Œ์—๋Š” `finalize.py`๋ฅผ `lib_py/loop/`์— ๋‘์—ˆ๋Š”๋ฐ, ๊ทธ๋Ÿฌ๋ฉด `publish_event`(=`lib_py.delegation`)๊ฐ€ **ํ˜•์ œ ํŒจํ‚ค์ง€๋ฅผ ์ž„ํฌํŠธ**ํ•˜๊ฒŒ ๋˜์–ด freeze ํ•˜์—์„œ ํŠธ๋ฆฌ๊ฐ€ ์„ž์ธ๋‹ค. Phase 1์ด ๋ช…๋ฌธํ™”ํ•˜๊ณ  Phase 2a์—์„œ ์—”์ง„ ๋ฐฐ์น˜๋ฅผ ์ •์ •ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๋˜ ๋ฐ”๋กœ ๊ทธ ๊ทœ์น™์ด๋ฉฐ, ๊ธฐ์กด ๊ฐ€๋“œ ํ…Œ์ŠคํŠธ(`test_delegation_package_imports_no_sibling_lib_py_modules`)๊ฐ€ ์ „์ฒด ์Šค์œ„ํŠธ์—์„œ ์ด๋ฅผ ๊ฒ€์ถœํ–ˆ๋‹ค. **๋งค๋‹ˆํŽ˜์ŠคํŠธ๋Š” job์˜ ๋ฆฌํฌํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์“ฐ์ด๊ณ  ์—์ด์ „ํŠธ๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” CLI๋Š” delegation ์ง„์ž…์ ์ด๋ฏ€๋กœ, `finalize`๋Š” `lib_py/delegation/`์— ์†ํ•œ๋‹ค.** `lib_py.loop`๊ฐ€ `lib_py.delegation`์„ ์ž„ํฌํŠธํ•˜๋Š” ๋ฐฉํ–ฅ์€ ํ—ˆ์šฉ๋œ๋‹ค. ๊ฐ™์€ ๊ทœ์น™์— ๋‘ ๋ฒˆ ๊ฑธ๋ฆฐ ์…ˆ์ด๋ฉฐ, ๊ฐ€๋“œ๊ฐ€ ๋‘ ๋ฒˆ ๋‹ค ์žก์•˜๋‹ค. ## 10. Phase 3 ์ธ๊ณ„ 1. `preexec_fn`: 2b๋„ ๋ฐ๋ชฌ์„ ์Šคํฐํ•˜์ง€ ์•Š์•„ ๋ฏธ๋…ธ์ถœ ์œ ์ง€. ์•Œ๋ฆผ flush๋Š” ๊ธฐ์กด ๊ตฌ๋…์ž ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ์ˆ˜ํ–‰ํ•œ๋‹ค. 2. ๋ถ€์ˆ˜ํšจ๊ณผ์˜ **์›๊ฒฉ** ํ™•์ธ(์‹ค์ œ push ๋„๋‹ฌ ์—ฌ๋ถ€ ๋“ฑ)์€ ๋น„๋ฒ”์œ„ โ€” ์ฆ๊ฑฐ์˜ ์กด์žฌยท๋Œ€์‘๊นŒ์ง€๋งŒ ๊ฒ€์ฆํ•œ๋‹ค. 3. `agy`/`hermes`/`opencode` ์ž๋™์™„๋ฃŒ๋Š” ์ •์ง€ ์ƒํƒœ ์‹ค์ธก ์ฆ๊ฑฐ ํ™•๋ณด ํ›„ ๋ณ„๋„ ํŒ๋‹จ.