# ๐Ÿ“‘ Target State Transitions and CAS Specification - **Document Version**: Rev.6 (dispatch token ๊ธฐ๋ฐ˜ ์›์ž์  ์‹œ๋„ ๊ท€์† ์ถ”๊ฐ€) - **Issue**: [Gitea Issue #5](https://git.godopu.com/tmpl/multi-agent-mux/issues/5) - **Scope**: Target Compare-And-Swap (CAS) State Machine & Attribution Contract --- ## 1. ์ด๋ฒคํŠธ(Event)์™€ ์ƒํƒœ(Status)์˜ ๊ฐœ๋…์  ๋ถ„๋ฆฌ ๊ธฐ์กด ์‹œ์Šคํ…œ์˜ ํ˜ผ์„ ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์šฉ์–ด๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•˜์—ฌ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค: - **์ด๋ฒคํŠธ (Event)**: ์—์ด์ „ํŠธ, ์›Œ์ฒ˜(Watcher), ๋˜๋Š” ์™ธ๋ถ€ ์šด์˜์ž๊ฐ€ ํŠน์ • ์‹œ์ ์— ๋ฉ”์‹œ์ง• ๋ฐฑํ”Œ๋ ˆ์ธ(MQTT)์ด๋‚˜ ๋กœ์ปฌ ์ฑ„๋„๋กœ ์ „๋‹ฌํ•˜๋Š” **์‚ฌ๊ฑด(Fact)**์ž…๋‹ˆ๋‹ค (`started`, `progress`, `permission_required`, `completed`, `error`, `cancelled`). - **์ƒํƒœ (Status)**: ๋‹จ์ผ ์ƒํƒœ ์ œ์–ด ์—”์ง„(Engine)์ด ์›์ž์  CAS ํŠธ๋žœ์žญ์…˜์„ ํ†ตํ•ด ๊ณตํ†ต ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— ์˜์†์ ์œผ๋กœ ๊ธฐ๋กํ•˜๋Š” **ํ˜„์žฌ ์ž‘์—…์˜ ๊ณต์‹ ์ƒ์• ์ฃผ๊ธฐ ๋‹จ๊ณ„**์ž…๋‹ˆ๋‹ค (`pending`, `running`, `completed`, `error`, `cancelled`). > ๐Ÿ“Œ **ํ•ต์‹ฌ ์›์น™**: ์ด๋ฒคํŠธ๋Š” ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•ด ๋‹ฌ๋ผ๋Š” **์ „์ด ์š”์ฒญ(Transition Request)**์ผ ๋ฟ์ด๋ฉฐ, ์—”์ง„์˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ๊ณผ CAS ๊ฒŒ์ดํŠธ๋ฅผ ํ†ต๊ณผํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. --- ## 2. 4์ค‘ ์‹คํ–‰ ๊ท€์†(Execution Attribution) ๋ณด์žฅ ๊ณ„์•ฝ ๋‹จ์ˆœํžˆ ์—์ด์ „ํŠธ ํ„ฐ๋ฏธ๋„์ด ์œ ํœด(`idle`) ์ƒํƒœ๋ผ๊ณ  ํ•ด์„œ ์ž‘์—…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ข…๋ฃŒ๋˜์—ˆ๋‹ค๊ณ  ์ถ”๋ก (Inferred Completion)ํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ์ด์ „ ์ž‘์—…์˜ ์ž”์—ฌ ์œ ํœด ์ƒํƒœ, ์„ธ์…˜ ์žฌ์‚ฌ์šฉ, ๋˜๋Š” ํ”„๋กœ์„ธ์Šค ์žฌ์‹œ์ž‘์œผ๋กœ ์ธํ•œ ์˜คํƒ์„ ์›์ฒœ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ **4์ค‘ ์‹๋ณ„์ž ํŠœํ”Œ**์„ ํ•„์ˆ˜๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค: $$\text{Attribution Tuple} = (\text{job\_id}, \text{attempt\_id}, \text{agent\_session\_uuid}, \text{pane\_process\_generation})$$ 1. **`job_id`**: ๋“ฑ๋ก๋œ ๊ณ ์œ  ์ž‘์—… ์‹๋ณ„์ž (32-bit hex ๋˜๋Š” UUID). 2. **`attempt_id`**: ๋‹จ์ผ Job ๋‚ด์—์„œ ์žฌ์‹œ๋„ ์‹œ ๋‹จ์กฐ ์ฆ๊ฐ€ํ•˜๋Š” ์‹œ๋„ ๋ฒˆํ˜ธ. 3. **`agent_session_uuid`**: ์—์ด์ „ํŠธ ํ”„๋กœ์„ธ์Šค ๊ธฐ๋™ ์‹œ ํ• ๋‹น๋œ ์˜์† ๊ณ ์œ  ์‹๋ณ„์ž. 4. **`pane_process_generation`**: TMUX/Herdr ์ฐฝ ๋ฐ ๊ธฐ์ € ์…ธ ํ”„๋กœ์„ธ์Šค์˜ ์‹œ์ž‘ ์‹œ๊ฐ(`lstart`) ๋ฐ PID ์กฐํ•ฉ. ### ๊ท€์† ๋ฐ ์‹คํ–‰ ์•ต์ปค ๋ถˆ๋ณ€์‹: - ๋™์ผ ์—์ด์ „ํŠธ ์„ธ์…˜์—๋Š” ๋™์‹œ์— ๋‹จ ํ•˜๋‚˜์˜ ํ™œ์„ฑ ์ž‘์—…(`job_id`)๋งŒ ๋ฐฐ์ •๋ฉ๋‹ˆ๋‹ค. - ๋””์ŠคํŒจ์น˜ ํ™•์ธ(`dispatch_ack`) ์ดํ›„, ํ•ด๋‹น `attempt_id`์— ์†ํ•˜๋Š” ์‹ค์ œ ํ„ฐ๋ฏธ๋„ ์ถœ๋ ฅ ๋ฐ ํ™œ๋™(Execution Anchor)์ด ๊ด€์ธก๋œ ๊ฒฝ์šฐ์—๋งŒ ์™„๋ฃŒ ํ›„๋ณด๋กœ ์ธ์ •ํ•ฉ๋‹ˆ๋‹ค. - ๋„ค์ดํ‹ฐ๋ธŒ API๊ฐ€ ์ œ๊ณตํ•˜์ง€ ๋ชปํ•˜๋Š” ์‹๋ณ„์ž๋Š” `null + reason`์œผ๋กœ ํ‘œ๊ธฐํ•˜๋ฉฐ, ๊ฐ€์งœ ๊ฐ’์„ ์ž„์˜๋กœ ์ฃผ์ž…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. --- ## 3. ๋ชฉํ‘œ CAS ์ƒํƒœ ์ „์ดํ‘œ (Target State Machine) ๋ชจ๋“  ์ƒํƒœ ๋ณ€๊ฒฝ์€ Registry Lock ๋ณดํ˜ธ ํ•˜์—์„œ ๊ธฐ๋Œ€ ์ƒํƒœ(`expected_state`), ์‹œ๋„ ์„ธ๋Œ€(`attempt_id`), ๋ฒ„์ „ ๋ฒˆํ˜ธ(`version`)๋ฅผ ์›์ž์ ์œผ๋กœ ๋น„๊ตํ•œ ํ›„ ๊ฐฑ์‹ (CAS)ํ•ฉ๋‹ˆ๋‹ค. | ํ˜„์žฌ ์ƒํƒœ (`Current`) | ์š”์ฒญ ์‹ ํ˜ธ (`Request`) | ์ „์ด ์กฐ๊ฑด ๋ฐ ๊ฒ€์ฆ ๊ทœ์น™ | ๊ฒฐ๊ณผ ์ƒํƒœ (`Next`) | ๋น„๊ณ  ๋ฐ ๊ฐˆ๋“ฑ ์ฒ˜๋ฆฌ | |---|---|---|---|---| | `pending` | `started` / `claim` | ์ž‘์—… ํ• ๋‹น ์„ธ์…˜ ๋ฐ `attempt_id` ์ผ์น˜ ํ™•์ธ | `running` | `started`๋Š” ์ƒํƒœ enum์ด ์•„๋‹ˆ๋ฉฐ `running`์œผ๋กœ ์ „์ด | | `running` | `progress` | ๋น„-Terminal ์œ ์ง€. ์ตœ๊ทผ ํ™œ๋™ ์‹œ๊ฐ ๋ฐ ์„ธ๋ถ€ ์ •๋ณด ๊ฐฑ์‹  | `running` | ์ƒํƒœ ๋ณ€๊ฒฝ ์—†์ด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋งŒ ๊ฐฑ์‹  | | `running` | `permission_required` | ๋น„-Terminal ์œ ์ง€. `blocked_reason` ๊ธฐ๋ก | `running` | ๊ถŒํ•œ ๋Œ€๊ธฐ ์ค‘์—๋Š” ์ž๋™์™„๋ฃŒ ์ „๋ฉด ๊ธˆ์ง€ | | `running` | `explicit terminal` | ์œ ํšจํ•œ ์ž‘์—…์ž ์„ธ์…˜์˜ ์„œ๋ช…๋œ `completed`/`error`/`cancelled` ์ˆ˜์‹  | ์š”์ฒญ๋œ Terminal | ์ •์ƒ ์ข…๋ฃŒ ์ปค๋ฐ‹ | | `running` | `inferred completed` | 4์ค‘ ๊ท€์† ์ผ์น˜ + ์‹คํ–‰ ์•ต์ปค ํ™•์ธ + ํ™•์ • ํ•ด์‹œ/๋งค๋‹ˆํŽ˜์ŠคํŠธ ์กด์žฌ + Fresh `idle/done` + ๋ธ”๋กœ์ปค ์—†์Œ + ๋ถ€์ˆ˜ํšจ๊ณผ ๊ฒ€์ฆ | `completed` | Fail-Closed AND ๊ฒŒ์ดํŠธ ํ†ต๊ณผ ์‹œ์—๋งŒ CAS ์ปค๋ฐ‹ | | `terminal` | ๋™์ผ ๋…ผ๋ฆฌ์  ์™„๋ฃŒ ์žฌ์ˆ˜์‹  | ๊ธฐ ์ปค๋ฐ‹๋œ Terminal ์ƒํƒœ์™€ ๋™์ผํ•œ ์š”์ฒญ | `terminal` (No-op) | ๋ฉฑ๋“ฑ(Idempotent) ACK ๋ฐ˜ํ™˜, ์ถ”๊ฐ€ ๋””์ŠคํŒจ์น˜ ๊ธˆ์ง€ | | `terminal` | ์ƒ์ถฉ ์‹ ํ˜ธ (`progress`/๋‹ค๋ฅธ Terminal) | ์ด๋ฏธ Terminal ์ƒํƒœ์— ๋„๋‹ฌํ•œ ํ›„ ๋Šฆ๊ฒŒ ๋„์ฐฉํ•œ ์‹ ํ˜ธ | ๊ธฐ ์ปค๋ฐ‹ ์ƒํƒœ ์œ ์ง€ | ์ƒํƒœ ์—ญํ–‰ ๋ฐ ๋ฎ์–ด์“ฐ๊ธฐ ๊ฑฐ๋ถ€, Conflict Audit Log ๊ธฐ๋ก | | ์ž„์˜ ์ƒํƒœ | Stale Attempt / Generation | ๊ณผ๊ฑฐ ์‹œ๋„ ์„ธ๋Œ€ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค ์„ธ๋Œ€ ๋ถˆ์ผ์น˜ ์‹ ํ˜ธ | ์ „์ด ๊ฑฐ๋ถ€ | Stale Attempt ๊ฒฝ๊ณ  ๊ธฐ๋ก ๋ฐ ํŒจํ‚ท ํ๊ธฐ | | `running` | `deadline_timeout` | ์ž‘์—… ํƒ€์ž„์•„์›ƒ ๊ฒฝ๊ณผ ๋ฐ ์‹คํ–‰ ์ค‘๋‹จ ํ™•์ธ | `error` | ํƒ€์ž„์•„์›ƒ ์›์ธ ๊ธฐ๋ก | | `terminal` | `redispatch` (**์šด์˜์ž ๊ถŒํ•œ**) | ๋ฐ˜๋ณต ์œ„์ž„(`--type loop\|discuss`)์˜ ๋‹ค์Œ ํšŒ์ฐจ ์ „๋‹ฌ. `iteration`์ด ๊ธฐ์กด ๊ฐ’๋ณด๋‹ค **์—„๊ฒฉํžˆ ์ฆ๊ฐ€**ํ•ด์•ผ ํ•จ | `pending` | ๊ต์ฐจ ๋ฆฌ๋ทฐ `68abd0ff` ๋ณด์™„. ์žฌ์ƒ(replay)์€ iteration ๋ฏธ์ฆ๊ฐ€๋กœ ๊ฑฐ๋ถ€๋จ | | `terminal` | `finalize` (**์šด์˜์ž ๊ถŒํ•œ**) | ๋ฐ˜๋ณต ์˜ˆ์‚ฐ ์†Œ์ง„ ์‹œ ์›Œํฌํ”Œ๋กœ ํ™•์ • | `error` | ๊ต์ฐจ ๋ฆฌ๋ทฐ `68abd0ff` ๋ณด์™„ | > ๐Ÿ”‘ **๊ถŒํ•œ ์ถ•(Authority)**: `redispatch`ยท`finalize`๋Š” `source โˆˆ {registry_cli, operator, delegate_wrapper}`์—์„œ๋งŒ ํ—ˆ์šฉ๋œ๋‹ค. ์—์ด์ „ํŠธ(`publish_event`)๋Š” **์ž์‹ ์˜ terminal์„ ๋˜๋Œ๋ฆด ์ˆ˜ ์—†๋‹ค** โ€” ์ด๊ฒƒ์ด CAS ํ‘œ์˜ ์กด์žฌ ์ด์œ ์ด๋ฉฐ, ์œ„ ๋‘ ํ–‰์€ ๊ทธ ์›์น™์˜ ์˜ˆ์™ธ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ž˜ํผ๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ณ„๊ฐœ ์ „์ด๋ฅผ ์ด๋ฆ„ ๋ถ™์ธ ๊ฒƒ์ด๋‹ค. > > ๐Ÿ”‘ **์‹œ๋„ ์ •์ฒด์„ฑ์€ ๋ ˆ์ฝ”๋“œ์— ์žˆ๋‹ค**: `dispatch_token`์€ ์‹œ๋„๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ์š”์ฒญ(`claim`/`redispatch`)์—์„œ ์ƒˆ๋กœ ๋ฐœ๊ธ‰๋˜๋ฉฐ, `expected_dispatch_token` ์ „์ œ์กฐ๊ฑด์œผ๋กœ **๋ฝ ์•ˆ์—์„œ** ๋Œ€์กฐ๋œ๋‹ค. ์ปค๋ฐ‹ ์ „์—๋งŒ ํ™•์ธํ•˜๋Š” ๊ท€์† ๊ฒ€์‚ฌ๋Š” ๊ทธ ์‚ฌ์ด์˜ ์žฌ๋””์ŠคํŒจ์น˜๋ฅผ ๋ง‰์ง€ ๋ชปํ•œ๋‹ค โ€” ์ „์ œ์กฐ๊ฑด์ด ์ปค๋ฐ‹๊ณผ ์›์ž์ ์ด๋ ค๋ฉด ํŠธ๋žœ์žญ์…˜์ด ์ž๊ธฐ ๋ฝ ์•ˆ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. `iteration`(๋ฃจํ”„ ํšŒ์ฐจ)๊ณผ๋Š” ๋‹ค๋ฅธ ๊ฐœ๋…์ด๋ฏ€๋กœ ๋ณ„๋„ ํ•„๋“œ๋‹ค. ์žฌ์œ„์ž„๋œ ์ž‘์—…(`attempt_id > 1`)์˜ ๋น„-์šด์˜์ž ์†Œ์Šค terminal ์š”์ฒญ์€ ๋ฐ˜๋“œ์‹œ ๊ณ ์ •๋œ dispatch token ๋˜๋Š” `expected_attempt` ์ „์ œ์กฐ๊ฑด์„ ์ฆ๋ช…ํ•ด์•ผ ์ปค๋ฐ‹๋œ๋‹ค. โ€” ๊ต์ฐจ ๋ฆฌ๋ทฐ `a45e5b7f` R2, Issue #6 > > ๐Ÿ”‘ **๋ฉฑ๋“ฑ ACK๋Š” ๊ฑฐ๋ถ€๊ฐ€ ์•„๋‹ˆ๋‹ค**: `terminal` ์ƒํƒœ์—์„œ ๊ฐ™์€ terminal์„ ์žฌ์ˆ˜์‹ ํ•˜๋ฉด ํ‘œ๋Š” ์ด๋ฅผ **No-op ACK**๋กœ ์ •์˜ํ•œ๋‹ค. ํ˜ธ์ถœ์ž(์šด์˜์ž CLI)๋Š” ์ด๋ฅผ ์„ฑ๊ณต(rc 0)์œผ๋กœ ์ทจ๊ธ‰ํ•ด์•ผ ํ•œ๋‹ค. ์‹ค์ œ ๊ฑฐ๋ถ€(์ƒ์ถฉ ์‹ ํ˜ธยท๊ถŒํ•œ ๋ถ€์กฑ)๋งŒ non-zero๋‹ค. โ€” ๊ต์ฐจ ๋ฆฌ๋ทฐ `cb792e91` F-C > > ๐Ÿ”‘ **status๋Š” ์š”์ฒญ์œผ๋กœ๋งŒ ์„ค์ •๋œ๋‹ค**: ์ž„์˜ ํ•„๋“œ๋กœ ์‹ค๋ฆฐ `status`๋Š” ๊ฒฝ๊ณ„ ๋‚ด๋ถ€์—์„œ ๊ฑฐ๋ถ€๋œ๋‹ค(`progress`๊ฐ€ terminal์„ ์ปค๋ฐ‹ํ•˜๋Š” ์šฐํšŒ ์ฐจ๋‹จ). ์•Œ ์ˆ˜ ์—†๋Š” ์š”์ฒญ๋ช…๋„ ๊ฑฐ๋ถ€๋œ๋‹ค. `pending`๋„ ์†Œ์œ  ์š”์ฒญ(`redispatch`)์„ ๊ฐ–๋Š”๋‹ค. --- ### 3-1. ๊ตฌํ˜„ ๋งคํ•‘ (Phase 2a) | ๊ณ„์•ฝ | ๊ตฌํ˜„ | ํ…Œ์ŠคํŠธ | |---|---|---| | ยง3 CAS ์ „์ดํ‘œ | `lib_py/delegation/engine.py::_decide` (์ˆœ์ˆ˜ ํ•จ์ˆ˜, ๋ฝ ์•ˆ์—์„œ ํ˜ธ์ถœ) | `test_engine_*`, `test_fa_*`, `test_r2_*`, `test_r3_*` | | ๋‹จ์ผ ์ „์ด ์ฃผ์ฒด | `engine.transition` โ€” ์œ ์ผํ•œ ์ƒํƒœ writer. `update_job_status`ยท`pick_pending`์ด ์ด๋ฅผ ๊ฒฝ์œ  | `test_g6_every_record_writer_*` | | ๋ฝ ๋‚ด I/O ๋ฐฐ์ œ | ๋ฝ = ํŒ์ • + ๋ ˆ์ฝ”๋“œ 1ํšŒ ์“ฐ๊ธฐ. ๊ฐ์‚ฌ mirror๋Š” ํ์ž‰ ํ›„ ๋ฝ ๋ฐ– flush | `test_g5_no_blocking_io_*` | | ยง2 4์ค‘ ๊ท€์† | `lib_py/loop/attribution.py::check` + `policy.collect_observed_identity` (๊ด€์ธก ์‹๋ณ„์ž์™€์˜ ๋Œ€์กฐ) | `test_attribution_*`, `test_r1_*` | | ๋กค๋ฐฑ | `MAM_ENGINE_CAS=0` โ†’ ๋ณด์กด๋œ `_*_legacy` ๋ณธ์ฒด | ์ „ ํŠน์„ฑํ™” ํ…Œ์ŠคํŠธ parametrize | > ๐Ÿ“Œ **Phase 2a๋Š” ์ถ”๋ก  ์™„๋ฃŒ๋ฅผ ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๋Š”๋‹ค.** `inferred completed` ํ–‰์€ `lib_py/loop/policy.py`๊ฐ€ `candidate_approved`๋กœ **ํŒ์ •๋งŒ** ํ•˜๊ณ , shadow ๋Ÿฌ๋„ˆ๊ฐ€ ์ด๋ฅผ ๋กœ๊ทธ๋กœ ๋‚จ๊ธด๋‹ค. ์‹ค์ œ CAS ์ปค๋ฐ‹ ์—ฐ๋™์€ Phase 2b๋‹ค. --- ## 4. ๋ฆฌํฌํŠธ ํ™•์ • ๋‹จ๊ณ„ (Report Finalization Lifecycle) ์ž๋™์™„๋ฃŒ ์ถ”๋ก  ์‹œ ํŒŒ์ผ ์“ฐ๊ธฐ ๋„์ค‘ ๋ฐœ์ƒํ•˜๋Š” ๋ถˆ์™„์ „ ๋ฆฌํฌํŠธ ์ฑ„ํƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด 3๋‹จ๊ณ„ ํ™•์ • ๊ณ„์•ฝ์„ ์ˆ˜๋ฆฝํ•ฉ๋‹ˆ๋‹ค: ``` [writing] โ”€โ”€(์“ฐ๊ธฐ ์ง„ํ–‰ ์ค‘)โ”€โ”€> [stable_candidate] โ”€โ”€(์›์ž์  ๊ต์ฒด ๋ฐ ๋งค๋‹ˆํŽ˜์ŠคํŠธ)โ”€โ”€> [finalized] ``` 1. **`writing` ๋‹จ๊ณ„**: - ์—์ด์ „ํŠธ๊ฐ€ ์ž„์‹œ ํŒŒ์ผ(`report-final.md.tmp`)์„ ์ž‘์„ฑ ์ค‘์ธ ์ƒํƒœ. - ์›Œ์ฒ˜๋Š” ์ด ์ƒํƒœ์—์„œ ์™„๋ฃŒ๋ฅผ ์ ˆ๋Œ€ ์ธ์ •ํ•˜์ง€ ์•Š์Œ (Hold). 2. **`stable_candidate` ๋‹จ๊ณ„ (1์ฐจ/๋ณด์กฐ ํ•„ํ„ฐ)**: - ๋ฆฌํฌํŠธ ํŒŒ์ผ์˜ mtime์ด ๋‹จ์กฐ ์‹œ๊ณ„(monotonic clock) ๊ธฐ์ค€ **์ตœ์†Œ 15์ดˆ(๊ธฐ๋ณธ ๊ถŒ์žฅ๊ฐ’)** ๋™์•ˆ ๋ถˆ๋ณ€์ธ ์ƒํƒœ. - โš ๏ธ **๋ถˆ๋ณ€์‹**: **๋””๋ฐ”์šด์Šค ๊ฒฝ๊ณผ(15s)๋งŒ์œผ๋กœ๋Š” ์™„๋ฃŒ ๊ถŒํ•œ์ด ์„ฑ๋ฆฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.** ์ด๋Š” ์ผ์‹œ์ ์ธ LLM ์ƒ๊ฐ ์ค‘๋‹จ์ด๋‚˜ ๋„คํŠธ์›Œํฌ ์ง€์—ฐ์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์˜ค์ง 'ํ›„๋ณด ํ•„ํ„ฐ'๋กœ๋งŒ ๊ธฐ๋Šฅํ•ฉ๋‹ˆ๋‹ค. 3. **`finalized` ๋‹จ๊ณ„ (2์ฐจ/ํ™•์ • ๊ณ„์•ฝ)**: - ์ตœ์ข… ๋Œ€์ƒ ๊ฒฝ๋กœ(`report-final.md`)๋กœ์˜ **์›์ž์  ์ด๋ฆ„ ๋ณ€๊ฒฝ(Atomic Rename)** ์™„๋ฃŒ. - ํ•ด๋‹น ์‹œ๋„์˜ `attempt_id`์™€ `report SHA-256 hash`๊ฐ€ ๋ช…์‹œ๋œ **์™„๋ฃŒ ๋งค๋‹ˆํŽ˜์ŠคํŠธ(Commit Manifest)** ์ƒ์„ฑ ์™„๋ฃŒ. - ์™ธ๋ถ€ ๋ถ€์ˆ˜ํšจ๊ณผ(Git push, API ํ˜ธ์ถœ)๊ฐ€ ์ˆ˜๋ฐ˜๋˜๋Š” ์ž‘์—…์ธ ๊ฒฝ์šฐ, ํ•ด๋‹น ๋ถ€์ˆ˜ํšจ๊ณผ์˜ ์™„๋ฃŒ ์ฆ๊ฑฐ๊ฐ€ ๋งค๋‹ˆํŽ˜์ŠคํŠธ์— ์ฒจ๋ถ€๋˜์–ด์•ผ ํ•จ. - ๋ฆฌํฌํŠธ๊ฐ€ ์žฌ์ž‘์„ฑ๋˜๋ฉด ์ด์ „ ํ•ด์‹œ๋Š” ์ฆ‰์‹œ ๋ฌดํšจํ™”๋˜๋ฉฐ ์ƒˆ๋กœ์šด ํ™•์ • ์ ˆ์ฐจ๊ฐ€ ํ•„์š”ํ•จ. --- ## 5. ์ง€์—ฐ ์•Œ๋ฆผ (Pending Notification) ๋ฐ ํŠธ๋žœ์žญ์…˜ ๋ณต๊ตฌ ์„ค๊ณ„ ์ƒํƒœ ์ „์ด ๋ฝ(Registry Lock) ํ•˜์—์„œ ์™ธ๋ถ€ I/O(MQTT ๋ธŒ๋กœ์ปค ์ „์†ก, ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ)๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋ฐ๋“œ๋ฝ๊ณผ ์‹ฌ๊ฐํ•œ ์ง€์—ฐ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ **๋‚ด๊ตฌ์„ฑ ์ง€์—ฐ ์•Œ๋ฆผ(Pending Notification) ํŠธ๋žœ์žญ์…˜**์„ ๋ช…์„ธํ•ฉ๋‹ˆ๋‹ค: ```mermaid sequenceDiagram participant Engine participant Registry as Job Registry (Disk) participant Publisher as Async Publisher (Wire) participant Broker as MQTT Broker Note over Engine: 1. CAS ์ „์ด ๊ฒฐ์ • activate Engine Engine->>Registry: ๋ฝ ํš๋“ (fcntl.flock) Engine->>Registry: ์›์ž์  ์ƒํƒœ ์ปค๋ฐ‹ (status=completed, pending_notification=intent) Engine->>Registry: ๋ฝ ์ฆ‰์‹œ ํ•ด์ œ deactivate Engine Note over Publisher: 2. ๋น„๋™๊ธฐ ์•Œ๋ฆผ ์ „์†ก Publisher->>Broker: MQTT ์ด๋ฒคํŠธ ๋ฐœํ–‰ (HMAC ์„œ๋ช… ํฌํ•จ) alt ์ „์†ก ์„ฑ๊ณต Broker-->>Publisher: ACK (PUBACK) Publisher->>Registry: pending_notification ์™„๋ฃŒ ํ‘œ์‹œ else ์ „์†ก ์‹คํŒจ / ํฌ๋ž˜์‹œ Note over Publisher: ๋ฐฑ์˜คํ”„ ์žฌ์‹œ๋„ ๋ฐ ๊ธฐ๋™ ์‹œ ๋ฏธ์™„๋ฃŒ ์•Œ๋ฆผ ๋ณต๊ตฌ ์ „์†ก end ``` ### ํŠธ๋žœ์žญ์…˜ ๋ณด์žฅ ๊ทœ์น™: 1. **๋‹จ์ผ ๋‚ด๊ตฌ์„ฑ ์ž‘์—… ๋ ˆ์ฝ”๋“œ**: - ๋…๋ฆฝ๋œ ๋ณ„๋„์˜ Outbox DB๋ฅผ ์‹ ์„คํ•˜์ง€ ์•Š๊ณ , ๊ธฐ์กด `.mam/jobs/.json` ๋ ˆ์ฝ”๋“œ ๋‚ด์— `pending_notification: { event, timestamp, seq, signature }`๋ฅผ ์›์ž์ ์œผ๋กœ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. 2. **๋ฝ ํ•ด์ œ ํ›„ ์ „์†ก**: - ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๋ฝ์„ ํ•ด์ œํ•œ ํ›„ ๋น„๋™๊ธฐ ์›Œ์ปค๊ฐ€ MQTT ๋ฐœํ–‰์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. 3. **ํฌ๋ž˜์‹œ ๋ณต๊ตฌ(Crash Recovery)**: - ์—”์ง„ ์žฌ์‹œ์ž‘ ์‹œ `status in TERMINAL`์ด๋ฉด์„œ `pending_notification`์ด ๋‚จ์•„์žˆ๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ์Šค์บ”ํ•˜์—ฌ ๋ฉฑ๋“ฑ์ ์œผ๋กœ ์žฌ์ „์†กํ•ฉ๋‹ˆ๋‹ค. --- ## 6. ๊ถŒํ•œ ์ฐจ๋‹จ(Permission Blocked) ํ•ด์ œ ์ •์ฑ… - ์—์ด์ „ํŠธ ํ„ฐ๋ฏธ๋„์ด `blocked` (๊ถŒํ•œ ์Šน์ธ ๋Œ€๊ธฐ) ์ƒํƒœ๋กœ ๊ด€์ธก๋˜๋ฉด, **์–ด๋– ํ•œ ๊ฒฝ์šฐ์—๋„ ์ž๋™์™„๋ฃŒ ์ „์ด๋ฅผ ์‹œ๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.** - ์ฐจ๋‹จ ํ•ด์ œ ํŒ๋‹จ: - ๋ฌต์‹œ์  ์ „์ด ๊ธˆ์ง€: ๋‹จ์ˆœํžˆ ๋‹ค์Œ ๊ด€์ธก์—์„œ `working`์ด ๋˜์—ˆ๋‹ค๊ณ  ํ•ด์„œ ์ด์ „ ์ฐจ๋‹จ์ด ์ •๋‹นํ•˜๊ฒŒ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค๊ณ  ๋‹จ์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. - ๋ช…์‹œ์  ์Šน์ธ ์ฆ๊ฑฐ ๋˜๋Š” ์šด์˜์ž์˜ ์Šน์ธ ์ž…๋ ฅ ๋กœ๊ทธ๊ฐ€ ํ™•์ธ๋˜์ง€ ์•Š๋Š” ํ•œ, ์ž‘์—…์€ `running (blocked)` ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ ๋ฐ๋“œ๋ผ์ธ ๋„๋‹ฌ ์‹œ ์•ˆ์ „ํ•˜๊ฒŒ ํƒ€์ž„์•„์›ƒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.