# πŸ“Š MAM λ©”μ‹œμ§• λ°±ν”Œλ ˆμΈ μ•„ν‚€ν…μ²˜ 심측 뢄석 λ³΄κ³ μ„œ: MQTT vs NATS - **λ¬Έμ„œ 버전**: Rev.2 Final Synthesis (`f1956d2e` / `5ac88ca0`) - **μž‘μ„±/κ²€ν†  주체**: MAM Multi-Agent Orchestration Team (`claude`, `agy`) - **κΈ°μ€€ 컀밋**: `ac82f9b` (`refactor`, 276/276 tests passing) - **λ¬Έμ„œ λͺ©μ **: MAM ν”„λ ˆμž„μ›Œν¬μ˜ λ©”μ‹œμ§• 인프라(MQTT)λ₯Ό NATS둜 μ „λ©΄ μ „ν™˜ν•  것인지 여뢀에 λŒ€ν•œ 쒅합적인 κΈ°μˆ Β·μš΄μ˜Β·λ³΄μ•ˆ 타당성 뢄석 및 μ‹€ν–‰ λ‘œλ“œλ§΅ ν™•μ •. --- ## 0. μ΅œμ’… νŒμ • (Executive Verdict) > ### 🎯 **[VERDICT: DO NOT MIGRATE CLIENT PROTOCOL β€” ADOPT `nats-server` AS DEDICATED BROKER]** > > **ν΄λΌμ΄μ–ΈνŠΈ 전솑 ν”„λ‘œν† μ½œ(MQTT)은 μœ μ§€ν•˜κ³ , μ „μš© λΈŒλ‘œμ»€λ‘œμ„œ `nats-server`의 λ‚΄μž₯ MQTT 3.1.1 μ–΄λŒ‘ν„°λ₯Ό μ±„νƒν•©λ‹ˆλ‹€.** ### 0.1 3λŒ€ 핡심 κ·Όκ±° μš”μ•½ ``` [MAM Control Plane] ────> run_loop.sh (wait_for_job: 3s Local Disk Polling) ──> 100% Broker-Independent [Observability Plane] ────> publish_event.py ──(MQTT 3.1.1)──> nats-server (JetStream + nkeys) ``` 1. **μ œμ–΄ 평면과 κ΄€μΈ‘ ν‰λ©΄μ˜ 뢄리**: MAM의 핡심 루프(`run_loop.sh`)λŠ” MQTT λ©”μ‹œμ§€λ₯Ό κ΅¬λ…ν•˜μ§€ μ•ŠμœΌλ©°, 둜컬 νŒŒμΌμ‹œμŠ€ν…œ(`.mam/jobs/.json`)을 3초 주기둜 폴링(`wait_for_job`)ν•˜μ—¬ μž‘μ—… μ™„λ£Œλ₯Ό νŒμ •ν•©λ‹ˆλ‹€. λΈŒλ‘œμ»€λŠ” **비동기 κ΄€μΈ‘(observability) μ‚¬μ΄λ“œμΉ΄**이며 μ œμ–΄ 평면을 μ°¨λ‹¨ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 2. **NATS의 μ‹€μ§ˆμ  이점은 'μ„œλ²„'에 쑴재**: NATS의 핡심 강점(단일 무의쑴 Go λ°”μ΄λ„ˆλ¦¬, JetStream μ˜μ†μ„±, nkeys/JWT 계정·Subject별 ACL)은 μ„œλ²„ κ³„μΈ΅μ˜ μ†μ„±μž…λ‹ˆλ‹€. `nats-server`λŠ” **MQTT 3.1.1 ν”„λ‘œν† μ½œμ„ λ„€μ΄ν‹°λΈŒλ‘œ 수용**ν•˜λ―€λ‘œ, ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œλ₯Ό ν•œ 쀄도 λ°”κΎΈμ§€ μ•Šκ³  μ„œλ²„μ˜ λͺ¨λ“  μš΄μ˜Β·λ³΄μ•ˆ 이점을 100% 확보할 수 μžˆμŠ΅λ‹ˆλ‹€. 3. **λ„€μ΄ν‹°λΈŒ NATS(`nats-py`) μ „ν™˜μ˜ λΉ„μš© λŒ€λΉ„ 무읡함**: `nats-py`λŠ” asyncio μ „μš© 라이브러리둜, bash 기반의 단λͺ…(short-lived) 동기 CLI 도ꡬ듀(`publish_event.py` λ“±)κ³Ό μ‹¬κ°ν•œ ꡬ쑰적 λ§ˆμ°°μ„ μΌμœΌν‚€λ©°, μ΅œμ†Œ 46건의 ν…ŒμŠ€νŠΈ μž¬μž‘μ„± 및 276건 green 베이슀라인 훼손 μœ„ν—˜μ„ μ΄ˆλž˜ν•©λ‹ˆλ‹€. 반면 NATS 고유 κΈ°λŠ₯(Req/Reply, μ΄ˆλ‹Ή 수백만 μ²˜λ¦¬λŸ‰, ν΄λŸ¬μŠ€ν„°λ§)은 MAM μ›Œν¬λ‘œλ“œ(단일 μ›Œν¬μŠ€νŽ˜μ΄μŠ€, μž‘λ‹Ή 수 개 이벀트)μ—μ„œ μ „ν˜€ μ‚¬μš©λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. --- ## 1. 3λŒ€ μ „λž΅μ  선택지 비ꡐ 뢄석 | 평가 ν•­λͺ© | (A) ν˜„ν–‰ μœ μ§€ (곡개 HiveMQ) | (B) λ„€μ΄ν‹°λΈŒ NATS μ „ν™˜ (`nats-py`) | (C) `nats-server` + MQTT ν”„λ‘œν† μ½œ μœ μ§€ (μ±„νƒμ•ˆ) | |---|---|---|---| | **ν΄λΌμ΄μ–ΈνŠΈ μ½”λ“œ λ³€κ²½** | 0쀄 | 4개 ν˜ΈμΆœλΆ€ μ „λ©΄ 비동기 μž¬μž‘μ„± | **0쀄** (ν™˜κ²½λ³€μˆ˜λ§Œ ꡬ성) | | **ν…ŒμŠ€νŠΈ μ½”λ“œ μž¬μž‘μ„±** | 0건 | μ΅œμ†Œ 46건 μž¬μž‘μ„± (276건 베이슀라인 μœ„ν—˜) | **0건** (κΈ°μ‘΄ 276건 100% 보쑴) | | **A-2 λ³΄μ•ˆ 결함 ν•΄μ†Œ** | ❌ λΆˆκ°€ (곡개 브둜컀) | βœ… μ™„μ „ ν•΄μ†Œ | βœ… **μ™„μ „ ν•΄μ†Œ** (nkeys/JWT subject ACL) | | **단일 정적 λ°”μ΄λ„ˆλ¦¬ 배포** | ❌ λΆˆκ°€ | βœ… 지원 | βœ… **지원** (`nats-server` λ°”μ΄λ„ˆλ¦¬ 1개) | | **이벀트 μ˜μ†μ„± (JetStream)** | ❌ 미지원 | βœ… 지원 | βœ… **지원** (λ‚΄μž₯ JetStream μ—”μ§„) | | **동기 CLI ν˜Έν™˜μ„±** | βœ… 우수 (paho-mqtt) | ❌ 심각 (asyncio κ°•μ œ) | βœ… **우수** (κΈ°μ‘΄ 동기 ν•«νŒ¨μŠ€ μœ μ§€) | | **되돌리기(Rollback) λΉ„μš©** | β€” | πŸ”΄ λ†’μŒ (λΉ„κ°€μ—­ μ½”λ“œ μž¬μž‘μ„±) | 🟒 **0 (가역적 ν™˜κ²½λ³€μˆ˜ μŠ€μœ„μΉ˜)** | | **μ΅œμ’… 평가** | **기각 (λ³΄μ•ˆ μœ„ν—˜)** | **기각 (λΉ„μš© λŒ€λΉ„ 싀읡 전무)** | πŸ† **μ΅œμ’… 채택** | --- ## 2. ν˜„ν–‰ μ•„ν‚€ν…μ²˜ μ‹€μΈ‘ 및 기술적 진단 (Ground Truth) ### 2.1 μ œμ–΄ 경둜 μƒμ˜ MQTT μ˜μ‘΄λ„ μ‹€μΈ‘ - `run_loop.sh` (899쀄, 메인 μ˜€μΌ€μŠ€νŠΈλ ˆμ΄ν„°) λ‚΄ MQTT 직접 μ°Έμ‘°λŠ” `:889`의 μž„μ‹œ κ΅¬λ…μž 둜그 파일 μ‚­μ œ 1κ±΄λΏμž…λ‹ˆλ‹€. - μž‘μ—… μ™„λ£Œ κ°μ§€λŠ” 11개 호좜 지점(전체 12개 μ°Έμ‘°) 전체가 `wait_for_job()` ν•¨μˆ˜λ₯Ό 톡해 `.mam/jobs/.json` 파일의 `status` ν•„λ“œλ₯Ό 3초 κ°„κ²©μœΌλ‘œ κ²€μ‚¬ν•©λ‹ˆλ‹€. - λ”°λΌμ„œ λΈŒλ‘œμ»€κ°€ λ‹€μš΄λ˜μ–΄λ„ μ œμ–΄ 평면 μžμ²΄λŠ” λ…λ¦½μ μœΌλ‘œ μ™„μ£Όν•  수 μžˆλŠ” κ΅¬μ‘°μž…λ‹ˆλ‹€. ### 2.2 paho-mqtt 결합도 (Blast Radius) - `import paho`λŠ” `mqtt_common.py:32` 단 1곳에 μΊ‘μŠν™”λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. - κ·ΈλŸ¬λ‚˜ `make_client()`κ°€ raw `mqtt.Client` μΈμŠ€ν„΄μŠ€λ₯Ό λ°˜ν™˜ν•˜μ—¬ λ‹€μŒ 4개 μ§€μ μ—μ„œ κ΅¬λ™λ©λ‹ˆλ‹€: 1. `mqtt_common.py:250-276` (`make_client`) 2. `publish_event.py:102-122` (λ°œν–‰ 및 ACK λŒ€κΈ°) 3. `job_subscriber.py:172-251` (이벀트 νμž‰ 및 ꡬ독) 4. `reconcile.sh:245-292` (λ‚΄μž₯ python 이벀트 μˆ˜μ‹ ) --- ## 3. μ½”λ“œλ² μ΄μŠ€ 잠볡 결함 뢄석 (F-1 ~ F-5) 브둜컀 μ œν’ˆ 선택과 λ¬΄κ΄€ν•˜κ²Œ ν˜„ν–‰ μ½”λ“œμ— μž λ³΅ν•΄ μžˆλŠ” 5κ°€μ§€ ꡬ쑰적 결함이 λ°œκ΅΄λ˜μ—ˆμŠ΅λ‹ˆλ‹€. ``` [발꡴된 결함 체인] F-1: publish μ‹€νŒ¨ μ‹œ return 2 ──> λ ˆμ§€μŠ€νŠΈλ¦¬ μƒνƒœ 동기화 λˆ„λ½ ──> run_loop 3900초(65λΆ„) μ •μ§€ F-4: subscriber 미포착 μ˜ˆμ™Έ rc=1 ──> loop/discuss κ²½λ‘œμ—μ„œ job_status="error" μ˜€νŒμ • F-2/F-3: μ „μ—­ ν† ν”½ + auth_token 쑰건뢀 ──> μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 격리 및 HMAC 검증 μ‚¬κ°μ§€λŒ€ (A-2) F-5: λ§€ μ‹€ν–‰ 랜덀 client_id ──> λ¬Έμ„œκ°€ μ£Όμž₯ν•˜λŠ” durable session ꡬ성 λΆˆκ°€ ``` ### 3.1 F-1 (Critical): λ°œν–‰ μ‹€νŒ¨ μ‹œ λ ˆμ§€μŠ€νŠΈλ¦¬ κ°±μ‹  λˆ„λ½ (65λΆ„ 루프 μ •μ§€) - `publish_event.py:195-199`μ—μ„œ 브둜컀 λ„€νŠΈμ›Œν¬ 였λ₯˜ λ°œμƒ μ‹œ `return 2`둜 μ‘°κΈ° μ’…λ£Œλ©λ‹ˆλ‹€. - 이둜 인해 λ’€λ”°λ₯΄λŠ” `append_event`, `registry.append_event`, `update_job_status(status=completed)`κ°€ μ‹€ν–‰λ˜μ§€ λͺ»ν•©λ‹ˆλ‹€. - `wait_for_job`은 `status=running` μƒνƒœμ—μ„œ `max_wait=3900s`λ₯Ό μ†Œμ§„ν•  λ•ŒκΉŒμ§€ **65λΆ„κ°„ μ •μ§€**ν•©λ‹ˆλ‹€. ### 3.2 F-2 (High): μ›Œν¬μŠ€νŽ˜μ΄μŠ€ μ§€λ¬Έ ν† ν”½ λ―Έλ°œν–‰ (A-2) - `reconcile.sh:236`은 μ§€λ¬Έ ν† ν”½(`mam//jobs/+/events`)을 κ΅¬λ…ν•˜μ§€λ§Œ, `mqtt_common.py:119`λŠ” μ „μ—­ ν† ν”½(`python/mqtt/jobs`)으둜만 λ°œν–‰ν•©λ‹ˆλ‹€. - μ›Œν¬μŠ€νŽ˜μ΄μŠ€ κ°„ λ©”μ‹œμ§€ 격리가 μ‹€μ§ˆμ μœΌλ‘œ λΉ„ν™œμ„±ν™”λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. ### 3.3 F-3 (High): HMAC 인증 쑰건뢀 κ³΅ν—ˆν™” (A-2) - `registry.py:75-79`λŠ” TLSλ‚˜ μ‚¬μš©μž 인증이 μΌœμ§„ λ³΄μ•ˆ 브둜컀 감지 μ‹œ `secrets.token_urlsafe(32)`λ₯Ό μžλ™ μƒμ„±ν•˜λ‚˜, κΈ°λ³Έ 곡개 브둜컀(λ˜λŠ” 평문 TCP 브둜컀) ν™˜κ²½μ—μ„œλŠ” 토큰이 λ°œκΈ‰λ˜μ§€ μ•Šμ•„ `auth_token=None`으둜 λ‚¨μŠ΅λ‹ˆλ‹€. - 이둜 인해 `verify_hmac`의 `if not auth_token: return True` λΆ„κΈ°κ°€ 무쑰건 참이 λ˜μ–΄ 곡개 브둜컀 ν™˜κ²½μ—μ„œ HMAC 검증이 무λ ₯ν™”λ©λ‹ˆλ‹€ (Track 2μ—μ„œ μ „ 브둜컀 λŒ€μƒ 무쑰건 λ°œκΈ‰μœΌλ‘œ 심측 λ°©μ–΄ 적용 ν•„μš”). ### 3.4 F-4 (Critical): `loop`/`discuss` μœ„μž„ 경둜의 μ˜€νŒμ • 결함 - `multi-agent-mux-delegate-job:331-341`μ—μ„œ `wait "$sub_pid"`의 `sub_rc`λ₯Ό 직접 `job_status`둜 λ§€ν•‘(`rc=1` -> `job_status="error"`). - 브둜컀 μ—°κ²° μ‹€νŒ¨ μ‹œ `job_subscriber.py`κ°€ 미포착 μ˜ˆμ™Έλ‘œ `rc=1`을 λ‚΄λ―€λ‘œ, **브둜컀 접속 μ‹€νŒ¨κ°€ μž‘μ—… μ—λŸ¬λ‘œ λ‘”κ°‘**ν•©λ‹ˆλ‹€. ### 3.5 F-5 (Medium): μ˜μ† μ„Έμ…˜(Durable Session) ꡬ성 λΆˆκ°€ - `make_client()`κ°€ λ§€ μ‹€ν–‰λ§ˆλ‹€ `uuid.uuid4().hex[:8]`둜 랜덀 `client_id`λ₯Ό μƒμ„±ν•˜λ―€λ‘œ, λΈŒλ‘œμ»€κ°€ μž¬μ—°κ²° μ„Έμ…˜μ„ 식별할 수 μ—†μŠ΅λ‹ˆλ‹€. --- ## 4. 리뷰 및 μ±Œλ¦°μ§€ 검증 (Challenge Resolution) ### 4.1 C1 μ±Œλ¦°μ§€ 뢄석 및 νŒμ • Reviewer (`agy`)κ°€ μ œκΈ°ν•œ `job_subscriber.py`의 μ œμ–΄ 경둜 λΈ”λ‘œν‚Ή 및 λ””μŠ€ν¬ 폴백 λˆ„λ½ 지적을 μ‹€μΈ‘ κ²€μ¦ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 1. **C1-a (μœ„μž„ λŒ€κΈ° 경둜 μ‹€μž¬)**: `multi-agent-mux-delegate-job:227`에 `wait "$sub_pid"`κ°€ μ‘΄μž¬ν•˜λ©°, `run_loop.sh`의 λͺ¨λ“  ν˜ΈμΆœλΆ€κ°€ `--type direct`둜 이 경둜λ₯Ό 톡과함을 확인 (수용). 2. **C1-b (λ””μŠ€ν¬ 폴백 λΆ€μž¬)**: `job_subscriber.py`λŠ” 였직 `watcher.events.get()`만 λŒ€κΈ°ν•˜λ―€λ‘œ 브둜컀 λ‹¨μ ˆ μ‹œ 이벀트λ₯Ό μˆ˜μ‹ ν•˜μ§€ λͺ»ν•¨ (수용). 3. **C1-c (λ©”μ»€λ‹ˆμ¦˜ 선후관계)**: C1은 F-1이 ν•΄κ²°λ˜μ–΄ λ””μŠ€ν¬μ— μ™„λ£Œ μƒνƒœκ°€ μ“°μ—¬μ§„ 이후에 λ“œλŸ¬λ‚˜λŠ” 연쇄 κ²°ν•¨μž„ (μ •μ • 및 반영). 4. **C1-d (μ§€μ—° μ‹œκ°„ μ‹€μΈ‘)**: 브둜컀 도달 λΆˆκ°€ μ‹œ κ΅¬λ…μžλŠ” 15~40초 λ‚΄ `rc=1`둜 μ‘°κΈ° μ’…λ£Œλ˜μ–΄ μ‹€μ œ μΆ”κ°€ λΈ”λ‘œν‚Ήμ€ 0μ΄ˆμž„ (μ§€μ—° 영ν–₯ 기각, κ·ΈλŸ¬λ‚˜ 감사 둜그 μ˜€μ—Ό 및 κ±°μ§“ μ‹€νŒ¨ νŒμ •μ˜ μ‹¬κ°μ„±μœΌλ‘œ 채택). 5. **C1-e (ν•΄κ²°μ±… 채택)**: `job_subscriber.py`의 λŒ€κΈ° 루프에 둜컬 λ””μŠ€ν¬(`load_job` / `read_logged_status`) 폴백을 λ„μž…ν•˜μ—¬ 브둜컀 λ‹¨μ ˆ μ‹œμ—λ„ μ¦‰μ‹œ 정상 μ’…λ£Œν•˜λ„λ‘ 보강. --- ## 5. 단계별 μ‹€ν–‰ κ³„νš (Actionable Roadmap) ``` [Track 0: 결함 ꡐ정] ──> [Track 1: nats-server 슀파이크] ──> [Track 2: A-2 λ³΄μ•ˆ/격리 ν•΄μ†Œ] ──> [Track 3: λ¬Έμ„œν™”] (F-1, C1, F-4 ν•΄κ²°) (S-1 ~ S-9 맀트릭슀 검증) (F-2, F-3, Token, ACL) (MESSAGING, VERSIONS) ``` ### 5.1 Track 0 β€” κ°€μš©μ„± 및 결함 ꡐ정 (μ΅œμš°μ„  과제, 브둜컀 무관) #### Step μˆœμ„œ μ˜μ‘΄μ„± (Strict Ordering) 1. **Step 1 (`publish_event.py`)**: λ°œν–‰ μ‹€νŒ¨ μ‹œμ—λ„ λ ˆμ§€μŠ€νŠΈλ¦¬ μƒνƒœ 동기화 및 감사 둜그 μž‘μ„±μ„ μ™„μˆ˜ν•˜κ³  `return 2` λ°˜ν™˜. 2. **Step 2 (`job_subscriber.py`)**: `queue.Empty` μ‹œ 3초 μŠ€λ‘œν‹€λ‘œ λ””μŠ€ν¬ 터미널 μƒνƒœλ₯Ό ν™•μΈν•˜μ—¬ `source: disk-fallback` ν•©μ„± 이벀트 좜λ ₯ ν›„ `rc=0` μ‘°κΈ° μ’…λ£Œ. 3. **Step 3 (`multi-agent-mux-delegate-job`)**: 인프라 μ˜ˆμ™Έμ— μ „μš© `rc=3`을 λΆ€μ—¬ν•˜κ³  `job_status="broker_unavailable"` λΆ„κΈ° 처리. #### νšŒκ·€ κ°€λ“œ 맀트릭슀 (11μ’… μ‹ μ„€ β€” G-1 ~ G-11, λͺ©ν‘œ 287/287 PASS) - **G-1**: 브둜컀 도달 λΆˆκ°€ λ°œν–‰ μ‹œ `rc=2`μ΄λ©΄μ„œ λ ˆμ§€μŠ€νŠΈλ¦¬ `status=completed` 확인. - **G-2**: 감사 λ‘œκ·Έμ— `published: false` 및 `publish_error` ν•„λ“œ 기둝 확인. - **G-3**: 정상 브둜컀 λ°œν–‰ μ‹œ `rc=0` 및 `published: true` λ¬΄νšŒκ·€ 확인. - **G-4**: λ°œν–‰ μ‹€νŒ¨ μ‹œ 단쑰 `last_seq` 증가 및 후속 λ°œν–‰ seq 보쑴 확인. - **G-5**: λ””μŠ€ν¬ `status=completed` μ„ μž‘μ„± μ‹œ 브둜컀 λ‹€μš΄ μƒνƒœμ—μ„œλ„ `job_subscriber.py`κ°€ 3초 λ‚΄ `rc=0` μ’…λ£Œ. - **G-6**: λ””μŠ€ν¬ 폴백 μ’…λ£Œ μ‹œ stdout에 `disk-fallback` λͺ…μ‹œ 확인. - **G-7**: λ””μŠ€ν¬ `status=error` μ‹œ 폴백 `rc=1` λ°˜ν™˜ 확인. - **G-8**: 닀쀑 작 κ°μ‹œ μ‹œ 전체 μ™„λ£Œ μ „κΉŒμ§€ μ‘°κΈ° μ’…λ£Œ λ°©μ§€. - **G-9**: λ””μŠ€ν¬ 터미널 λΆ€μž¬ + 브둜컀 μ‹€νŒ¨ μ‹œ `rc=3` λ°˜ν™˜ 확인 (F-4 λ°©μ–΄). - **G-10**: `loop` μœ„μž„ κ²½λ‘œμ—μ„œ `rc=3` μˆ˜μ‹  μ‹œ `job_status`κ°€ `"error"`둜 μ˜€νŒλ˜μ§€ μ•ŠμŒμ„ 확인. - **G-11**: `registry.register_job()` 호좜 μ‹œ `auth_token`이 항상 λΉ„μ–΄μžˆμ§€ μ•Šκ²Œ 생성됨을 단언 (`secrets.token_urlsafe(32)` μœ μ§€). ### 5.2 Track 1 β€” `nats-server` 슀파이크 검증 맀트릭슀 (S-1 ~ S-9) 격리 클둠(`$SCRATCH/nats-spike`)μ—μ„œ 검증 μˆ˜ν–‰: - **S-1**: `nats-server -js` MQTT λ¦¬μŠ€λ„ˆ κΈ°λ³Έ ꡬ동 및 `started/progress/completed` λ°œν–‰ 수용 (`rc=0`). - **S-2**: paho-mqtt 2.x `CallbackAPIVersion.VERSION2` CONNACK ν˜Έν™˜μ„± 검증. - **S-3 (핡심 κ΄€λ¬Έ)**: **Retained terminal event 정상 전달 검증** (λŠ¦μ€ κ΅¬λ…μžμ˜ μ¦‰μ‹œ μ΅œμ’… μƒνƒœ μˆ˜μ‹ ). *μ‹€νŒ¨ μ‹œ mosquitto둜 νšŒκ·€*. - **S-4**: QoS 1 `wait_for_publish` ACK λ™μž‘ 검증. - **S-5**: μ™€μΌλ“œμΉ΄λ“œ ν† ν”½(`mam//jobs/+/events`) ꡬ독 및 λΌμš°νŒ… 검증. - **S-6**: TLS μ•”ν˜Έν™” 및 μœ μ € 인증 μ ‘κ·Ό μ œμ–΄ 검증. - **S-7**: Subject/Topic 레벨 κΆŒν•œ 뢄리(Publisher write-only / Subscriber read-only) 검증. - **S-8**: 전체 287건 νšŒκ·€ ν…ŒμŠ€νŠΈ 100% PASS 검증. - **S-9**: Track 0 λ””μŠ€ν¬ 폴백이 `nats-server` μž₯μ•  μƒν™©μ—μ„œλ„ 정상 λ™μž‘ν•¨μ„ 톡합 검증. ### 5.3 Track 2 β€” A-2 λ³΄μ•ˆ 및 μ›Œν¬μŠ€νŽ˜μ΄μŠ€ 격리 ν•΄μ†Œ 1. **F-3 ν•΄μ†Œ**: `registry.register_job()`μ—μ„œ 브둜컀 μ„€μ •(TLS/인증 유무)κ³Ό λ¬΄κ΄€ν•˜κ²Œ `secrets.token_urlsafe(32)` 기반 `auth_token`을 **무쑰건 항상 λ°œκΈ‰**. 2. **F-2 ν•΄μ†Œ**: `DEFAULT_TOPIC_ROOT`λ₯Ό `mam//jobs`둜 μ „ν™˜. λ°œν–‰μΈ‘ μ „ν™˜ ν›„ `reconcile.sh`의 λ ˆκ±°μ‹œ ꡬ독 단계적 제거. 3. 배포 섀정에 nkeys 기반 계정 뢄리 적용. ### 5.4 Track 3 β€” λ¬Έμ„œ 및 μ„€μ • 동기화 - `MESSAGING.md`: 브둜컀 사양을 `nats-server`둜 κ°±μ‹ , F-1/C1 ν•΄μ†Œ 기둝, F-5 싀츑에 맞좘 μ˜μ† μ„Έμ…˜ μ„€λͺ… μ •μ •. - `IMPROVEMENTS.md` & `VERSIONS.md`: A-2 μ™„λ£Œ μ „ν™˜, F-1/F-4/F-5 백둜그 이λ ₯ 반영. - `.mam.env`: `nats-server` 포트(1883/8883) 및 인증 ν…œν”Œλ¦Ώ κ°±μ‹ . --- ## 6. λΉ„-λͺ©ν‘œ (Explicit Non-Goals) 1. ❌ **`nats-py` 라이브러리 λ„μž… 및 ν΄λΌμ΄μ–ΈνŠΈ 비동기 μž¬μž‘μ„±**: λΆˆν•„μš”ν•œ λ³΅μž‘λ„ 및 μž₯μ•  유발. 2. ❌ **`.mam/jobs/*.json`의 JetStream KV λŒ€μ²΄**: νŒŒμΌμ‹œμŠ€ν…œ 폴링 μ œμ–΄ 계약을 ν›Όμ†ν•˜λ―€λ‘œ μƒνƒœ 계측 λ³€κ²½ μ œμ™Έ. 3. ❌ **Durable Session κ°•μ œ λ„μž…μ„ μœ„ν•œ `client_id` κ³ μ •**: λ™μ‹œμ„± 좩돌 μœ„ν—˜μ΄ 크며, Track 0 λ””μŠ€ν¬ 폴백이 동일 볡원λ ₯을 λ¬΄λΉ„μš©μœΌλ‘œ μ œκ³΅ν•¨. 4. ❌ **`requirements.txt` λ‚΄ `paho-mqtt>=2.0.0` 제거**: ν˜„ν–‰ 쒅속성 μœ μ§€. --- ## 7. κ²°λ‘  MAM ν”„λ ˆμž„μ›Œν¬μ˜ λ©”μ‹œμ§• λ°±ν”Œλ ˆμΈμ€ **ν΄λΌμ΄μ–ΈνŠΈ ν”„λ‘œν† μ½œ(MQTT)을 100% λ³΄μ‘΄ν•œ μƒνƒœμ—μ„œ `nats-server`λ₯Ό μ „μš© 브둜컀둜 채택(Option C)**ν•˜λŠ” 것이 κΈ°μˆ μ Β·μš΄μ˜μ Β·λ³΄μ•ˆμ  μ΅œμ ν•΄μž…λ‹ˆλ‹€. μ„ ν–‰ ν•„μˆ˜ 과제인 **Track 0(F-1 + C1 + F-4 κ°€μš©μ„± 결함 ꡐ정)**을 μš°μ„  μ™„μˆ˜ν•œ ν›„, 슀파이크 검증(Track 1) 및 A-2 λ³΄μ•ˆ κ°•ν™”(Track 2)λ₯Ό 순차 μ „κ°œν•©λ‹ˆλ‹€.