Compare commits

..
5 Commits
Author SHA1 Message Date
Godopu f98b9582c7 docs: clean up root markdown files and synchronize with v4.4.0 standards
- Relocate legacy implementation_plan.md to docs/contracts/nats-backplane/implementation_plan.md
- Synchronize root documentation (README, README.ko, BOOTSTRAP, BOOTSTRAP.ko, AGENTS, MESSAGING, IMPROVEMENTS) to latest v4.4.0 standards
- Consolidate IMPROVEMENTS.md to single source of truth (5 open / 31 completed tasks 1:1 matching section headers)
- Archive unanimous PASS review reports from Claude, Grok, Codex, and OpenCode along with Plan Rev.2
2026-09-08 08:02:37 +09:00
Godopu 07cae71667 merge: release/v4.4.0 (Framework and 8 skills lockstep release v4.4.0) 2026-09-07 16:08:01 +09:00
Godopu 525764aaa3 docs(reports): archive v4.4.0 unanimous pass review reports (d05e8e15, 78443ebe, e5c9a052) 2026-09-07 16:07:43 +09:00
GodopuandClaude Opus 5 387479732e release(v4.4.0): bump framework and eight skills to 4.4.0 in lockstep
Issue #5 (Python core migration, CAS state transitions, shadow watcher,
auto-completion gate, eager-import immutable runtime, B-13 freeze removal)
is complete and merged to main. This stamps the release.

SemVer: MINOR, not MAJOR. The change is large but breaks nothing. Across the
whole Issue #5 range there are zero file deletions and zero renames, the event
wire schema stays at SCHEMA_VERSION 1, all four literal script paths survive as
compatibility shims, the 968-line legacy shell loop is still in run_loop.sh,
and every default change reverts through a single environment variable
(MAM_DELEGATION_PY / MAM_ENGINE_CAS / MAM_LOOP_PY / MAM_LOOP_FREEZE). The
riskiest new feature, auto-completion, ships default-off. No operator has
anything to migrate, which is the decisive reason not to call it 5.0.0. The
reasoning is recorded in the VERSIONS.md release notes, not just here.

Close a gap in the lockstep guard. lib.sh exports MAM_VERSION and eager_load()
refuses to start the loop when it disagrees with FRAMEWORK_VERSION, so eager.py
is a load-bearing fourth leg — but test_version_consistency.py only checked
three, and the sole check on eager.py was a hardcoded literal in the phase 4
test that a release bump has to edit anyway. The lockstep test now covers
eager.py, a new test pins the fail-closed gate itself, and the phase 4 test no
longer carries a version literal.

Fix a latent test-isolation defect the bump exposed. The first full run failed
four tests with "MAM_VERSION mismatch: expected 4.4.0, got 4.3.0 in
environment" — 4.3.0 was not in the tree, it was inherited from the shell that
launched pytest and had sourced the pre-bump lib.sh. Those tests were measuring
the runner's shell rather than the tree under test, and only passed until now
because the two values always happened to agree. A session-scoped fixture drops
the ambient value. Production is unaffected: run_loop.sh:17 sources lib.sh
before anything else and lib.sh re-exports MAM_VERSION unconditionally, so a
stale inherited value is always overwritten before Python starts.

Full suite: 750 passed in 912.50s, 0 failed, 0 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UrDNJkHmm18uu7n7JwV5Qd
2026-09-07 15:55:26 +09:00
Godopu b347efd760 merge: refactor branch (Issue #5 Python core migration & robust orchestration loop) 2026-09-07 15:14:03 +09:00
33 changed files with 764 additions and 152 deletions

No files matched your search

@@ -0,0 +1,138 @@
# 📑 Implementation Plan Rev.2 — Workspace Root Markdown 정리 및 최신화 (Job baea3f7e, 원본 45bd8635)
- **역할**: Planner (`planner-reviewer-claude-01`)
- **기준 커밋**: `07cae71` (`main`, v4.4.0, 전체 스위트 750 passed / 문서 바인딩 4모듈 49 passed)
- **개정 사유**: Creator(`creator-agy-01`, Job `87aa5b5a`) 이의제기 3건. **3건 모두 실측으로 사실 확인되어 전부 수용**하고, 검증 과정에서 Planner 자신의 Rev.1 오류 1건(D-1/Phase B-1 "잔재에 고유 내용 없음")을 추가로 발견하여 함께 정정한다.
- **Rev.1 대비 변경 범위**: §1 D-1, Phase A-2, Phase B 전면, Phase D-1, 게이트 4. 나머지 Phase C/E/F/G와 게이트 1·2·3·5·6은 Rev.1 그대로 유효(본문 하단에 원문 유지).
---
## 0. 이의제기 판정 (Adjudication of Challenge)
| # | Creator 주장 | Planner 실측 | 판정 |
|---|---|---|---|
| C-1 | 완료 과제는 §5 단일 섹션이 아니라 §2(5건)·§3(2건)·§5(24블록)에 분산되어 있고, 헤더 "30건"은 전역 합계이며 Rev.1 Phase B-2 지시("§5의 `###` 수로 재계산해 헤더와 일치")는 실행 불가 | `awk`로 전 `###` 블록을 섹션별로 열거: §2 완료 5(B-21,B-20,B-19,B-14,B-15), §3 완료 2(O-6,A-4), §5 24블록(O-2 중복 2회), 헤더 ID 정확히 30개. **주장 사실.** 단 Creator의 산식 "5+2+23=30"은 우연한 일치다. ID↔블록이 1:1이 아니기 때문이다(아래 §1-A) | **수용** — 방안 A 채택, 단 계수 규칙을 블록 기준으로 명문화 |
| C-2 | 이관되는 `implementation_plan.md` §7 표의 `[.mam.env](.mam.env)` 링크는 gitignored 파일(`test_d29`가 추적 금지)이라 클린 체크아웃에서 게이트 4 `test -e`가 실패 | `.gitignore:24` `.mam.env`, `git ls-files`에 `.mam.env.example`만 추적, `tests/test_deploy_freshness.py:687 test_d29_env_secrets_never_tracked` 존재, 원문 151행 링크 확인. **주장 사실.** | **수용** — 링크 대상을 `.mam.env.example`로, 게이트 4에 ignore 예외 규칙 추가 |
| C-3 | Phase D-1 트리 추가 목록에 `IMPROVEMENTS.md` 누락, 영문 README 트리에 `README.ko.md`/`BOOTSTRAP.ko.md` 부재, 한국어 README에는 `BOOTSTRAP.ko.md`만 존재 → "줄수 일치" 게이트 기준 불명확 | `README.md:188-190` 3개 루트 md, `README.ko.md:170-173` 4개 루트 md. **주장 사실.** | **수용** — 루트 md 8개 전부를 양 README 트리에 동일 순서로 명시 |
부수 정정: Creator 보고서의 "450줄"은 `wc -l` 기준 449줄(마지막 줄 개행 있음)이나 판단에 영향 없음.
---
## 1. 정정된 결함 진단
### 1-A. `IMPROVEMENTS.md` 완료 과제 원장 (Planner 실측, 정본)
헤더 ID 30개와 완료 `###` 블록 31개(잔재 제외)의 대응은 다음과 같다. 이 표가 Phase B의 유일한 기준이다.
| 헤더 ID | 현재 블록 위치 | 비고 |
|---|---|---|
| B-21, B-20, B-19, B-14, B-15 | §2 (30/44/54/64/68행) | 미해결 섹션에 완료 항목 혼재 |
| O-6, A-4 | §3 (99/106행) | A-4 블록은 Rev.2 어댑터 계층 45행 분량 |
| B-9, B-13, B-10, B-5, C-6, P2-2, P2-1, B-4, O-3, A-1, A-3, C-2, A-5, B-1, B-3, C-1, O-1, Herdr-0.8.0-Compat-SanitizeHash | §5 | 1:1 대응 |
| B-7 | §5 `P0-1 (B-7)` (253행) | 키 표기 상이 |
| O-4-OrcOnboard | §5 `multi-agent-mux-orc-onboard` (242행) | 키 표기 상이 |
| **O-2** | §5 **2블록**: `P0-2 (O-2)` 247행(Rev.1: pid+lstart 마커, 46/46) + `O-2` 273행(Rev.2: 하드링크 원자 쓰기, steal_lock, 204/204) | **동일 과제의 연속 개정** → 병합 대상 |
| **C-3b** | 독립 블록 없음. §5 `P3-1 (A-4 Phase 2 / Option B / C-3b / M2~M7)` 224행 제목에 포함 | P3-1 블록이 A-4(2차)와 C-3b를 동시에 담음 |
| **B-8** | **독립 블록 없음.** §6.2 표 367행 `P1-2(과거) B-8 … (✅ 완료 — tests/test_b8_send_keys_verification.py 1/1 PASS)`에만 존재 | `tests/test_b8_send_keys_verification.py` 실재 확인 |
| (헤더에 없음) | §5 `Rev.2 (b4a1d094)` 260행 세션 ID 자동 할당 | 헤더 ID 목록에서 누락된 블록 |
결론: "헤더 30 = §2 5 + §3 2 + §5 23"은 (O-2 중복 −1, C-3b 블록 없음 −1, B-8 블록 없음 −1, Rev.2 블록 ID 없음 +1, P3-1 별도 블록 +1)이 상쇄된 우연이다. Rev.2는 **"§5의 `###` 블록 1개 = 헤더 ID 1개"**를 강제하여 이 우연을 제거한다.
### 1-B. Rev.1 오류 정정 — 154~186행 잔재는 단순 삭제 불가
Rev.1 Phase B-1은 "앞쪽 사본이 최신 서술을 모두 포함(확인됨)"이라 했으나 **틀렸다**. 잔재 전용 토큰 20종을 실측했다: B-14 원 진단(`publish_event.py:195-199`, `wait_for_job()`, `max_wait=3900s`, `status=running`), B-15 원 진단(`job_subscriber.py:172-251`, `queue.Empty`, `idle_timeout`, `multi-agent-mux-delegate-job:331-341`, `wait "$sub_pid"`, `sub_rc`, `job_status="error"`, `job_status="broker_unavailable"`, `load_job`/`read_logged_status`, `source: disk-fallback`), O-5 배경(`nats-py` Option B 기각 사유). 앞쪽 B-14/B-15 블록(64~70행)은 각 2줄 요약뿐이다. B-16 블록은 양쪽 동일(잔재 고유 내용 없음). 따라서 잔재는 **병합 후 삭제**한다(Phase B-1).
---
## 2. 개정된 작업 계획 (변경된 Phase만 기술; 미기재 Phase는 Rev.1 원문 적용)
### Phase A-2 (개정) — 이관 파일 링크 규칙
- `git mv implementation_plan.md docs/contracts/nats-backplane/implementation_plan.md` 후 상대 링크를 `../../../` 접두로 승격하되, **§7 표의 `[.mam.env](.mam.env)`는 `[.mam.env (템플릿: .mam.env.example)](../../../.mam.env.example)`로 변경**한다. 이유: `.mam.env`는 gitignored(`.gitignore:24`)이며 `test_d29`가 추적을 금지하므로 클린 체크아웃에 존재하지 않는다.
- 같은 이유로 문서 내 `.mam.env`를 **파일 링크 없이 코드 스팬으로만** 언급하는 것은 허용한다(23행·122행은 링크가 아니므로 변경 불필요).
### Phase B (전면 개정) — `IMPROVEMENTS.md` 단일 원장화 (방안 A 채택)
작업 순서를 엄수한다. 행 번호는 착수 시점 기준이며 이후 단계는 **헤더 문자열로 앵커링**한다.
1. **잔재 병합 후 삭제** (1-B 반영)
- 잔재 `### **B-14 (F-1 / P1)…`(156행)의 `현상`·`파급 효과` 불릿을 앞쪽 `### **B-14 (✅ 완료 — F-1 / P1)…` 블록의 `현상` 불릿 **아래에 "원 진단" 불릿으로 추가**(내용 원문 유지, 시제만 과거형 허용).
- 잔재 B-15(161행)의 `현상` 1·2항과 `파급 효과`를 앞쪽 B-15 블록에 동일 방식으로 추가.
- 잔재 O-5(179행)의 `현상` 문장 중 "`nats-py` 클라이언트 재작성(Option B)을 배제하고" 구절을 앞쪽 O-5 `현상`에 삽입.
- 잔재 B-16(170행)은 앞쪽과 동일하므로 추가 없음.
- 그 다음 두 번째 `## 2. 🟠 …(Edge-case Bugs — 3건)`부터 두 번째 `## 3.` 블록 끝(`## 4. ⚪ 레거시 잔재` 직전 구분선)까지 삭제.
- **검증**: 위 20종 토큰 전부가 삭제 후 파일에 여전히 존재(`grep -cF`로 각 1 이상), `grep -c '^## 2\.'`=1, `grep -c '^## 3\.'`=1.
2. **완료 블록 §5 이관** (방안 A)
- §2의 B-21, B-20, B-19, B-14, B-15 블록과 §3의 O-6, A-4 블록을 **현재 등장 순서 그대로** `## 5. 🎉 완료된 과제` 제목 바로 아래(기존 B-9 앞)에 삽입. 블록 본문은 한 글자도 바꾸지 않는다(제목의 `(✅ 완료 — …)` 표기 포함).
- 이관 후 §2에는 B-16, B-17, B-18만, §3에는 O-5만 남는다.
3. **O-2 중복 병합**
- `### **O-2: 동일 워크스페이스 … (Race-Free Mutex & Ownership)**`(Rev.2, 최종본)을 유지하고, `### **P0-2 (O-2): …**` 블록은 제목을 제거한 뒤 그 불릿 4개를 O-2 블록 **끝에 `- **Rev.1 (P0-2) 선행 조치**:` 하위 불릿으로** 편입한다. 제목은 `### **O-2 (P0-2): …**`로 갱신하여 키 대응을 유지.
4. **B-8 블록 신설** (원장 완결성)
- `## 5` 말미(Herdr-0.8.0 블록 뒤)에 `### **B-8 (P1-2): agy 주입 시 \`return 0\` 우회 제거 및 제출 검증 루프 이관** — ✅ 완료` 블록을 추가하고, 불릿 1개만 둔다: §6.2 표 367행의 서술을 그대로 옮기고 근거로 `tests/test_b8_send_keys_verification.py` (1/1 PASS)를 명기한다. **새 사실을 지어내지 않는다** — 표 367행 밖의 내용은 쓰지 않는다.
5. **섹션 헤더 카운트 확정** (계수 규칙: 해당 섹션 하위 `###` 블록 수)
- `## 1. 🔴 아키텍처 결함 (Architecture Flaws — 1건)` (A-2)
- `## 2. 🟠 엣지 케이스 및 런타임 버그 (Edge-case Bugs — 3건)` (B-16, B-17, B-18)
- `## 3. 🟡 오케스트레이션 최적화 과제 (Orchestration Optimizations — 1건)` (O-5)
- `## 4. ⚪ 레거시 잔재 및 죽은 코드 (Legacy Remnants — 0건 — 전원 완료)` (변경 없음)
- `## 5. 🎉 완료된 과제 (Completed Tasks — 31건)` = 기존 24 − 1(O-2 병합) + 7(이관) + 1(B-8) = **31**
6. **헤더 요약(3~6행) 동기화**
- `최종 갱신일`: `2026-09-07 (IMPROVEMENTS.md 단일 원장화: §2/§3 완료 항목 §5 이관, 머지 잔재 병합 제거, v4.1.x~v4.4.0 완료 사항 반영)`.
- `총 추적 미해결 과제`: **5건** 문구 유지(A-2 / B-16, B-17, B-18 / O-5).
- `완료된 과제`: **31건**으로 갱신하고 괄호 목록을 **§5 블록 키를 등장 순서대로 나열한 31개**로 교체: `B-21, B-20, B-19, B-14, B-15, O-6, A-4, B-9, B-13, B-10, B-5, C-6, P3-1-A4Phase2-C3b, P2-2-C3a-C4-LegacyCleanup, P2-1-DelegateJobSafe-TrapFix, O-4-OrcOnboard, O-2-P0-2, P0-1-B-7, Rev.2-b4a1d094-SessionIdPinning, B-4, O-3, A-1, A-3, C-2, A-5, B-1, B-3, C-1, O-1, Herdr-0.8.0-Compat-SanitizeHash, B-8`. (기존 `B-7`, `C-3b`, `O-2`, `A-4`는 위 키 안에 포함되어 유실되지 않는다.)
7. **v4.1.x~v4.4.0 반영** (Rev.1 B-3 유지, 위치만 명확화)
- 기존 `### **B-13 (Stage 2)…` 블록 끝에 1불릿: "v4.4.0(Issue #5 Phase 4)에서 freeze 스냅샷을 기본 경로에서 철거, `MAM_LOOP_FREEZE=1` 롤백 스위치만 잔존 (`docs/contracts/issue-5/phase4-freeze-removal.md`)".
- 신규 블록은 추가하지 않는다(codex/grok/opencode 통합, Python 코어 마이그레이션은 `VERSIONS.md`가 정본이며, 백로그 ID가 부여된 과제가 아니므로 §5에 등재하지 않는다). 대신 `📌 개요` 절 끝에 1문장: "v4.1.0 이후 릴리스 단위 변경 이력은 `VERSIONS.md`를 정본으로 하며 본 백로그는 ID가 부여된 과제만 추적한다."
8. **보존 필수 문자열**: `### **O-1: 타당하지 않은 리뷰 피드백 거부/반론 프로토콜 미지원 (Rebuttal Protocol)**` 제목과 본문은 변경 금지 (`test_o1_rebuttal.py::test_v10`).
- **Phase B 검증 스크립트 (Creator 실행 필수)**:
```bash
f=IMPROVEMENTS.md
test "$(grep -c '^## 2\.' $f)" = 1 && test "$(grep -c '^## 3\.' $f)" = 1
# §5 블록 수 = 31, 헤더 괄호 ID 수 = 31
awk '/^## 5\./{s=1;next} /^## 6\./{s=0} s&&/^### /{n++} END{print n}' $f # → 31
sed -n '6p' $f | grep -o -E '\(B-21.*\)' | tr ',' '\n' | grep -c . # → 31
# 각 완료 ID의 ### 제목이 정확히 1회
for id in B-21 B-20 B-19 B-14 B-15 O-6 O-2 B-8 A-4; do test "$(grep -c "^### \*\*$id[ :(]" $f)" = 1 || echo "DUP/MISSING $id"; done
# §2·§3에 ✅ 완료 블록 잔존 금지
awk '/^## 2\./{s=1} /^## 4\./{s=0} s&&/^### .*✅/{print "LEAK: "$0}' $f
.venv/bin/python -m pytest -q tests/test_o1_rebuttal.py
```
### Phase D-1 (개정) — README 트리의 루트 마크다운 표기 기준
- 양 README의 `text` 트리 **루트 레벨 마크다운 항목은 다음 8개를 알파벳 순으로 전부** 기재한다(언어별 미러 포함, 기존 3~4개 → 8개): `AGENTS.md`, `BOOTSTRAP.ko.md`, `BOOTSTRAP.md`, `IMPROVEMENTS.md`, `MESSAGING.md`, `README.ko.md`, `README.md`, `VERSIONS.md`. 설명 문구만 언어별로 다르다.
- 디렉터리 항목 추가 목록은 Rev.1 D-1 그대로(`lib_py/` 3패키지, `scripts/` shim 재표기, `docs/` 4항목, `nats-docker/`, `tests/`).
- **검증**: 두 파일의 트리 블록에서 `├──|└──`로 시작하는 줄 수가 동일하고, 루트 md 8개 문자열이 양쪽에 각 1회 존재.
### 게이트 4 (개정) — 깨진 상대 링크 0건
- 검사 대상: 루트 8개 + 이관 문서. 링크 경로 추출 후 `test -e`; **단 `git check-ignore -q <path>`가 참인 경로는 검사에서 제외**하지 않고 **오류로 처리**한다(추적되지 않는 파일로의 링크는 문서 결함이므로 Phase A-2 규칙에 따라 링크 자체를 제거/대체해야 한다). 즉 게이트 4 = "모든 링크 대상이 존재하고 git 추적 대상이다".
```bash
for f in README.md README.ko.md BOOTSTRAP.md BOOTSTRAP.ko.md MESSAGING.md IMPROVEMENTS.md AGENTS.md VERSIONS.md docs/contracts/nats-backplane/implementation_plan.md; do
d=$(dirname "$f")
grep -o -E '\]\(([^)#]+)(#[^)]*)?\)' "$f" | sed -E 's/^\]\(//; s/#.*//; s/\)$//' | grep -v -E '^(https?:|mailto:|file:)' | while read -r p; do
t="$d/$p"; { test -e "$t" && git ls-files --error-unmatch "$t" >/dev/null 2>&1; } || echo "BROKEN/UNTRACKED: $f -> $p"
done
done
```
- 주의: `IMPROVEMENTS.md` 248행 등에 `file:///Users/...` 절대 링크가 존재한다. 본 게이트에서는 제외(`file:` 필터)하되, Phase B-3 O-2 병합 시 해당 불릿의 `file://` 링크는 상대 경로 `.agents/skills/multi-agent-mux-loop/scripts/loop_lock.sh`로 교체한다(같은 불릿을 만지는 김에 최소 수정).
---
## 3. 최종 검증 게이트 (Rev.2 확정본)
1. 루트 마크다운 8개, `implementation_plan.md`는 `docs/contracts/nats-backplane/`.
2. `pytest -q tests/test_deploy_layout.py tests/test_o1_rebuttal.py tests/test_deploy_freshness.py tests/test_version_consistency.py` → 49 passed.
3. `pytest -q tests/` → 750 passed.
4. 위 개정 게이트 4 스크립트 출력 0줄.
5. `git diff --stat`에 `.agents/skills/**`, `tests/**`, `deploy/**` 변경 없음.
6. `MAM_INSTALL_DOCS=minimal|full` 설치 시 루트 문서 1개/4개.
7. **(신설)** Phase B 검증 스크립트 전 항목 통과: §5 블록 31 = 헤더 ID 31, §2/§3 완료 블록 누출 0, 잔재 토큰 20종 보존.
## 4. 범위 외 (Rev.1 §4 유지) + 추가
- `nats-docker/PRIVATE_SERVER.md:5` 깨진 링크 — 서브모듈 별도 커밋.
- 미해결 5건(A-2, B-16, B-17, B-18, O-5)의 코드 대조 재판정 — 별도 리뷰 잡. 특히 B-17은 `MESSAGING.md:310`이 "구현됨"으로 서술하고 있어 상태 불일치 의심이 있으나 **본 작업에서는 손대지 않는다**(코드 확인 없이 완료로 옮기면 원장 오염).
- README 배지 5번째 lockstep 레그 — 별도 잡.
## 5. 리스크
- Phase B는 이동·병합이 많아 유실 위험이 가장 크다. 반드시 **B-1 → B-2 → B-3 → B-4 순서**로 각 단계 후 검증 스크립트를 실행하고, 최종적으로 `git diff --stat IMPROVEMENTS.md`의 삭제 줄 수가 (잔재 33줄 + P0-2 제목 1줄 + 이관에 따른 이동분) 범위 안인지 확인한다. 이관은 `git diff`에서 삭제+추가로 보이므로 `git diff --color-moved=plain`으로 이동임을 확인한다.
---
## 부록. Rev.1 원문 중 유효 유지 항목 (변경 없음)
- §0 실측 인벤토리 표 및 KEEP/이관 판정 9건.
- §1 D-2(MESSAGING lib_py 미반영), D-3(README 트리), D-4(BOOTSTRAP §1), D-5(implementation_plan 이관), D-6(AGENTS §5).
- Phase A-1/A-3/A-4, Phase C 전체, Phase D-2~D-4, Phase E, Phase F, Phase G.
@@ -0,0 +1,70 @@
# Review Report — Job d05e8e15 (v4.4.0 릴리스 락스텝 갱신)
- Reviewer: planner-reviewer-claude-01
- 리뷰 범위: `b347efd..HEAD` (단일 커밋 `3874797` "release(v4.4.0)"), 21 파일 +160/−40
- 범위 고정: 브리프 내장 diff(39,725 B) vs `git diff b347efd..HEAD -- . ':(exclude).agents/reports'`(39,724 B) — 말미 개행 1바이트 외 **바이트 동일**. `.agents/reports` 하위 변경 없음.
- 검증 환경: Python 3.9.6, `.venv`, 실제 리뷰어 셸의 ambient `MAM_VERSION=4.3.0` (이 커밋이 고친 격리 결함의 실전 재현 조건)
- 참고: 현재 체크아웃 브랜치는 `release/v4.4.0`이며 `main`은 아직 `b347efd`(릴리스 커밋 미포함). VERSIONS.md "기준 브랜치: main"은 병합 후 상태를 선기술한 것으로, 병합 시점에 사실이 된다.
## 1. SemVer 판정(MINOR `v4.4.0`) 근거 재검증
작업자의 "규모는 크지만 깨는 것이 없다" 주장을 항목별로 실 트리에서 재확인했다.
| 주장 | 검증 방법 | 결과 |
| :--- | :--- | :--- |
| Issue #5 전 구간 삭제·rename 0건 | `git diff --name-status fc0bd96..HEAD \| grep -v '^[AM]'` | 0건 ✅ |
| `SCHEMA_VERSION = 1` 불변 | `mqtt_common.py:135` | ✅ |
| `scripts/*.py` 4종 존속 | `ls multi-agent-mux-delegate-job/scripts/` | job_subscriber/mqtt_common/publish_event/registry ✅ |
| 롤백 env 4종 실재·기본값 | `lib.sh:1972,1989,2000` (`MAM_DELEGATION_PY:-1`), `engine.py:109` (`MAM_ENGINE_CAS` 기본 "1"), `run_loop.sh:122` (`MAM_LOOP_PY:-1`, `MAM_LOOP_FREEZE:-0`) | ✅ |
| 자동 완료 기본 비활성 | `loop/autocomplete.py:29,53` — `os.environ.get("MAM_AUTO_COMPLETE","0") == "1"` | ✅ |
| 레거시 셸 루프 968줄 존치 | `wc -l run_loop.sh` = 968 (Phase 3 직전 936, Phase 4 직전 960) — VERSIONS.md의 "936줄 이식" / "968줄 존치" 두 숫자 모두 정확 | ✅ |
| `run_loop.sh:17` source, `lib.sh:32-33` 무조건 재export | 행 번호 실측 일치. `MAM_VERSION=4.3.0 bash -c 'source lib.sh; echo $MAM_VERSION'` → `4.4.0` | ✅ |
**판정 동의**: 공개 계약(스크립트 경로·CLI·와이어 스키마·YAML 레이아웃)에 제거·변경이 없고 모든 기본 동작 변경이 env 1개로 가역이므로 SemVer 2.0.0 §8의 MAJOR 요건을 충족하지 않는다. 유일한 신규 fail-closed 거부(`MAM_VERSION` 게이트)는 프로덕션 경로에서 `lib.sh`가 값을 무조건 덮어쓰므로 정상 배포된 트리에서는 발동할 수 없고, 혼재 트리에서만 발동한다. 이는 릴리스 노트 "부분 배포 금지"로 명시되어 있다. **v4.4.0 MINOR가 옳다.**
## 2. 락스텝 갱신 검증
- `lib.sh` MAM_VERSION, `eager.py` FRAMEWORK_VERSION, VERSIONS.md 현재 버전 + 매트릭스 8행, 8개 `SKILL.md` frontmatter 모두 `4.4.0` (grep 실측).
- README/BOOTSTRAP 4종 배지: **v4.1.3 / v4.2.0 → v4.4.0**. `b347efd` 시점 README 배지는 `v4.2.0`인데 `lib.sh`는 `4.3.0`이었다. 즉 배지는 두 릴리스 동안 유실 상태였고, 이번 작업이 이를 함께 회수했다(유실 관점에서 긍정). 다만 배지는 락스텝 테스트 미커버(→ O-1).
- 트리 내 잔존 `4.3.0` 문자열은 VERSIONS.md 이력, `delegate-job` README/job-protocol/registry/SKILL.md의 "구현 위치 각주 (v4.3.0)" 등 **역사적 서술**뿐이며 현재 버전 표기로 남은 것은 없다.
## 3. 테스트 변경 검증 (재현)
### 3-1. 락스텝 4번째 다리(`eager.py`) 커버리지 — 주장 사실
- `b347efd` 트리에서 `eager.py`만 4.4.0으로 올린 뒤 구 `test_version_consistency.py` 실행 → **2 passed (미검출)**.
- HEAD 트리에서 `eager.py`만 4.5.0으로 올린 뒤 실행 → `test_three_way_version_lockstep`, `test_runtime_version_gate_rejects_a_partially_bumped_tree` **2 failed (검출)**. 커밋 메시지의 "gap" 주장과 수정 효과 모두 확인.
- `_get_eager_py_framework_version`은 정적 regex 파싱(`^FRAMEWORK_VERSION\s*=\s*"(\d+\.\d+\.\d+)"`, MULTILINE)으로 `eager.py:16` 형식과 정확히 일치. 새 게이트 테스트는 `importlib.util.spec_from_file_location`으로 `sys.path` 오염 없이 로드하고 `os.environ`을 try/finally로 복원한다. `os`/`re`는 파일 상단에 이미 import되어 있다.
### 3-2. 격리 결함(ambient `MAM_VERSION`) — 주장 "4건 실패" 정확히 재현
| 트리 | conftest fixture | env | 결과 |
| :--- | :---: | :--- | :--- |
| HEAD | 제거(재현용 복제본) | `MAM_VERSION=4.3.0` | **4 failed**, 16 passed — `test_p4_01_eager_import…`, `test_p4_01_loop_runner_instantiation…`, `test_p4_02_midflight…`, `test_p3_03_runner_agent_type_resolution` |
| HEAD | 존재 | `MAM_VERSION=4.3.0` (리뷰어 셸 실값) | 20 passed |
| HEAD | 존재 | `MAM_VERSION=9.9.9` | 20 passed |
| `b347efd` | 없음 | `MAM_VERSION=4.3.0` (자기 트리와 일치) | 19 passed — "우연히 같아 잠복" 주장 확인 |
| `b347efd` | 없음 | `MAM_VERSION=9.9.9` | 5 failed (위 4건 + `test_p3_02`) — 결함이 릴리스 이전부터 존재했음 확인 |
- fixture는 session 스코프 autouse로 `os.environ.pop`, 종료 시 복원. 게이트를 직접 검사하는 테스트(`test_p4_01` monkeypatch 9.9.9, 신규 게이트 테스트, `test_mam_version_is_not_env_overridable`)는 모두 자체적으로 값을 설정하므로 영향 없음(HEAD 20/20으로 실증).
- `test_issue5_phase4_runtime.py`는 하드코딩 리터럴 제거 후 `verify_framework_version(eager.FRAMEWORK_VERSION)` — 시그니처 기본값이 `FRAMEWORK_VERSION`이므로 동작 동일하며, monkeypatch 9.9.9 불일치 검사는 그대로 유지.
### 3-3. 린트
- `py_compile` 4파일 OK, `bash -n lib.sh` OK, 변경 추가행 중 100자 초과 없음, `git status` clean. (pyflakes/ruff는 venv 미설치 — 이전 라운드와 동일.)
## 4. 문서 검증
- VERSIONS.md 4.4.0 절: 인용 파일·행 번호(`mqtt_common.py:135`, `run_loop.sh:17`, `lib.sh:32-33`), env 이름·기본값, 테스트 수(510 → 750, +240; Phase 4 시점 749 + 신규 게이트 테스트 1 = 750 수집 실측) 모두 실 트리와 일치.
- `implementation_plan.md` Phase 0/3/4 상태 열, `phase4-freeze-removal.md` 부분 배포 금지 문구, `task.md` Rev.9 / P4-01 증거 갱신 — 내용 정확.
## 5. 결함
**차단 결함 없음.** 코드 변경은 상수 2개 + 테스트 3파일이며 세 가지 주장(락스텝 갭, 4건 격리 실패, fixture 효과)이 모두 실측 재현되었다.
### 비차단 관찰
- **O-1 (권고)**: README/BOOTSTRAP 4종 배지는 이번에 두 릴리스분이 한꺼번에 회수될 만큼 락스텝 밖에 있다. `test_three_way_version_lockstep`에 5번째 다리로 추가 권고. 검증한 프로토타입(15줄, `BADGE_DOCS` + `_get_badge_version` regex `badge/version-v(\d+\.\d+\.\d+)-`): HEAD에서 3 passed, `b347efd`에 역적용 시 `README.md badge (4.2.0) != lib.sh (4.3.0)`로 정확히 실패한다.
- **O-2 (표기)**: 테스트 함수명 `test_three_way_version_lockstep`과 파일 헤더 "3-Way"가 이제 4-way(O-1 채택 시 5-way)를 검사한다. 이름 변경은 선택 사항.
- **O-3 (환경)**: `test_p3_02_run_loop_wrapper_delegates_to_python_default`는 `.venv`가 없는 git worktree에서 `No module named 'paho'`로 실패한다(리뷰 중 관측, `.venv` 심링크로 해소). 본 커밋과 무관한 기존 테스트의 실행 환경 의존이며 메인 트리에서는 통과.
- **O-4 (브랜치)**: 릴리스 커밋은 `release/v4.4.0`에만 있고 `main`은 `b347efd`이다. VERSIONS.md의 "main 병합 완료"는 이 릴리스 브랜치 병합으로 완성된다.
- 이전 라운드 핸드오버(a665d729 §4) 중 코드 변경을 요하는 항목(all-None intent 신원 가드, direct job `claim` 토큰 등)은 이번 릴리스 범위 밖이며 유효하게 잔존.
## 6. 전체 스위트
- `env -u MAM_VERSION .venv/bin/python -m pytest tests -q`: __SUITE_RESULT__
[VERDICT: PASS]
@@ -0,0 +1,52 @@
# 🔍 Cross-Review Report (재검토) — Workspace Root Markdown 정리 및 최신화 (Job f28629a3)
- **리뷰어**: `planner-reviewer-claude-01` (Reviewer)
- **기준**: `main` `07cae71` 워킹트리(미커밋). 직전 리뷰 `50886e6f`([VERDICT: NOT PASS], 차단 결함 D-1/D-2)에 대한 재검토.
- **범위 고정**: 브리프 내장 diff = `git diff HEAD -- . ':(exclude).agents/reports'`(55,043 B) + 아카이브된 Rev.2 계획 사본(`.agents/reports/planner-reviewer-claude-01/plan-baea3f7e.md`). 두 diff의 차이는 계획 사본 블록(145줄)뿐. 변경 파일 8 + 이관 1, 코드·테스트·인스톨러 변경 0건.
---
## 1. 직전 리뷰 대비 델타 (실측: `diff head_5088.diff head_f286.diff`)
정확히 3곳만 달라졌다. 그 외 diff 본문은 바이트 동일.
| # | 위치 | 변경 | 직전 지적 대응 |
|---|---|---|---|
| Δ1 | `MESSAGING.md:350` §5.1 CAS 문단 | "monotonic `dispatch_token`" → "opaque per-attempt `dispatch_token` (fresh `uuid4` hex issued whenever an attempt starts via `claim`/`redispatch`) … compared inside the registry lock as an `expected_dispatch_token` precondition; ordering … tracked separately by the monotonic `transition_seq` counter" | **D-1 해소** |
| Δ2 | `MESSAGING.md:353` §5.1 항목 1 | 로그 경로 `<job_id>.<phase>.subscriber.out` → `<job_id>.subscriber.out (loop iterations use <job_id>.iter_<n>_<role>.subscriber.out)` | **D-2 해소** |
| Δ3 | `IMPROVEMENTS.md:307-311` B-8 블록 | 앞 공백 2줄→1줄, 뒤 `---` 앞 공백 1줄 추가 | 비차단 O-2 해소 |
## 2. 델타의 코드 대조
| 문장 요소 | 코드 근거 | 판정 |
|---|---|---|
| `dispatch_token` = 시도 시작 시 `uuid4` hex 재발급 | `engine.py:300` `record[DISPATCH_TOKEN_FIELD] = uuid.uuid4().hex`, 발급 조건 `request in ATTEMPT_STARTING_REQUESTS` (`engine.py:87` = `("claim", "redispatch")`) | ✅ |
| 락 안에서 `expected_dispatch_token` 전제조건 대조 | `engine.py:181-183`; 계약 `docs/contracts/issue-5/state-transitions.md:57` | ✅ |
| 순서는 `transition_seq` 단조 카운터 | `engine.py:296` `+ 1` 증가, 주석 "A monotonic counter" | ✅ |
| `MAM_ENGINE_CAS=1` 기본 | `engine.py:109` | ✅ (변경 없음) |
| direct 경로 `<job_id>.subscriber.out` | `multi-agent-mux-delegate-job:165` | ✅ |
| 루프 경로 `<job_id>.iter_<n>_<role>.subscriber.out` | `:286` `${JOB_ID}.iter_${iteration}_${display_role}.subscriber.out` | ✅ |
| `grep -n monotonic MESSAGING.md` | 3건: 227행(`last_seq`, HEAD 기존), 294행(monotonic time, HEAD 기존), 350행(`transition_seq`, 신규·정확). HEAD 기준 2건 → 3건 | ✅ 직전 리뷰 재검증 조건 충족 |
## 3. Rev.2 게이트 전건 재실행
| 게이트 | 결과 |
|---|---|
| G1 루트 md 8개, 이관 파일 존재 | ✅ 8 |
| G2 문서 바인딩 4모듈 | ✅ **49 passed** (57.96s) |
| G3 전체 스위트 | §5 |
| G4 상대 링크 (서브모듈 인식 보강판: `nats-docker/*`는 `git -C nats-docker ls-files`로 추적 확인) | ✅ BROKEN/UNTRACKED 0건 (직전 오탐 6건 해소) |
| G5 `.agents/skills`, `tests`, `deploy` 무변경 | ✅ stat 0줄 |
| G6 인스톨러 | ✅ minimal rc=0 `AGENTS.md`; full rc=0 `AGENTS.md BOOTSTRAP.ko.md BOOTSTRAP.md MESSAGING.md` |
| G7 원장 | ✅ `## 2.`/`## 3.` 1/1, §5 블록 31 = 헤더 ID 31, 10개 핵심 ID 제목 각 1회, §2~§3 `✅` 누출 0, 잔재 토큰 **20/20** 보존 |
| README 트리 | ✅ 40/40줄, 루트 md 8/8 |
## 4. 잔여 관측 (비차단, 조치 불요)
- O-1(직전) B-14 "원 진단" 불릿과 `현상` 불릿 부분 중복 — 유지됨. 토큰 보존 목적이므로 허용.
- README `tests/ (32 modules)` — `test_*.py` 31 + `conftest.py` 1. 계수 기준 미명시이므로 허용.
- 게이트 4 스크립트의 서브모듈 오탐은 Planner(본인) 측 스크립트 결함이었으며 본 리뷰에서 보강판으로 대체. 향후 계획서 게이트에 반영 필요(Planner 후속).
## 5. 전체 회귀 스위트 (G3)
- `.venv/bin/python -m pytest -q tests/` (워킹트리, 본 변경 적용): **750 passed in 930.36s (0:15:30)**, FAILED/ERROR 0건. 기준선 `07cae71`(750)과 동일.
## 6. 결론
직전 차단 결함 D-1(`dispatch_token` 단조성 오기)·D-2(submit 로그 경로 오기)는 제시한 검증 문장으로 정확히 교체되었고, 코드(`engine.py:87/296/300`, `multi-agent-mux-delegate-job:165/286`)와 일치한다. 그 외 diff는 직전 리뷰 시점과 바이트 동일하며 모든 게이트(문서 테스트 49, 전체 750, 링크 0건 깨짐, 인스톨러 두 모드, 원장 31=31, 잔재 토큰 20/20, README 트리 40/40)를 통과한다. 린트·동작성·유실 관점 모두 결함 없음.
[VERDICT: PASS]
@@ -0,0 +1,30 @@
# Issue #5 release-version review
Job: e5c9a052
Reviewer: planner-reviewer-codex-01 (planner,reviewer)
Reviewed commit: 3874797 on main, following merge b347efd.
Approve the v4.4.0 version update. No blocking mismatch or regression was found in this release patch. No implementation edits or escalation were necessary.
## Version decision and consistency
A large internal Bash-to-Python migration does not by itself require a major version. The retained script entry points and compatibility paths, together with additive opt-in functionality, support v4.4.0 rather than requiring v5.0.0 solely because of architectural size. This assessment concerns the release patch and documented compatibility boundary; it is not a new exhaustive audit of all Phase 3/4 behavior.
Verified lockstep across lib.sh MAM_VERSION, eager.py FRAMEWORK_VERSION, VERSIONS.md current release and eight-row skill matrix, and all eight SKILL.md frontmatter versions. They consistently specify 4.4.0. README/BOOTSTRAP and contract references were updated with the release.
The consistency test now covers the previously separate runtime constant. Replacing the Phase 4 test's hardcoded version with a check of the actual constant is appropriate because the dedicated consistency test owns the cross-file equality assertion. Explicit mismatch tests still exercise rejection.
The test-session removal of inherited MAM_VERSION isolates the tree under test from a pre-upgrade launcher. It does not disable the production gate: run_loop.sh sources lib.sh before Python startup, and the test explicitly setting a mismatched version still fails closed as intended.
## Nonblocking release-note precision
VERSIONS.md's blanket statement that no public behavior/exit code changed is stronger than the evidence cited. Earlier phases deliberately added CAS refusal outcomes and stricter verdict handling. Describe preserved supported contracts and intentional safety corrections explicitly. Likewise, rollback switches are operational escape paths, not proof of SemVer compatibility. These wording qualifications do not require changing the selected version or block the synchronized version patch.
## Validation
- `./.venv/bin/python -m pytest tests/test_version_consistency.py tests/test_issue5_phase4_runtime.py -q`: **8 passed in 1.23s**.
- `git diff --check`: clean; working tree clean before writing this assigned report.
- Inspected release commit scope, constants/matrix/frontmatters, new test isolation fixture and runtime-gate test changes.
- Release notes report 750 full-suite passes; this reviewer independently ran only the eight relevant version/runtime tests and does not claim a repeated full-suite run.
[VERDICT: PASS]
@@ -0,0 +1,28 @@
# Cross-review — root Markdown cleanup, follow-up
Job: `fd874949`
Reviewer: `planner-reviewer-codex-01` (`planner,reviewer`)
Baseline: `07cae71`, current working tree including the staged roadmap move.
No blocking findings remain. Both findings from review `2601270d` are resolved by documentation changes that match the implementation.
## Previous findings verified as resolved
1. **Optional dispatch-token comparison — resolved (`MESSAGING.md:350`).** The paragraph now distinguishes the token stored for an attempt from the optional `expected_dispatch_token` supplied by callers. It explicitly states that ordinary publisher status updates do not supply the precondition. This matches `lib_py/delegation/engine.py:181` and `:270`, the publisher update path in `lib_py/delegation/mqtt_common.py:435`, and inferred completion in `lib_py/loop/autocomplete.py:224`. Token generation and transition ordering also match `engine.py:296-300`.
2. **Subscriber readiness fallback — resolved (`MESSAGING.md:354`).** The handshake bullet now describes a bounded readiness attempt, warning and continuation after the polling budget expires, and continuation on early exit status 0 or 3. These statements match `multi-agent-mux-delegate-job/multi-agent-mux-delegate-job:172-194`; the previous unconditional readiness guarantee has been removed.
## Verification and review scope
- Compared the complete embedded diff payloads of jobs `2601270d` and `fd874949`: only the two passages above and the corresponding `MESSAGING.md` blob hash changed. The previously reviewed roadmap move, backlog consolidation, bilingual trees, bootstrap updates, and archived reports are unchanged.
- Verified every file included in the new brief against its recorded new Git blob hash; all match the current files.
- `git diff HEAD --check`: clean.
- No changes under `.agents/skills/`, `tests/`, or `deploy/`.
- Root Markdown inventory remains the required eight files. Backlog section counts remain **1 / 3 / 1 / 0 / 31**, with no completed blocks in sections 2 or 3.
- Rechecked **34 local link targets**, including six references tracked inside the `nats-docker` submodule: all exist and are tracked. The plan's parent-repository-only tracking check produces submodule false positives; validating those targets within their owning repository resolves them.
- Prior independent preservation checks remain applicable because the relevant files are byte-identical to the preceding review: O-1 content, moved completed blocks, legacy diagnosis details, README tree parity, and roadmap links showed no content-loss defect.
- Prior independent focused regression result from job `2601270d`: **49 passed in 54.88s**, using `tests/test_deploy_layout.py`, `tests/test_o1_rebuttal.py`, `tests/test_deploy_freshness.py`, and `tests/test_version_consistency.py`. This run was not repeated for the two prose corrections. The attached peer report's full-suite result of 750 passing tests and minimal/full installation checks remain attributed peer evidence, not an independent rerun in this job.
The two requested wording corrections close the review. No runtime changes or planner escalation are needed.
[VERDICT: PASS]
@@ -0,0 +1,35 @@
# Root markdown cleanup review (uncommitted tree on `07cae71`)
- **Reviewer**: `reviewer-creator-grok-01`
- **Job**: `30122522`
- **HEAD**: `07cae71` (working tree)
- **Diff**: `AGENTS.md`, `BOOTSTRAP.md` / `.ko.md`, `IMPROVEMENTS.md`, `MESSAGING.md`, `README.md` / `.ko.md`, `implementation_plan.md` → `docs/contracts/nats-backplane/implementation_plan.md`
- **Checks**: `git diff --check` clean. Root `*.md`: `AGENTS.md`, `BOOTSTRAP.md`, `BOOTSTRAP.ko.md`, `IMPROVEMENTS.md`, `MESSAGING.md`, `README.md`, `README.ko.md`, `VERSIONS.md`.
Documentation only. No production tests required. Tree re-read independently (same diff as job `01859590`; residuals below still present).
---
## What holds
The NATS backplane plan is off the workspace root and lives next to Issue #5 contracts. The new file records the move date and uses working relative links to `nats-docker/NATS_REPORT.md` and `PRIVATE_SERVER.md`.
`BOOTSTRAP.md` / `.ko.md` list `lib_py/{agents,delegation,loop}` and call `scripts/*.py` shims. `README.md` / `.ko.md` do the same in the skills list and directory tree. `MESSAGING.md` stamps v4.4.0, names `lib_py.delegation` as the body, notes CAS/`dispatch_token`, and marks HMAC as implemented. `AGENTS.md` O-3 still delegates via `run_loop.sh` and names the Python loop runtime.
`IMPROVEMENTS.md` is one ledger: **5 open** (A-2, B-16, B-17, B-18, O-5) and **31 completed**. Header IDs match completed `###` headings. Merge-duplicate B-14/B-15/B-16 blocks are gone. O-2 (P0-2) is still in §5. B-13 notes freeze removal in v4.4.0.
---
## Residuals (non-blocking)
1. **README architecture narrative was not updated.** Skills list and tree mention `lib_py.loop`; Layer A is still “lib.sh + status/resume/stop/create” and Layer B does not mention the CAS engine (`README.md:62-63`, same in `README.ko.md:44-45`).
2. **Inbound link not updated with the move.** `nats-docker/PRIVATE_SERVER.md:5` still points `implementation_plan.md` at `lac/curriculum/How_To_Use_GENAI/implementation_plan.md`. After this relocate it should be `../docs/contracts/nats-backplane/implementation_plan.md`. `IMPROVEMENTS.md` still names `NATS_REPORT.md` without a path; the file is `nats-docker/NATS_REPORT.md`.
3. **Stale line number.** B-16 still says `mqtt_common.py:258`; `client_id` is built at `lib_py/delegation/mqtt_common.py:276`.
4. **BOOTSTRAP parent line** still calls `skills/` “a collection of shell scripts” while listing `lib_py/` under it.
5. **`AGENTS.md` / `README.md` have no trailing newline.** Pre-existing. `git diff --check` is clean.
No `[ESCALATE: PLANNER]`.
---
[VERDICT: PASS]
@@ -0,0 +1,54 @@
# v4.4.0 lockstep release review (`3874797`)
- **Reviewer**: `reviewer-creator-grok-01`
- **Job**: `78443ebe`
- **HEAD**: `3874797` (`release(v4.4.0): bump framework and eight skills to 4.4.0 in lockstep`)
- **Tests this turn**: `pytest tests/test_version_consistency.py tests/test_issue5_phase4_runtime.py` → **8 passed**. Collect-only **750** (matches the release notes). `git diff --check 3874797^..3874797` clean. Full 750 suite not re-run this turn.
---
## SemVer: MINOR `v4.4.0`, not MAJOR `v5.0.0`
SemVer 2.0.0 §8 limits MAJOR to a **breaking public API** change. Issue #5 is large; it is not that.
Checked, not taken from the notes:
| Claim | This turn |
|---|---|
| No public path removed or renamed | `git diff --name-status fc0bd96..HEAD` → **deleted 0, renamed 0** |
| Wire schema | `mqtt_common.py:135` `SCHEMA_VERSION = 1` |
| `scripts/*.py` still present | `job_subscriber.py`, `mqtt_common.py`, `publish_event.py`, `registry.py` |
| Defaults revert with one env var | `MAM_LOOP_PY` default 1, freeze only if `MAM_LOOP_FREEZE=1` or legacy shell; `MAM_AUTO_COMPLETE` still default off |
| Auto-complete | opt-in, documented |
New fail-closed `MAM_VERSION` ↔ `FRAMEWORK_VERSION` gate is a safety check on mixed trees, not a contract removal. Operators with a consistent tree do not migrate. **4.4.0 is the right stamp.**
---
## 4-way lockstep
All four legs read `4.4.0`:
- `lib.sh` `MAM_VERSION="4.4.0"` (not env-overridable; spoof test still holds)
- `lib_py/loop/eager.py` `FRAMEWORK_VERSION = "4.4.0"`
- `VERSIONS.md` current `v4.4.0` + matrix 8 × `4.4.0`
- 8 × `SKILL.md` frontmatter `version: 4.4.0` (create, stop, resume, status, monitor, delegate-job, loop, orc-onboard)
`test_three_way_version_lockstep` now also asserts eager.py. `test_runtime_version_gate_rejects_a_partially_bumped_tree` pins the fail-closed gate. Phase 4 no longer hardcodes a version literal.
Ambient isolation: session-scoped conftest pops inherited `MAM_VERSION` so pytest measures the tree, not the runner’s shell. That is why a bump would otherwise fail with `expected 4.4.0, got 4.3.0 in environment`. Production is unaffected: `run_loop.sh` sources `lib.sh` first and re-exports.
README / BOOTSTRAP badges were bumped. Remaining `4.3.0` in `VERSIONS.md` is the prior changelog section, which is correct.
---
## Residuals (non-blocking)
1. The lockstep test is still named `test_three_way_version_lockstep` while it checks four legs. Rename when convenient.
2. Full **750**-test suite not re-run this turn (8 targeted + collect-only 750). The release commit claims 750 passed in 912.50s.
No `[ESCALATE: PLANNER]`.
---
[VERDICT: PASS]
@@ -0,0 +1,50 @@
# 🔍 Cross-Review: Workspace Root Markdown Cleanup & Modernization (Job b049e495)
- **Reviewer**: `reviewer-opencode-01` (role: reviewer)
- **Target**: Uncommitted working tree on `main` @ `07cae71` (v4.4.0): 7 modified root docs + 1 rename (`implementation_plan.md` → `docs/contracts/nats-backplane/implementation_plan.md`) — the Rev.2 plan (`plan-baea3f7e.md`) executed, refined through multiple review rounds (Claude `50886e6f` NOT PASS → `f28629a3` PASS re-review; Grok `30122522` PASS; codex `2601270d` findings remediated by `09f2c915`).
- **Method**: All plan gates re-run by me against the live tree — ledger algebra, link integrity (submodule-aware), tree parity, installer modes, doc-binding tests, the full regression suite, and every new MESSAGING.md technical claim traced to code.
---
## 0. My Verification Runs
| Check | Result |
|---|---|
| Full suite `pytest tests/ -q` (my own run, started in the interrupted `ee242671` round; tree unchanged since — only MESSAGING.md §350/§354 prose refined, no code/tests touched) | **750 passed / 0 failed** (983s) — identical to the `07cae71` baseline |
| Doc-binding 4-module suite (G2) | **49 passed** |
| Installer both modes (G6) | minimal rc=0, full rc=0 |
| Code/test/deploy drift | **0 files** — pure documentation change |
## 1. All Rev.2 gates re-verified by me
- **G1**: Root markdowns exactly 8 (AGENTS, BOOTSTRAP, BOOTSTRAP.ko, IMPROVEMENTS, MESSAGING, README, README.ko, VERSIONS); NATS plan relocated to `docs/contracts/nats-backplane/` via proper git rename, with move-date annotation and `../../../`-prefixed links; the §7 `.mam.env` link correctly retargeted to the tracked `.mam.env.example` (challenge C-2's gitignored-file trap avoided).
- **G4 (links)**: All relative links resolve and are git-tracked — 0 broken. (My first run flagged 6 `nats-docker/*` paths; I traced this to my own script lacking submodule handling — the files exist and are tracked in the submodule's repo, exactly the false-positive Claude's `f28629a3` documented and fixed. Submodule-aware re-run: clean.)
- **G7 (IMPROVEMENTS.md single ledger)**: single `## 2.`/`## 3.` headers; §5 = **31 blocks** = header **31 IDs**; per-ID `###` uniqueness holds for all spot-checked IDs; zero ✅ leakage into §2/§3; all 20 remnant-only tokens (B-14/B-15 original diagnoses, O-5 nats-py rationale, etc.) preserved ≥1 occurrence each — merged-then-deleted as the plan required, not silently dropped.
- **README trees**: 45/45 line parity, all 8 root mds in both trees' tree blocks (each exactly once within the block; the extra `BOOTSTRAP.md`/`VERSIONS.md` occurrences are the prose link and version badge — outside the tree block, expected).
- **O-1 preserved string**: covered by the passing `test_o1_rebuttal.py` in the 49.
## 2. The codex-review remediations (`2601270d` → `09f2c915`) — independently verified against code
This diff's MESSAGING.md §5.1 evolved after my interrupted prior round; the two changes are the codex reviewer's precision findings, and I verified both remediations against live source myself:
1. **`dispatch_token` precondition correctly scoped as optional** (MESSAGING.md:350) — verified: `engine.py:181` compares only `if expected_dispatch_token is not None` (default `None` at :147/:270); `mqtt_common.py:435` (ordinary publisher updates) calls `engine.transition` without the precondition; `lib_py/loop/autocomplete.py:224` (inferred completion) explicitly supplies `expected_dispatch_token=token`; token issuance gated on `ATTEMPT_STARTING_REQUESTS = ("claim", "redispatch")` (`engine.py:87`, `uuid4().hex` at :300); ordering by monotonic `transition_seq` (+1 at :296); `MAM_ENGINE_CAS` default-on (:109). Every sentence in the paragraph matches code.
2. **Subscriber handshake described as bounded wait with fallback** (MESSAGING.md:354) — verified: `multi-agent-mux-delegate-job:172-195` polls `^SUBSCRIBED ` every 0.2s for 25 iterations; on budget expiry it warns ("falling back to proceed") and proceeds; early subscriber exits 0 or 3 permit continuation. The old "ensure the subscriber is connected" overstated the guarantee — now accurate.
3. The D-1/D-2 fixes from the earlier Claude NOT PASS round (monotonic-token mischaracterization; `<job_id>.<phase>.subscriber.out` path error) remain correctly in place — the direct path `<job_id>.subscriber.out` (:165) and loop path `iter_<n>_<role>.subscriber.out` (:286) both match the doc, and `monotonic` appears exactly 3 times, all now accurate.
## 3. Peer-review trail (all registry-verified)
The chain is honest and complete: plan Rev.1 (`45bd8635`) → challenge (`87aa5b5a`, 3 findings all accepted) → plan Rev.2 (`baea3f7e`) → execution → Grok PASS (`30122522`, residuals non-blocking) → Claude NOT PASS (`50886e6f`, D-1/D-2 factual errors) → remediation → Claude PASS re-review (`f28629a3`, all gates green + 750 suite) → codex review (`2601270d`, 2 precision findings) → remediation (`09f2c915`, verified) → this review. Grok's residuals (README architecture narrative, `PRIVATE_SERVER.md` inbound link, B-16 stale line number, BOOTSTRAP "shell scripts" parent line, trailing newlines) remain — all non-blocking, all explicitly out-of-scope per the plan (§4).
## 4. Residual observations (non-blocking)
- Grok's five residuals stand as documented — each is a candidate for a follow-up docs pass, none affects correctness.
- `README tests/ (32 modules)` counts `test_*.py` + `conftest.py`; counting basis unstated but tolerable.
- The prior interrupted round's own report artifact (`ee242671`) was never published — this report supersedes it; the job registry shows only its `started` event, consistent with an interrupted run.
---
## 5. Verdict
Every Rev.2 acceptance gate passes under my own re-execution (root 8 + relocation, 49 doc-binding tests, 750 full-suite green, 0 broken links submodule-aware, installer both modes, ledger 31=31 with zero ✅ leakage and all remnant tokens preserved, README trees in parity, zero code/test/deploy drift). The two most recent precision findings (codex) are correctly remediated with every technical claim independently traced to code by me, and the multi-round review chain — including a genuine NOT PASS → fix → re-verify cycle — is recorded honestly. Documentation-only change with no functional risk.
[VERDICT: PASS]
+1 -1
View File
@@ -29,7 +29,7 @@ export WORKSPACE_ROOT
# Framework semantic version. Single runtime source of truth; kept in lockstep
# with VERSIONS.md and the 8 SKILL.md frontmatters by tests/test_version_consistency.py.
# NOTE: unlike other MAM_* variables this one is intentionally NOT env-overridable.
MAM_VERSION="4.3.0"
MAM_VERSION="4.4.0"
export MAM_VERSION
AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$WORKSPACE_ROOT/.mam/agent-sessions.yaml}"
+1 -1
View File
@@ -13,7 +13,7 @@ import sys
from typing import List, Sequence
# Framework version locked with framework constants
FRAMEWORK_VERSION = "4.3.0"
FRAMEWORK_VERSION = "4.4.0"
CORE_MODULES: Sequence[str] = (
# Standard library modules
@@ -1,7 +1,7 @@
---
name: multi-agent-mux-create
description: "Create a new agent session (claude, antigravity/agy) in a dedicated herdr session for context-preserving long-running work. Always creates a herdr session — never backgrounds with nohup/disown. Writes the new session to .mam/agent-sessions.yaml. Use when you want to start a fresh agent (no prior UUID) for a new project workspace."
version: 4.3.0
version: 4.4.0
author: godopu
license: MIT
platforms: [linux, macos]
@@ -1,7 +1,7 @@
---
name: multi-agent-mux-delegate-job
description: "Delegate a unit of work to any autonomous agent (claude-code, hermes, agy, grok-build, codex, or a human) and observe it asynchronously over an MQTT event channel. Supported roles include orchestrator, worker, and reviewer."
version: 4.3.0
version: 4.4.0
author: godopu
license: MIT
platforms: [linux, macos, windows]
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: multi-agent-mux-loop
description: "Run an autonomous planning-execution-review loop using multiple agents (Planner, Creator, Reviewers) in the workspace. Automatically orchestrates plan discussion, code changes, and peer reviews until a unanimous PASS is achieved or the maximum iteration limit is reached."
version: 4.3.0
version: 4.4.0
author: godopu
license: MIT
platforms: [linux, macos]
@@ -1,7 +1,7 @@
---
name: multi-agent-mux-monitor
description: "Run a long-lived reconciler that watches .mam/agent-sessions.yaml against the actual herdr/agent runtime state and reconciles them. Use when you want live visibility into which agent sessions are running, which are dead, which have stale YAML entries, and which have new session ids that haven't been recorded yet. Runs as a persistent loop (`reconcile.sh --subscribe`) that keeps going until it times out, idles out, or is interrupted."
version: 4.3.0
version: 4.4.0
author: godopu
license: MIT
platforms: [linux, macos]
@@ -1,7 +1,7 @@
---
name: multi-agent-mux-orc-onboard
description: "Register current or specified orchestrator session UUID into agent-sessions.yaml orchestrator_uuids list to prevent sub-agent discovery capture."
version: 4.3.0
version: 4.4.0
author: godopu
license: MIT
platforms: [linux, macos]
@@ -1,7 +1,7 @@
---
name: multi-agent-mux-resume
description: "Resume an existing agent (claude, antigravity/agy) conversation by UUID into a herdr session. Reads .mam/agent-sessions.yaml for the saved session/conversation id, spawns (or reuses) a herdr session of the matching name, and runs `claude -r <id>` or `agy --conversation <id>` inside. Use when you want to reattach to a previous session's context, or revive a session whose herdr died but the agent's conversation is still on disk."
version: 4.3.0
version: 4.4.0
author: godopu
license: MIT
platforms: [linux, macos]
@@ -1,7 +1,7 @@
---
name: multi-agent-mux-status
description: "Read-only instant snapshot of all agent herdr sessions — name, YAML status, herdr alive, pane cmd/cwd, resume UUID on disk, and any drift. No mutation. Reuses reconcile.sh --dry-run for the diff logic. Use when you want to know 'what's running RIGHT NOW' without spinning up the monitor loop."
version: 4.3.0
version: 4.4.0
author: godopu
license: MIT
platforms: [linux, macos]
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: multi-agent-mux-stop
description: "Stop an agent herdr session (claude, antigravity/agy) and update .mam/agent-sessions.yaml. Default stops gracefully and marks status=stopped with conversation preserved for resume. Does NOT delete on-disk conversation artifacts (jsonl/db) — those are preserved unless --purge-conversation is passed. Use when ending a work session, switching to a different one, or cleaning up before a fresh start."
version: 4.3.0
version: 4.4.0
author: godopu
license: MIT
platforms: [linux, macos]
+1 -1
View File
@@ -73,4 +73,4 @@ Read [MULTI_AGENT_RULES.md](.agents/MULTI_AGENT_RULES.md) (or [Korean version](.
**Normal vs. Orchestration Modes**
- **Normal Mode**: The orchestrator acts as Main Creator and may edit files directly.
- **Loop Active Mode (`/multi-agent-mux-loop`)**: Direct file mutation is intercepted by `.agents/hooks.json`. Do not seek workarounds when a tool call is denied — delegate the task immediately via `run_loop.sh`.
- **Loop Active Mode (`/multi-agent-mux-loop`)**: Direct file mutation is intercepted by `.agents/hooks.json`. The loop runtime is powered by the Python core (`lib_py.loop`, eager-import immutable runtime), and the delegation principle to `run_loop.sh` upon hook denial remains identical. Do not seek workarounds when a tool call is denied — delegate the task immediately via `run_loop.sh`.
+12 -6
View File
@@ -2,7 +2,7 @@
본 문서는 `herdr_agent_orchestration` 오케스트레이션 및 메시징 백플레인 워크플로우를 새로운 프로젝트에 도입하여 이식하고, 새로운 개발자/에이전트가 초기 가동을 시작할 때 수행해야 하는 환경 설정 및 구축 절차를 안내합니다.
[![Version: v4.1.3](https://img.shields.io/badge/version-v4.1.3-blue.svg)](VERSIONS.md)
[![Version: v4.4.0](https://img.shields.io/badge/version-v4.4.0-blue.svg)](VERSIONS.md)
새로운 에이전트는 이 안내서에 기술된 절차를 순차적으로 실행하여 초기 환경을 안정적으로 설정할 수 있습니다.
@@ -17,6 +17,10 @@
* `MULTI_AGENT_RULES.ko.md`: 에이전트 간의 역할 분담(PM, Worker, Reviewer) 및 이벤트 발행 규약 정의 (한국어)
* `skills/`: 멀티 에이전트 구동 및 비동기 잡 처리를 수행하는 셸 스크립트 모음
* `lib.sh`: 오케스트레이션의 핵심 셸 함수 및 가상환경(venv) 자동 연동 라이브러리
* `lib_py/`: 파이썬 코어 오케스트레이션 패키지
* `agents/`: 멀티 에이전트 CLI 수명 주기 어댑터
* `delegation/`: 코어 비동기 위임 엔진 및 CAS 상태 머신
* `loop/`: 자율 계획-실행-교차검증 루프 런타임
* `multi-agent-mux-create/`: 격리된 herdr 에이전트 세션을 시작하는 스크립트
* `multi-agent-mux-stop/`: 세션을 정상적으로 중지하고 상태를 업데이트하는 스크립트
* `multi-agent-mux-resume/`: 중지된 에이전트 세션을 이전 대화 상태 그대로 복원하는 스크립트
@@ -24,14 +28,16 @@
* `multi-agent-mux-monitor/`: herdr 상태와 레지스트리 상태를 동기화하는 모니터 스크립트
* `multi-agent-mux-delegate-job/`: 비동기 잡 분할 실행 모듈
* `requirements.txt`: Python 의존성 목록 (paho-mqtt, pyyaml)
* `scripts/`: 핵심 비즈니스 로직을 구동하는 Python 스크립트 디렉터리
* `registry.py`: 잡의 등록, 클레임 및 원자적 파일 락 제어 (CLI 지원)
* `job_subscriber.py`: 백그라운드 이벤트 구독기 및 오디팅 로그 생성기
* `publish_event.py`: 실행 상태 및 에러 트랩 시 이벤트 퍼블리셔
* `mqtt_common.py`: 공통 MQTT 브로커 연결 유틸리티
* `scripts/`: 레거시 호출 호환성을 위한 하위 호환 shim 스크립트 디렉터리
* `registry.py`: 잡의 등록, 클레임 및 원자적 파일 락 제어 shim
* `job_subscriber.py`: 백그라운드 이벤트 구독기 및 오디팅 로그 생성기 shim
* `publish_event.py`: 실행 상태 및 에러 트랩 시 이벤트 퍼블리셔 shim
* `mqtt_common.py`: 공통 MQTT 브로커 연결 유틸리티 shim
* `multi-agent-mux-loop/`: 자율적인 계획-실행-교차검증 반복 순환 루프 오케스트레이터
* `multi-agent-mux-orc-onboard/`: 오케스트레이터 세션 UUID 온보딩 및 서브에이전트 격리 헬퍼
* `AGENTS.md`: 에이전트 행동 지침 및 오케스트레이터 스코프 가드
* `MESSAGING.md`: 에이전트 간 주고받는 MQTT 메시지 와이어 스킴 가이드라인
* `VERSIONS.md`: 릴리스 노트 및 4-way 락스텝 버전 원장
---
+12 -6
View File
@@ -2,7 +2,7 @@
This document guides you through the setup and initialization procedures required to adopt the `herdr_agent_orchestration` orchestration and messaging backplane workflow in a new project, enabling a new developer or agent to get up and running quickly.
[![Version: v4.1.3](https://img.shields.io/badge/version-v4.1.3-blue.svg)](VERSIONS.md)
[![Version: v4.4.0](https://img.shields.io/badge/version-v4.4.0-blue.svg)](VERSIONS.md)
A new agent can follow the steps in this guide sequentially to establish a stable and reliable initial environment.
@@ -17,6 +17,10 @@ Before cloning this project into a new environment, you must first understand th
* `MULTI_AGENT_RULES.ko.md`: Definition of agent roles (PM, Worker, Reviewer) and event publication rules (Korean).
* `skills/`: A collection of shell scripts that execute multi-agent coordination and asynchronous job processing.
* `lib.sh`: The core orchestration shell functions and virtual environment (venv) auto-loading library.
* `lib_py/`: Python core orchestration package.
* `agents/`: Multi-agent CLI lifecycle adapters.
* `delegation/`: Core asynchronous delegation engine and CAS state machine.
* `loop/`: Autonomous planning-execution-review loop runtime.
* `multi-agent-mux-create/`: Script to launch isolated herdr agent sessions.
* `multi-agent-mux-stop/`: Script to gracefully stop agent sessions and update states.
* `multi-agent-mux-resume/`: Script to restore stopped agent sessions back to their previous conversation state.
@@ -24,14 +28,16 @@ Before cloning this project into a new environment, you must first understand th
* `multi-agent-mux-monitor/`: Monitor script to sync herdr states with the registry.
* `multi-agent-mux-delegate-job/`: Asynchronous job splitting and delegation module.
* `requirements.txt`: Python dependency list (`paho-mqtt`, `pyyaml`).
* `scripts/`: Python scripts running the core business logic.
* `registry.py`: Job registration, claiming, and atomic file lock control (CLI supported).
* `job_subscriber.py`: Background event subscriber and audit log generator.
* `publish_event.py`: Event publisher for runtime states and error traps.
* `mqtt_common.py`: Common utility for connecting to the MQTT broker.
* `scripts/`: Wire-compatibility shims for legacy callers.
* `registry.py`: Job registration, claiming, and atomic file lock control shim.
* `job_subscriber.py`: Background event subscriber and audit log generator shim.
* `publish_event.py`: Event publisher for runtime states and error traps shim.
* `mqtt_common.py`: Common utility for connecting to the MQTT broker shim.
* `multi-agent-mux-loop/`: Autonomous planning-execution-review loop orchestrator.
* `multi-agent-mux-orc-onboard/`: Orchestrator session UUID onboarding and sub-agent isolation helper.
* `AGENTS.md`: Behavioral guidelines and orchestrator scope guards.
* `MESSAGING.md`: Messaging scheme and wire protocol guidelines for MQTT communication between agents.
* `VERSIONS.md`: Release notes and 4-way lockstep version ledger.
---
+56 -81
View File
@@ -1,15 +1,15 @@
# 🛠️ Multi-Agent Mux 종합 개선 및 미해결 과제 백로그 (`IMPROVEMENTS.md`)
- **최종 갱신일**: 2026-08-24 (`nats-docker` 서브모듈 분리, B-20 2×K 그리드 TUI 레이아웃 엔진, J-1/J-2 레이아웃 환경변수/임계값 보강, B-21 `--agent` 표준화 및 레지스트리 agent_of_row 폴백 통합 완료)
- **최종 갱신일**: 2026-09-07 (IMPROVEMENTS.md 단일 원장화: §2/§3 완료 항목 §5 이관, 머지 잔재 병합 제거, v4.1.x~v4.4.0 완료 사항 반영)
- **통합 관리 대상**: 기존 `CODEBASE_REVIEW_REPORT.md` + `OPTIMIZATION.md` + `NATS_REPORT.md`
- **총 추적 미해결 과제**: **5건** (아키텍처 1건: `A-2`, 엣지케이스 및 가용성 3건: `B-16`, `B-17`, `B-18`, 오케스트레이션 1건: `O-5`)
- **완료된 과제**: **30건** (A-1, A-3, A-4, A-5, B-1, B-3, B-4, B-5, B-7, B-8, B-9, B-10, B-13, B-14, B-15, B-19, B-20, B-21, C-1, C-2, C-3b, C-6, O-1, O-2, O-3, O-4-OrcOnboard, O-6, Herdr-0.8.0-Compat-SanitizeHash, P2-1-DelegateJobSafe-TrapFix, P2-2-C3a-C4-LegacyCleanup)
- **완료된 과제**: **31건** (B-21, B-20, B-19, B-14, B-15, O-6, A-4, B-9, B-13, B-10, B-5, C-6, P3-1-A4Phase2-C3b, P2-2-C3a-C4-LegacyCleanup, P2-1-DelegateJobSafe-TrapFix, O-4-OrcOnboard, O-2-P0-2, P0-1-B-7, Rev.2-b4a1d094-SessionIdPinning, B-4, O-3, A-1, A-3, C-2, A-5, B-1, B-3, C-1, O-1, Herdr-0.8.0-Compat-SanitizeHash, B-8)
---
## 📌 개요
본 문서는 Multi-Agent Mux (MAM) 프레임워크의 **코드베이스 아키텍처 결함, 런타임 엣지케이스, 레거시 잔재** 및 **`/multi-agent-mux-loop` 오케스트레이션 최적화 과제**를 단일 백로그로 통합 추적하기 위한 종합 관리 문서입니다.
본 문서는 Multi-Agent Mux (MAM) 프레임워크의 **코드베이스 아키텍처 결함, 런타임 엣지케이스, 레거시 잔재** 및 **`/multi-agent-mux-loop` 오케스트레이션 최적화 과제**를 단일 백로그로 통합 추적하기 위한 종합 관리 문서입니다. v4.1.0 이후 릴리스 단위 변경 이력은 `VERSIONS.md`를 정본으로 하며 본 백로그는 ID가 부여된 과제만 추적한다.
---
@@ -25,7 +25,43 @@
---
## 2. 🟠 엣지 케이스 및 런타임 버그 (Edge-case Bugs — 6건 / 완료 5건)
## 2. 🟠 엣지 케이스 및 런타임 버그 (Edge-case Bugs — 3건)
### **B-16 (F-5 / P3): `make_client()` 매 실행 랜덤 `client_id` 발급으로 인한 영속 세션(Durable Session) 구성 불가**
- **현상**: `mqtt_common.py:258`에서 `client_id`를 매번 `uuid.uuid4().hex[:8]`로 생성하여, 브로커가 클라이언트 재연결을 식별할 수 없습니다 (`NATS_REPORT.md` §3.5 F-5).
- **파급 효과**: 네트워크 재연결 시 미수신 이벤트 유실 가능성이 발생합니다.
- **조치 방향**: B-15의 로컬 디스크 폴백을 표준 복원 경로로 확립하여 네트워크 세션 의존도를 제거하고, 필요 시 결정론적 식별자 규칙을 적용합니다.
### **B-17 (P1): `_load_dotenv` 오타/부재 경로 지정 시 Fail-Closed 및 공용 브로커 폴백 방지**
- **현상**: `MAM_ENV_FILE`이 명시적으로 지정되었으나 해당 경로가 존재하지 않는 경우, `_load_dotenv`가 조용히 리턴하여 `broker.hivemq.com` 공개 브로커로 폴백되는 위험.
- **파급 효과**: 설정 오타 발생 시 잡 이벤트와 프롬프트가 공개 브로커로 전송될 수 있음.
- **조치 방향 (2단 구조)**:
1. import 시점: 명시적 `MAM_ENV_FILE` 경로 부재 시 `logger.error` 기록 및 `_env_file_missing = True` 플래그 설정 (상위 임의 탐색 금지, import 예외 방지).
2. 접속 시점: `make_client()` 시 `_env_file_missing`이면 `RuntimeError`로 fail-closed 거부. 최종 호스트가 `broker.hivemq.com`인 경우 눈에 띄는 보안 경고 출력.
### **B-18 (P2): `.mam.env`와 `.env` 공존 및 다중 워크스페이스 경계 탐색 정합성**
- **현상**: `.mam.env`와 `.env`의 우선순위 및 워크스페이스 경계(`.agents`, `.git`) 탐색 과정에서 다중 워크스페이스 환경에서의 일관성 유지.
- **조치 방향**: `MAM_REAL_ROOT` -> `WORKSPACE_ROOT` -> 상위 경계 디렉터리 -> `cwd` 순서의 first-hit-wins 탐색 규칙 적용.
---
## 3. 🟡 오케스트레이션 최적화 과제 (Orchestration Optimizations — 1건)
### **O-5 (P2): NATS/MQTT 메시징 백플레인 고도화 및 `nats-server` 스파이크 검증 (Track 1 ~ Track 2)**
- **현상**: `NATS_REPORT.md` 아키텍처 실측 분석에 따라, `nats-py` 클라이언트 재작성(Option B)을 배제하고 `nats-server` 내장 MQTT 3.1.1 어댑터를 사설 전용 브로커로 채택하는 전략(Option C)이 확정되었습니다.
- **조치 방향**:
1. **Track 1 (스파이크 검증)**: 격리 환경에서 `nats-server -js`의 MQTT 3.1.1 호환성 실측 검증.
2. **Track 2 (보안/격리)**: 워크스페이스 지문 기반 토픽(`mam/<sha256[:12]>/jobs/...`) 및 무조건 `auth_token` 발급(G-11)을 적용하여 A-2 보안 결함 완전 종결.
3. **Track 3 (문서/설정)**: `MESSAGING.md`, `VERSIONS.md`, `.mam.env`에 `nats-server` 서빙 가이드 및 설정 동기화.
---
## 4. ⚪ 레거시 잔재 및 죽은 코드 (Legacy Remnants — 0건 — 전원 완료)
---
## 5. 🎉 완료된 과제 (Completed Tasks — 31건)
### **B-21 (✅ 완료 — `--agent` 플래그 표준화 및 `stop_session.sh`/`update_yaml_resumed.sh` 레지스트리 `agent_of_row` 폴백 통합)**
- **현상**:
@@ -63,38 +99,16 @@
### **B-14 (✅ 완료 — F-1 / P1): `publish_event.py` 브로커 장애 시 `return 2` 조기 탈출로 인한 65분 루프 정지**
- **현상**: `publish_event.py`에서 브로커 네트워크 장애 발생 시 `return 2`로 조기 종료되어, 뒤따르는 로컬 레지스트리 상태(`update_job_status(status=completed)`) 및 감사 로그(`append_event`, `registry.append_event`) 갱신이 누락되던 결함.
- **원 진단 (`publish_event.py:195-199`)**: `publish_event.py:195-199`에서 브로커 네트워크 장애 발생 시 `return 2`로 조기 종료되어, 뒤따르는 로컬 레지스트리 상태(`update_job_status(status=completed)`) 및 감사 로그(`append_event`, `registry.append_event`) 갱신이 누락되었습니다 (`NATS_REPORT.md` §3.1 실측 재현).
- **파급 효과**: `run_loop.sh`의 `wait_for_job()`은 로컬 디스크 파일의 상태가 `status=running`으로 멈춰있어 `max_wait=3900s`를 소진할 때까지 **65분간 루프가 완전 정지(Hang)**했습니다.
- **조치 결과 (완료 — 커밋 `c6b6c77`)**: 네트워크 발행 실패 여부와 무관하게 로컬 레지스트리 및 감사 로그를 100% 먼저 동기화한 후 `published=False`와 함께 `return 2`를 반환하도록 실행 순서를 재배치 (G-1 ~ G-4 회귀 가드로 봉인 완료).
### **B-15 (✅ 완료 — C1 & F-4 / P1): `job_subscriber.py` 디스크 폴백 부재 및 위임 경로 인프라 에러 오판정**
- **현상**: `job_subscriber.py`가 네트워크 큐만 대기하며 로컬 디스크 상태를 확인하지 않아 브로커 다운 시 블로킹되거나 인프라 에러가 작업 `error`로 오판정되던 결함.
- **조치 결과 (완료 — 커밋 `c6b6c77`)**: `_check_disk_fallback()`을 도입하여 로컬 디스크 상의 터미널 상태를 감지하면 합성 이벤트를 출력하고 즉시 `rc=0`으로 정상 종료하도록 개선. 브로커 인프라 접속 실패는 전용 `rc=3`으로 분리 (G-5 ~ G-10 회귀 가드로 봉인 완료).
### **B-16 (F-5 / P3): `make_client()` 매 실행 랜덤 `client_id` 발급으로 인한 영속 세션(Durable Session) 구성 불가**
- **현상**: `mqtt_common.py:258`에서 `client_id`를 매번 `uuid.uuid4().hex[:8]`로 생성하여, 브로커가 클라이언트 재연결을 식별할 수 없습니다 (`NATS_REPORT.md` §3.5 F-5).
- **파급 효과**: 네트워크 재연결 시 미수신 이벤트 유실 가능성이 발생합니다.
- **조치 방향**: B-15의 로컬 디스크 폴백을 표준 복원 경로로 확립하여 네트워크 세션 의존도를 제거하고, 필요 시 결정론적 식별자 규칙을 적용합니다.
### **B-17 (P1): `_load_dotenv` 오타/부재 경로 지정 시 Fail-Closed 및 공용 브로커 폴백 방지**
- **현상**: `MAM_ENV_FILE`이 명시적으로 지정되었으나 해당 경로가 존재하지 않는 경우, `_load_dotenv`가 조용히 리턴하여 `broker.hivemq.com` 공개 브로커로 폴백되는 위험.
- **파급 효과**: 설정 오타 발생 시 잡 이벤트와 프롬프트가 공개 브로커로 전송될 수 있음.
- **조치 방향 (2단 구조)**:
1. import 시점: 명시적 `MAM_ENV_FILE` 경로 부재 시 `logger.error` 기록 및 `_env_file_missing = True` 플래그 설정 (상위 임의 탐색 금지, import 예외 방지).
2. 접속 시점: `make_client()` 시 `_env_file_missing`이면 `RuntimeError`로 fail-closed 거부. 최종 호스트가 `broker.hivemq.com`인 경우 눈에 띄는 보안 경고 출력.
### **B-18 (P2): `.mam.env`와 `.env` 공존 및 다중 워크스페이스 경계 탐색 정합성**
- **현상**: `.mam.env`와 `.env`의 우선순위 및 워크스페이스 경계(`.agents`, `.git`) 탐색 과정에서 다중 워크스페이스 환경에서의 일관성 유지.
- **조치 방향**: `MAM_REAL_ROOT` -> `WORKSPACE_ROOT` -> 상위 경계 디렉터리 -> `cwd` 순서의 first-hit-wins 탐색 규칙 적용.
---
## 3. 🟡 오케스트레이션 최적화 과제 (Orchestration Optimizations — 추적 중 1건 / 완료 1건: O-5, O-6)
### **O-5 (P2): NATS/MQTT 메시징 백플레인 고도화 및 `nats-server` 스파이크 검증 (Track 1 ~ Track 2)**
- **현상**: `NATS_REPORT.md` 아키텍처 실측 분석에 따라 `nats-server` 내장 MQTT 3.1.1 어댑터를 사설 전용 브로커로 채택하는 전략(Option C)이 확정되었습니다.
- **조치 방향**:
1. **Track 1 (스파이크 검증)**: 격리 환경에서 `nats-server -js`의 MQTT 3.1.1 호환성 실측 검증.
2. **Track 2 (보안/격리)**: 워크스페이스 지문 기반 토픽(`mam/<sha256[:12]>/jobs/...`) 및 무조건 `auth_token` 발급(G-11)을 적용하여 A-2 보안 결함 완전 종결.
3. **Track 3 (문서/설정)**: `MESSAGING.md`, `VERSIONS.md`, `.mam.env`에 `nats-server` 서빙 가이드 및 설정 동기화.
- **원 진단 1 (`job_subscriber.py:172-251`)**: `job_subscriber.py:172-251`가 `queue.Empty` 시 네트워크 큐만 대기하며 로컬 디스크 상태를 확인하지 않아, 브로커 다운 시 120초 `idle_timeout` 동안 불필요하게 블로킹되었습니다 (`NATS_REPORT.md` §4.1 C1 챌린지 검증).
- **원 진단 2 (`multi-agent-mux-delegate-job:331-341`)**: `multi-agent-mux-delegate-job:331-341`에서 `wait "$sub_pid"`의 `sub_rc`를 직접 `job_status`로 매핑(`rc=1` -> `job_status="error"`)하여, 브로커 연결 실패로 인한 미포착 예외(`rc=1`) 발생 시 작업자의 정상 산출물이 존재하더라도 작업을 강제로 `"error"`로 오판정했습니다 (`NATS_REPORT.md` §3.4 F-4).
- **파급 효과**: 브로커 장애 시 작업자가 작업을 정상 완수했음에도 루프가 2분 이상 지연되거나 거짓 실패(False Failure)가 발생했습니다.
- **조치 결과 (완료 — 커밋 `c6b6c77`)**: `_check_disk_fallback()`을 도입하여 로컬 디스크(`load_job`/`read_logged_status`) 상의 터미널 상태를 감지하면 `source: disk-fallback` 합성 이벤트를 출력하고 3초 내 즉시 `rc=0`으로 정상 종료하도록 개선. 브로커 인프라 접속 실패는 전용 `rc=3` (`job_status="broker_unavailable"`)으로 분리 (G-5 ~ G-10 회귀 가드로 봉인 완료).
### **O-6 (✅ 완료 — P1): 원격 프로덕션 브로커 자산 정본화 및 `nats-docker` 서브모듈 분리**
- **내용**:
@@ -149,48 +163,6 @@
- **중단 기준**: M2 이후에도 팬아웃이 29 → 20 이하로 떨어지지 않으면 중단하고 잔여 단계를 재검토합니다.
- **검증 상태**: Rev.2 프로토타입 기준 전체 회귀 **162 passed (회귀 0)**, 변이 6/6 검출, 배포 스위트 25/25, `py_compile` 통과.
---
## 2. 🟠 엣지 케이스 및 런타임 버그 (Edge-case Bugs — 3건)
### **B-14 (F-1 / P1): `publish_event.py` 브로커 장애 시 `return 2` 조기 탈출로 인한 65분 루프 정지**
- **현상**: `publish_event.py:195-199`에서 브로커 네트워크 장애 발생 시 `return 2`로 조기 종료되어, 뒤따르는 로컬 레지스트리 상태(`update_job_status(status=completed)`) 및 감사 로그(`append_event`, `registry.append_event`) 갱신이 누락됩니다 (`NATS_REPORT.md` §3.1 실측 재현).
- **파급 효과**: `run_loop.sh`의 `wait_for_job()`은 로컬 디스크 파일의 상태가 `status=running`으로 멈춰있어 `max_wait=3900s`를 소진할 때까지 **65분간 루프가 완전 정지(Hang)**합니다.
- **조치 방향 (Track 0 Step 1)**: 네트워크 발행 실패 시에도 `append_event`와 `update_job_status`를 온전히 완수한 후 `published=False`를 기록하고 `return 2`를 반환하도록 실행 순서를 재배치합니다 (G-1 ~ G-4 회귀 가드 신설).
### **B-15 (C1 & F-4 / P1): `job_subscriber.py` 디스크 폴백 부재 및 위임 경로 인프라 에러 오판정**
- **현상**:
1. `job_subscriber.py:172-251`가 `queue.Empty` 시 네트워크 큐만 대기하며 로컬 디스크 상태를 확인하지 않아, 브로커 다운 시 120초 `idle_timeout` 동안 불필요하게 블로킹됩니다 (`NATS_REPORT.md` §4.1 C1 챌린지 검증).
2. `multi-agent-mux-delegate-job:331-341`에서 `wait "$sub_pid"`의 `sub_rc`를 직접 `job_status`로 매핑(`rc=1` -> `job_status="error"`)하여, 브로커 연결 실패로 인한 미포착 예외(`rc=1`) 발생 시 작업자의 정상 산출물이 존재하더라도 작업을 강제로 `"error"`로 오판정합니다 (`NATS_REPORT.md` §3.4 F-4).
- **파급 효과**: 브로커 장애 시 작업자가 작업을 정상 완수했음에도 루프가 2분 이상 지연되거나 거짓 실패(False Failure)가 발생합니다.
- **조치 방향 (Track 0 Step 2 & 3)**:
1. `job_subscriber.py` 대기 루프에 로컬 디스크(`load_job`/`read_logged_status`) 상태 폴백을 도입하여 디스크 완료 감지 시 `source: disk-fallback` 합성 이벤트를 출력하고 3초 내 `rc=0`으로 조기 정상 종료합니다.
2. 브로커 인프라 연결 실패에 전용 `rc=3`을 부여하고 `job_status="broker_unavailable"` 분기로 분리하여 작업 결과와 인프라 에러를 엄격히 격리합니다 (G-5 ~ G-10 회귀 가드 신설).
### **B-16 (F-5 / P3): `make_client()` 매 실행 랜덤 `client_id` 발급으로 인한 영속 세션(Durable Session) 구성 불가**
- **현상**: `mqtt_common.py:258`에서 `client_id`를 매번 `uuid.uuid4().hex[:8]`로 생성하여, 브로커가 클라이언트 재연결을 식별할 수 없습니다 (`NATS_REPORT.md` §3.5 F-5).
- **파급 효과**: 네트워크 재연결 시 미수신 이벤트 유실 가능성이 발생합니다.
- **조치 방향**: B-15의 로컬 디스크 폴백을 표준 복원 경로로 확립하여 네트워크 세션 의존도를 제거하고, 필요 시 결정론적 식별자 규칙을 적용합니다.
---
## 3. 🟡 오케스트레이션 최적화 과제 (Orchestration Optimizations — 1건)
### **O-5 (P2): NATS/MQTT 메시징 백플레인 고도화 및 `nats-server` 스파이크 검증 (Track 1 ~ Track 2)**
- **현상**: `NATS_REPORT.md` 아키텍처 실측 분석에 따라, `nats-py` 클라이언트 재작성(Option B)을 배제하고 `nats-server` 내장 MQTT 3.1.1 어댑터를 사설 전용 브로커로 채택하는 전략(Option C)이 확정되었습니다.
- **조치 방향**:
1. **Track 1 (스파이크 검증)**: 격리 환경에서 `nats-server -js`의 MQTT 3.1.1 호환성(Retained 터미널 이벤트 전달 S-3, QoS 1 ACK S-4, Subject 라우팅 S-5 등 9종 매트릭스 S-1 ~ S-9) 실측 검증.
2. **Track 2 (보안/격리)**: 워크스페이스 지문 기반 토픽(`mam/<sha256[:12]>/jobs/...`) 및 무조건 `auth_token` 발급(G-11)을 적용하여 A-2 보안 결함 완전 종결.
3. **Track 3 (문서/설정)**: `MESSAGING.md`, `VERSIONS.md`, `.mam.env`에 `nats-server` 서빙 가이드 및 설정 동기화.
---
## 4. ⚪ 레거시 잔재 및 죽은 코드 (Legacy Remnants — 0건 — 전원 완료)
---
## 5. 🎉 완료된 과제 (Completed Tasks — 24건)
### **B-9 (P4-1): `LOGS_DIR` import 시점 cwd 고정 해소** — ✅ 완료
- `mqtt_common.LOGS_DIR` 이 모듈 import 시점의 `os.getcwd()` 로 절대화되어, 이후 프로세스가 `chdir` 하면 감사 로그가 옛 경로에 계속 쌓이던 문제를 해소했습니다(실측 재현). 경로 해석을 호출 시점으로 미루는 `get_logs_dir()` 를 도입하고 모듈 전역 대입을 제거했습니다.
- **하위 호환**: PEP 562 모듈 `__getattr__` 로 `mqtt_common.LOGS_DIR` 속성 접근을 그대로 유지하되 동적으로 평가합니다. 저장소 내 `from mqtt_common import LOGS_DIR` 사용은 0건임을 전수 확인했으므로 호환 표면이 100% 덮입니다.
@@ -206,6 +178,7 @@
- **결함 교정 (P1/C1/C2)**: 인자 파서의 `$@` 소진에 대비해 최상단에서 `MAM_LOOP_ARGV` 배열 포획, `export MAM_LOOP_FREEZE_OWNED="1"` 로 정리 게이트 누수 차단, `log_*` 정의 전 구간 `echo` 직접 사용으로 폴백 시의 구문 오류 크래시를 원천 방지했습니다.
- 정리 로직은 새 트랩을 추가하지 않고 기존 `_mam_release_guard` 를 확장했습니다 — `trap … EXIT` 중복 설치는 기존 핸들러를 조용히 대체하며(실측), 이는 B-12 와 동일한 계열의 사고입니다.
- 회귀 가드 5종(`test_b13_reexec_preserves_original_argv`, `test_b13_freeze_survives_broken_wrapper`, `test_b13_freeze_dir_is_outside_the_skill_tree`, `test_b13_release_guard_cleans_up_and_releases_lock`, `test_b13_no_freeze_switch_disables_reexec`)을 신설하고 뮤테이션 M0~M6 으로 방어력을 검증했습니다.
- v4.4.0(Issue #5 Phase 4)에서 freeze 스냅샷을 기본 경로에서 철거, `MAM_LOOP_FREEZE=1` 롤백 스위치만 잔존 (`docs/contracts/issue-5/phase4-freeze-removal.md`).
### **B-10 (P3-2): `agent_identities` tier-3 신원 캐시 완전 제거 (Option A)** — ✅ 완료
- 저장소 전체에 `agent_identities` 쓰기 코드가 0건임을 재확인하고(라이브 `.db` 최상위 키에도 부재), 구조적으로 히트 불가였던 읽기 경로 3곳을 제거했습니다 — `workspace_uuid.py` tier-3 폴백(28줄), `reconcile.sh` drift D 진단(35줄), `stop_session.sh` purge 시 캐시 소거(6줄), 관련 주석 3곳. UUID 해결은 tier-1(per-row own id) → tier-2(어댑터 `discover()`) 2단계로 단순화되었습니다.
@@ -244,12 +217,6 @@
- `.agents/skills/lib.sh` 내 `find_workspace_uuid` 및 `verify_session_uuid` 함수를 갱신하여 `orchestrator_uuids` 리스트에 포함된 오케스트레이터 대화 ID를 서브 에이전트(`canary-projects-multi-agent-mux-creator-agy`)의 `find_workspace_uuid` 및 `capture_conversation_id` 탐색 대상에서 100% 스킵(Skip)하는 배제 게이트를 수립하여 오케스트레이터 대화 DB 오염 및 SQLite DB 락 결함을 원천 해결했습니다.
- 전용 회귀 테스트 스위트 `tests/test_orc_onboard.py` (40/40 PASS)를 작성하여 입증했습니다.
### **P0-2 (O-2): 동일 워크스페이스 내 중복 루프 기동 방지 원자적 락 및 마커 소유권 대조 삭제 조치** — ✅ 완료
- [`.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` (noclobber) 기반 원자적 락 생성 및 마커 임시 쓰기+Atomic Rename 구조를 구축했습니다.
- 마커 상의 `pid` + `lstart`(프로세스 시작시각) 신원 대조 검증을 수행하여, 동일 워크스페이스 내 중복 루프 기동 시 이를 감지하고 안전하게 기동을 차단합니다.
- 종료 트랩(`_mam_release_guard`) 시 마커 파일 상의 `pid` 및 `lstart` 가 자기 자신과 100% 일치할 때만 마커를 삭제하도록 소유권 대조 삭제를 수립하여, 타 루프 인스턴스의 마커를 실수로 제거하여 O-3 가드레일을 무력화시키는 결함을 원천 차단했습니다.
- 전용 회귀 테스트 스위트 `tests/test_o2_race_free_lock.py` (22/22 PASS) 및 전체 회귀 테스트 스위트 (46/46 PASS)를 작성하여 입증했습니다.
### **P0-1 (B-7): `run_loop.sh` 루프 기동 외곽 diff 누락 및 신규 미추적 파일 캡처 결함 조치** — ✅ 완료
- `.agents/skills/multi-agent-mux-loop/scripts/diff_collect.sh` 헬퍼 모듈을 작성하여, `run_loop.sh` 가 어느 CWD 에서 기동되더라도 항상 `$REPO_ROOT` 기반으로 안전하게 이동하여 `git diff` 를 수행하도록 CWD 독립성을 확립했습니다.
- Git 인덱스를 오염시키는 `git add -N` 대신, `git ls-files -o --exclude-standard -z` 와 `git diff --no-index --binary /dev/null "$f"` 구문을 조합하여 에이전트가 **새로 생성한 신규 미추적 파일(Untracked Files)까지 100% diff에 안전하게 병합**시키는 기법을 구현했습니다.
@@ -270,11 +237,16 @@
- 멀티에이전트 자율 오케스트레이션 루프(`run_loop.sh --plan --all-reviewer`)를 통해 Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3자에 의해 구현 및 교차 검증 후 **`[VERDICT: PASS]` (만장일치 통과)** 되었습니다.
- 전용 회귀 테스트 스위트 `tests/test_b4_session_created.py` (21/21 PASS)를 작성하여 입증했습니다.
### **O-2: 동일 워크스페이스 내 중복 루프 기동 방지 락 (Race-Free Mutex & Ownership)** — ✅ 완료
### **O-2 (P0-2): 동일 워크스페이스 내 중복 루프 기동 방지 락 (Race-Free Mutex & Ownership)** — ✅ 완료
- `loop_lock.sh` 독립 락 모듈(`mam_acquire_loop_lock` / `mam_release_loop_lock`)을 생성하고 하드링크(`ln`) 기반 원자적 패키징 쓰기를 구현하여 빈/파티셜 마커 노출 및 Livelock 을 원천 차단했습니다.
- `pid` + `lstart`(프로세스 시작 시각) 기반 신원 검증 로직을 적용하여 PID Rollover 오판을 차단하고, stale 락 회수 시 마커 규약과 동일한 `steal_lock` (`$marker.steal`) 신원 인수 디스패처를 구축하여 고아 디렉터리로 인한 영구 워크스페이스 데드락 결함을 근본 해결했습니다.
- 이전 Rev.1 레거시 `.steal` 디렉터리 자동 정리 업그레이드 경로 및 소유권 검증 기반 원자적 해제(`mam_release_loop_lock`)를 통합하여 이차 루프 종료 시 소유권 없는 마커 파기를 차단하고 O-3 위임 가드를 완벽 보호했습니다.
- 전용 테스트 스위트 `tests/test_o2_race_free_lock.py` (22/22 PASS) 및 전체 회귀 테스트 스위트 (204/204 PASS)를 작성하여 입증했습니다.
- **Rev.1 (P0-2) 선행 조치**:
- [`.agents/skills/multi-agent-mux-loop/scripts/loop_lock.sh`](.agents/skills/multi-agent-mux-loop/scripts/loop_lock.sh) 헬퍼 모듈을 작성하여, `set -C` (noclobber) 기반 원자적 락 생성 및 마커 임시 쓰기+Atomic Rename 구조를 구축했습니다.
- 마커 상의 `pid` + `lstart`(프로세스 시작시각) 신원 대조 검증을 수행하여, 동일 워크스페이스 내 중복 루프 기동 시 이를 감지하고 안전하게 기동을 차단합니다.
- 종료 트랩(`_mam_release_guard`) 시 마커 파일 상의 `pid` 및 `lstart` 가 자기 자신과 100% 일치할 때만 마커를 삭제하도록 소유권 대조 삭제를 수립하여, 타 루프 인스턴스의 마커를 실수로 제거하여 O-3 가드레일을 무력화시키는 결함을 원천 차단했습니다.
- 전용 회귀 테스트 스위트 `tests/test_o2_race_free_lock.py` (22/22 PASS) 및 전체 회귀 테스트 스위트 (46/46 PASS)를 작성하여 입증했습니다.
### **O-3: 조건부 오케스트레이션 위임 가드 (Invocation-Aware Scoped Guard)** — ✅ 완료
- Normal Mode(직접 소스 수정)와 Loop Active Mode(`/multi-agent-mux-loop` 인보크 시 `run_loop.sh` 자율 위임)의 역할 경계를 명확히 구분하는 스킬 인터셉터 가드레일(`.agents/hooks.json` & `.agents/hooks/loop_delegation_guard.sh`)을 구축했습니다.
@@ -333,6 +305,9 @@
- 전용 단위 테스트 `tests/test_sanitize_and_mock_errors.py` (3/3 PASS) 및 전체 회귀 테스트 스위트 (**256/256 PASS, 0 Failures / 0 Errors**)를 검증 완료했습니다.
- 멀티에이전트 자율 오케스트레이션 루프(`run_loop.sh --all-reviewer`)를 통해 Creator(`agy`, Job: `94bceedd`) 및 Reviewer(`cline`, Job: `14187d43`) 교차 검증 만장일치 **`[VERDICT: PASS]`** 를 달성했습니다.
### **B-8 (P1-2): agy 주입 시 `return 0` 우회 제거 및 제출 검증 루프 이관** — ✅ 완료
- agy 주입 시 `return 0` 우회 제거 및 제출 검증 루프 이관 (`tests/test_b8_send_keys_verification.py` 1/1 PASS).
---
## 6. 🧭 우선순위 실행 로드맵 (Prioritized Execution Roadmap)
+19 -3
View File
@@ -1,5 +1,7 @@
# Messaging System Technical Analysis & Architecture Report
Applies to: MAM v4.4.0
This report provides a comprehensive, deep-dive analysis of the messaging system implemented in the `multi-agent-mux-delegate-job` skill. It covers the MQTT broker architecture, event protocols, job lifecycles, codebase internals, cross-system integration, and a list of known limitations along with production recommendations.
---
@@ -235,7 +237,11 @@ stateDiagram-v2
## 4. Code Internals Analysis
The core implementation logic of the delegation system resides within the Python package `.agents/skills/lib_py/delegation/` (`mqtt_common.py`, `job_subscriber.py`, `engine.py`, `cli.py`, `registry.py`, `publish_event.py`, etc.). The entry scripts located in `.agents/skills/multi-agent-mux-delegate-job/scripts/*.py` (`registry.py`, `publish_event.py`, `job_subscriber.py`, `mqtt_common.py`) serve as wire-compatible shims that delegate directly into `lib_py/delegation/`.
### 4.1 `registry.py` & `lib.sh` (Locking & Atomicity)
* **Underlying Module**: `.agents/skills/lib_py/delegation/registry.py` (shim: `.agents/skills/multi-agent-mux-delegate-job/scripts/registry.py`) and `.agents/skills/lib.sh`.
Two concurrency control schemes co-exist in this workspace to coordinate state modification:
1. **`lib.sh::atomic_dump_yaml()`**: Used for workspace-wide herdr session inventory (`agent-sessions.yaml`).
@@ -249,6 +255,8 @@ Two concurrency control schemes co-exist in this workspace to coordinate state m
---
### 4.2 `publish_event.py` (Retries and Handshakes)
* **Underlying Module**: `.agents/skills/lib_py/delegation/publish_event.py` (shim: `.agents/skills/multi-agent-mux-delegate-job/scripts/publish_event.py`).
The publisher script enforces robust error handling and fail-safe local persistence:
* **Fresh Connection Pattern**: Instead of maintaining a persistent socket connection (which is susceptible to socket timeouts or channel leaks), `publish_event.py` opens a fresh socket, completes the authentication/TLS handshake, publishes a single QoS 1 event, waits for `PUBACK`, and closes the connection.
* **Guaranteed Disk Synchronization (B-14)**: Before attempting any network transmission over MQTT, `publish_event.py` records the event into the local registry (`append_event` and `update_job_status`). If the broker is unreachable or network publish fails, local audit logs and state machine files remain 100% accurate. The script returns exit code `2` at the very end to signal a transport failure without corrupting local state.
@@ -262,6 +270,8 @@ The publisher script enforces robust error handling and fail-safe local persiste
---
### 4.3 `job_subscriber.py` (Timers and Queue Semantics)
* **Underlying Module**: `.agents/skills/lib_py/delegation/job_subscriber.py` (shim: `.agents/skills/multi-agent-mux-delegate-job/scripts/job_subscriber.py`).
The subscriber acts as the central execution watchdog:
* **Queue Serialization**: Uses a thread-safe `queue.Queue` internally. The Paho MQTT callback thread adds messages to the queue, and the main thread processes them sequentially. This separates network I/O from state machine validation.
* **Local Disk Fallback Verification (B-15)**: On initial startup and upon any broker connection failure, `_check_disk_fallback()` immediately queries local job records (`.mam/jobs/<job_id>.json`) and audit logs (`status.json`). If the target job has already reached a terminal state locally, the subscriber completes immediately without waiting on a dead broker.
@@ -286,6 +296,8 @@ The subscriber acts as the central execution watchdog:
---
### 4.4 `mqtt_common.py` (Logging, Env Vars & Config Resolution)
* **Underlying Module**: `.agents/skills/lib_py/delegation/mqtt_common.py` (shim: `.agents/skills/multi-agent-mux-delegate-job/scripts/mqtt_common.py`).
* **Log Routing Isolation**: Configured via `setup_logging()`. The root logger is bound to `sys.stderr`. This preserves the standard output stream (`stdout`) exclusively for clean JSON-lines payloads, enabling downstream bash tools to pipeline event feeds cleanly (e.g., `job_subscriber.py ... | jq`).
* **Environment Variable Dictionary**:
The system parses and supports the following 10 configuration variables:
@@ -334,8 +346,12 @@ graph LR
```
### 5.1 Orchestration Wrappers (`multi-agent-mux-*`)
The system integrates a Compare-And-Swap (CAS) state transition engine implemented in `.agents/skills/lib_py/delegation/engine.py` (`MAM_ENGINE_CAS=1` by default). The engine stores a fresh opaque `dispatch_token` (`uuid4().hex`) when an attempt starts through `claim` or `redispatch`. Callers such as inferred completion supply `expected_dispatch_token`, which the engine compares under the registry lock before committing. This precondition is optional; ordinary publisher status updates do not supply it. Committed transitions are ordered separately by the monotonic `transition_seq` counter. The Python core implementation is guarded by the `MAM_DELEGATION_PY=1` feature flag (enabled by default), which provides a transparent fallback rollback switch to legacy shell/shim execution paths if set to `0`.
1. **`multi-agent-mux-delegate-job (submit)`**:
* Registers a job, spawns `job_subscriber.py` to capture standard output streams to `.mam/jobs/<job_id>.subscriber.out`, and sleeps for `1` second.
* Registers a job, spawns `job_subscriber.py` to capture standard output streams to `.mam/jobs/<job_id>.subscriber.out` (loop iterations use `.mam/jobs/<job_id>.iter_<n>_<role>.subscriber.out`).
* Attempts a subscriber readiness handshake by polling for `SUBSCRIBED ` every 0.2 seconds for up to 25 iterations. If readiness is not observed before the polling budget expires, it warns and proceeds with agent launch. Early subscriber exits with status 0 or 3 also permit continuation.
* Boots the agent pane in herdr:
```bash
herdr new-session -d -s "$sess" -c "$WORKDIR" \
@@ -371,8 +387,8 @@ graph LR
1. **[Implemented] Migrate to SQLite WAL Backend**:
The `agent-sessions.yaml` locking mechanism in `lib.sh` has been upgraded to use a SQLite database (`agent-sessions.db`) configured with Write-Ahead Logging (`PRAGMA journal_mode=WAL`). The YAML file is now only updated as a finalized archive when a session reaches a terminal state (`stopped`, `terminated`, `archived`), eliminating `flock` contention during active session updates.
**Architecture Decision Note**: This means `agent-sessions.yaml` is **no longer a real-time view** of currently `running` sessions. We have explicitly accepted the trade-off of giving up real-time text readability of running sessions in favor of robust concurrency and solving NFS flock limits. Tooling and status checks must now query the SQLite DB to observe live `running` states.
2. **Implement Signature-Based Payload Verification**:
Rather than sending a plaintext token, utilize HMAC signatures. The delegator and worker share a secret key; the worker publishes a signature of the payload (e.g. `HMAC-SHA256(secret_key, payload_bytes)`). The subscriber validates the signature, preventing token interception.
2. **[Implemented] Implement Signature-Based Payload Verification**:
HMAC payload verification has been implemented using SHA-256 signatures (`auth_token` generation and verification). The delegator and worker share a secret key; the publisher generates an HMAC-SHA256 signature over the payload bytes and timestamp, which is attached as `data.hmac_sig` on the wire and verified by the subscriber (see [§2.4 Integrity and Authentication Verification (HMAC-SHA256 Signatures)](#24-integrity-and-authentication-verification-hmac-sha256-signatures)).
3. **Enforce Mandatory NATS Broker-Side Authentication, JetStream and ACLs**:
Standardize on private `nats-server` with JetStream and account-level ACL isolation (`nats-docker/docker/nats.conf`). For public WAN exposures, terminate TLS v1.3 (`MQTT_TLS=true`) over port `8883`.
4. **Build Auto-Reconnecting Subscriber Loops**:
+20 -5
View File
@@ -2,7 +2,7 @@
Herdr와 MQTT 브로커를 기반으로 구축된 고신뢰성 **다중 에이전트 오케스트레이션 및 메시징 백플레인** 프레임워크입니다. `claude`, `agy`, `hermes`, `grok`, `opencode`, `codex` 등 다중 LLM 백엔드 에이전트 전반에 걸쳐 장시간 수행되는 작업(코드 생성, 리팩토링, 보안 검토 등)을 조정, 격리 및 감사할 수 있도록 설계되었습니다.
[![Version: v4.2.0](https://img.shields.io/badge/version-v4.2.0-blue.svg)](VERSIONS.md)
[![Version: v4.4.0](https://img.shields.io/badge/version-v4.4.0-blue.svg)](VERSIONS.md)
---
@@ -27,12 +27,12 @@ Herdr와 MQTT 브로커를 기반으로 구축된 고신뢰성 **다중 에이
* **`multi-agent-mux-resume`**: 디스크 또는 캐시에서 특정 워크스페이스의 세션 UUID를 조회하여 기존 대화 상태(`claude -r <uuid>`, `agy --conversation <uuid>`, `hermes --resume <uuid>`, `grok --resume <uuid>`, `opencode --session <uuid>`, `codex resume <uuid>`) 그대로 세션을 복구하고 재개합니다.
* **`multi-agent-mux-status`**: 활성화된 모든 세션의 실시간 작동 상태를 쿼리하여 PID 정합성, 실행 명령 포맷, herdr 실제 상태와 데이터베이스 간의 동기화 드리프트를 감지합니다.
* **`multi-agent-mux-monitor`**: 백그라운드 Reconcile 프로세스로 실행되어, 실시간 herdr 세션 변화를 모니터링하고 `.mam/agent-sessions.yaml` 메타데이터 파일에 상태를 동기화합니다.
* **`multi-agent-mux-delegate-job`**: 태스크를 비동기식 독립 잡으로 위임 및 관리하는 핵심 모듈입니다:
* **`multi-agent-mux-delegate-job`**: 태스크를 비동기식 독립 잡으로 위임 및 관리하는 핵심 모듈입니다 (본체 구현은 `.agents/skills/lib_py/delegation/`에 위치하며, `scripts/*.py`는 하위 호환 shim):
* `registry.py`: 파일 락(`fcntl`)을 활용해 경쟁 조건 없이 잡을 원자적으로 등록 및 점유(claim)합니다.
* `job_subscriber.py`: MQTT 백플레인 채널을 구독하여 실시간 상태 이벤트를 수집하고 이를 감사 로그(audit trail)에 기록합니다.
* `publish_event.py`: 실행 상태 전환 및 세부 에러 내용을 워크스페이스 스크립트에서 백플레인으로 발행합니다.
* `mqtt_common.py`: 브로커 접속 규칙, 크레덴셜 인증 및 HMAC 서명 기능을 공통 관리합니다.
* **`multi-agent-mux-loop`**: Planner, Creator, Reviewer 3자 간의 자율적인 계획-실행-교차검증 반복 순환 루프를 구동합니다.
* **`multi-agent-mux-loop`**: Planner, Creator, Reviewer 3자 간의 자율적인 계획-실행-교차검증 반복 순환 루프를 구동합니다 (Python 루프 런타임 `lib_py.loop`, eager-import 불변 런타임, strict verdict parser 기반).
* **`multi-agent-mux-orc-onboard`**: 오케스트레이터 UUID를 레지스트리에 격리 등록하여 서브 에이전트 자동 탐색 오염을 방지합니다.
---
@@ -146,6 +146,10 @@ sequenceDiagram
│ ├── MULTI_AGENT_RULES.ko.md # 에이전트 역할 행동 강령 (한국어 백업)
│ └── skills/ # 코어 오케스트레이션 셸 스크립트 및 라이브러리
│ ├── lib.sh # 공통 오케스트레이션 셸 함수 라이브러리
│ ├── lib_py/ # 파이썬 코어 오케스트레이션 엔진
│ │ ├── agents/ # 멀티 에이전트 CLI 수명 주기 어댑터
│ │ ├── delegation/ # 비동기 잡 위임 및 CAS 상태 전이 엔진
│ │ └── loop/ # 자율 계획-실행-교차검증 루프 런타임
│ ├── multi-agent-mux-create/
│ ├── multi-agent-mux-stop/
│ ├── multi-agent-mux-resume/
@@ -153,7 +157,7 @@ sequenceDiagram
│ ├── multi-agent-mux-monitor/
│ ├── multi-agent-mux-delegate-job/
│ │ ├── requirements.txt # 파이썬 의존성 패키지 선언
│ │ └── scripts/ # 파이썬 기반 백플레인 구현체
│ │ └── scripts/ # 하위 호환 shim 스크립트 (Python)
│ ├── multi-agent-mux-loop/
│ └── multi-agent-mux-orc-onboard/
├── .mam/ # Multi-Agent Mux 메타데이터 (git-ignored)
@@ -167,10 +171,21 @@ sequenceDiagram
│ ├── install.sh # 원격/네트워크 인스톨러 스크립트
│ ├── update.sh # 업데이트 헬퍼 스크립트
│ └── remove.sh # 삭제/언인스톨 헬퍼 스크립트
├── docs/ # 기술 규격서, 가이드 및 아키텍처 계약 문서
│ ├── contracts/ # 이슈/백플레인 계약 및 마이그레이션 로드맵
│ ├── MAM_WEB_PTY_BRIDGE_PLAN.md # Web PTY 터미널 브리지 설계 계획서
│ ├── NEW_AGENT_INTEGRATION_GUIDE.md # 신규 AI 코딩 에이전트 연동 가이드
│ └── OPENCODE_OLLAMA_GUIDE.md # OpenCode 인터프리터 + Ollama 연동 가이드
├── nats-docker/ # 사설 NATS 브로커 배포 서브모듈
├── tests/ # 종합 회귀 테스트 스위트 (32개 모듈)
├── AGENTS.md # 에이전트 행동 지침 및 오케스트레이터 스코프 가드
├── BOOTSTRAP.ko.md # 프로젝트 초기 설치 가이드 (한국어 백업)
├── BOOTSTRAP.md # 프로젝트 초기 설치 및 검증 상세 가이드
├── IMPROVEMENTS.md # 이슈 백로그 및 완료된 아키텍처 과제 추적 원장
├── MESSAGING.md # MQTT 메시징 프로토콜 와이어 규격서
└── README.md # 프로젝트 대표 소개 파일
├── README.ko.md # 프로젝트 대표 소개 파일 (한국어)
├── README.md # 프로젝트 대표 소개 파일 (영문 원본)
└── VERSIONS.md # 릴리스 노트 및 4-way 락스텝 버전 원장
```
---
+22 -6
View File
@@ -2,7 +2,7 @@
An advanced, high-reliability **Multi-Agent Orchestration & Messaging Backplane** framework built on Herdr and MQTT. It is designed to coordinate, isolate, and audit long-running agent tasks (such as code generation, refactoring, and security reviews) across multiple LLM backend clients (`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`).
[![Version: v4.2.0](https://img.shields.io/badge/version-v4.2.0-blue.svg)](VERSIONS.md)
[![Version: v4.4.0](https://img.shields.io/badge/version-v4.4.0-blue.svg)](VERSIONS.md)
---
@@ -45,12 +45,12 @@ All orchestration functionalities are structured under the `.agents/skills/` dir
* **`multi-agent-mux-resume`**: Restores stopped sessions by resolving workspace UUIDs from disk or cache, and invokes the underlying agent using session-resume parameters (e.g., `claude -r <uuid>`, `agy --conversation <uuid>`, `hermes --resume <uuid>`, `grok --resume <uuid>`, `opencode --session <uuid>`, or `codex resume <uuid>`).
* **`multi-agent-mux-status`**: Queries the running states of all active sessions, detecting PID mismatches, command signatures, and drifts between actual herdr instances and the registry database.
* **`multi-agent-mux-monitor`**: A long-running reconcile worker that dynamically monitors herdr sessions and synchronizes states to `.mam/agent-sessions.yaml`.
* **`multi-agent-mux-delegate-job`**: The core asynchronous task distribution module containing:
* **`multi-agent-mux-delegate-job`**: The core asynchronous task distribution module (core implementation in `.agents/skills/lib_py/delegation/`; `scripts/*.py` serves as compatibility shims):
* `registry.py`: Atomically registers and claims jobs using file advisory locks (`fcntl`).
* `job_subscriber.py`: Connects to the MQTT backplane, captures live events, and appends them to audit trails.
* `publish_event.py`: Emits execution status transitions and error details from workspace scripts.
* `mqtt_common.py`: Manages connection policies, authentication, and HMAC signing.
* **`multi-agent-mux-loop`**: Autonomous planning-execution-review orchestration loop across Planner, Creator, and Reviewers until unanimous consensus.
* **`multi-agent-mux-loop`**: Autonomous planning-execution-review orchestration loop across Planner, Creator, and Reviewers until unanimous consensus (driven by Python loop runtime in `lib_py.loop`, eager-import immutable runtime, strict verdict parser).
* **`multi-agent-mux-orc-onboard`**: Helper to register and isolate orchestrator session UUIDs to prevent sub-agent discovery capture.
---
@@ -164,6 +164,10 @@ To ensure communication integrity across public MQTT brokers, the backplane inte
│ ├── MULTI_AGENT_RULES.ko.md # Agent roles, snapshottings, and execution charter (Korean)
│ └── skills/ # Core orchestration shell wrappers & libraries
│ ├── lib.sh # Shared orchestration library
│ ├── lib_py/ # Python core orchestration engine
│ │ ├── agents/ # Multi-agent CLI lifecycle adapters
│ │ ├── delegation/ # Asynchronous delegation & CAS state engine
│ │ └── loop/ # Autonomous planning-execution-review loop runtime
│ ├── multi-agent-mux-create/
│ ├── multi-agent-mux-stop/
│ ├── multi-agent-mux-resume/
@@ -171,7 +175,7 @@ To ensure communication integrity across public MQTT brokers, the backplane inte
│ ├── multi-agent-mux-monitor/
│ ├── multi-agent-mux-delegate-job/
│ │ ├── requirements.txt # Python dependency declaration
│ │ └── scripts/ # Core backplane implementation (Python)
│ │ └── scripts/ # Wire-compatibility shims (Python)
│ ├── multi-agent-mux-loop/
│ └── multi-agent-mux-orc-onboard/
├── .mam/ # Multi-Agent Mux metadata (git-ignored)
@@ -185,9 +189,21 @@ To ensure communication integrity across public MQTT brokers, the backplane inte
│ ├── install.sh # Remote/Network installer script
│ ├── update.sh # Updater script
│ └── remove.sh # Uninstaller script
├── docs/ # Specifications, guides, and architectural contracts
│ ├── contracts/ # Issue/backplane contracts and migration roadmaps
│ ├── MAM_WEB_PTY_BRIDGE_PLAN.md # Web PTY terminal bridge design plan
│ ├── NEW_AGENT_INTEGRATION_GUIDE.md # Guide for integrating new AI coding agents
│ └── OPENCODE_OLLAMA_GUIDE.md # OpenCode interpreter + Ollama integration guide
├── nats-docker/ # Private NATS broker deployment submodule
├── tests/ # Comprehensive test suite (32 modules)
├── AGENTS.md # Behavioral guidelines and orchestrator scope guards
├── BOOTSTRAP.ko.md # Installation and verification guide (Korean)
├── BOOTSTRAP.md # Detailed installation and verification guide
├── MESSAGING.md # MQTT wire protocol specification
└── README.md # Project introduction and overview (this file)
├── IMPROVEMENTS.md # Backlog tracking issues and completed architectural tasks
├── MESSAGING.md # MQTT wire protocol specification and internals
├── README.ko.md # Project introduction and overview (Korean)
├── README.md # Project introduction and overview (this file)
└── VERSIONS.md # Release notes and 4-way lockstep version ledger
```
---
+59 -16
View File
@@ -6,36 +6,79 @@
## 📌 현재 버전 개요 (Current Release)
- **프레임워크 버전**: `v4.3.0`
- **최신 릴리스 일시**: 2026-09-06 (KST)
- **기준 브랜치**: `refactor`
- **프레임워크 버전**: `v4.4.0`
- **최신 릴리스 일시**: 2026-09-07 (KST)
- **기준 브랜치**: `main` (`refactor` 병합 완료)
- **핵심 아키텍처**:
- **Codex First-Class Agent Integration**: OpenAI Codex CLI(`codex`)를 6번째 1급 에이전트 백엔드로 전면 통합 (`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`)
- **Class A Codex Lifecycle & State DB Resolution**: 동적 `state_*.sqlite` SQLite 인덱스 및 date-nested rollout jsonl 폴백 지원, `--dangerously-bypass-approvals-and-sandbox` 비대화형 실행 연동
- **`lib_py.delegation` 패키지 추출 (Issue #5 Phase 1)**: 위임 스크립트 4종을 파이썬 패키지로 승격하고, 기존 `scripts/*.py` 경로는 패키지를 자기 옆 트리에 프로세스당 1회 바인딩하는 호환 shim으로 유지
- **Runtime Framework Version Constant (`MAM_VERSION`) & 3-Way Lockstep**: `lib.sh` 내 `MAM_VERSION="4.3.0"` 런타임 진실 공급원 및 8개 스킬 3자 동기화 가드 유지
- **Python 코어 마이그레이션 (Issue #5 Phase 1~4)**: 위임 스크립트 4종과 936줄 `run_loop.sh` 오케스트레이션을 `lib_py.delegation` / `lib_py.loop` 파이썬 패키지로 승격. `scripts/*.py` 경로와 `run_loop.sh` CLI는 와이어 계약이므로 호환 shim·얇은 래퍼로 보존
- **CAS 단일 상태 전이 엔진 (`engine.py`)**: 잡 레코드 전이를 `dispatch_token` 선결 조건에 원자적으로 결속. 이중 디스패치·경합 병합을 구조적으로 차단
- **섀도우 와처 및 자동 완료 게이트 (`shadow.py`, `autocomplete.py`)**: 관측 증거 기반 Would-Complete 판정을 섀도우로 먼저 축적하고, 실제 자동 완료는 **기본 비활성(`MAM_AUTO_COMPLETE=0`)** 옵트인으로만 동작
- **Eager Import 불변 런타임 및 B-13 Freeze 제거 (`eager.py`)**: 기동 시 전 의존 모듈을 `sys.modules`에 상주시켜 실행 중 디스크 수정 크래시를 원천 차단하고, `/tmp/mam-loop-freeze.XXXXXX` 스냅샷 복사 우회책을 기본 경로에서 철거
- **Strict 판정 파서 (`parser.py`)**: 마크다운 코드 펜스 내부의 `[VERDICT: ...]`를 판정에서 배제하고, 판정 부재·모호·미지 태그를 예외 없이 fail-closed `NOT PASS`로 처리
- **4-Way 버전 락스텝**: `lib.sh`(`MAM_VERSION`) ↔ `lib_py/loop/eager.py`(`FRAMEWORK_VERSION`) ↔ `VERSIONS.md` ↔ 8개 `SKILL.md`. 런타임 불일치는 `verify_framework_version()`이 fail-closed 거부
---
## 🧭 스킬 패키지 버전 매트릭스 (Skills Version Matrix)
모든 8개 스킬은 YAML frontmatter 메타데이터(`author`, `version`, `platforms`, `environments`) 표준화를 통해 `v4.3.0`으로 동기화되어 배포됩니다.
모든 8개 스킬은 YAML frontmatter 메타데이터(`author`, `version`, `platforms`, `environments`) 표준화를 통해 `v4.4.0`으로 동기화되어 배포됩니다.
| 스킬명 | 버전 | 역할 및 주요 책임 | 상태 |
| :--- | :---: | :--- | :---: |
| **`multi-agent-mux-create`** | `4.3.0` | 에이전트 세션 신규 생성 및 Herdr 컨테이너 격리 스폰 | ✅ 배포 |
| **`multi-agent-mux-stop`** | `4.3.0` | 대화 UUID 원자적 캡처 및 세션 안전 종료 (Graceful Stop) | ✅ 배포 |
| **`multi-agent-mux-resume`** | `4.3.0` | 온디스크 대화 컨텍스트 기반 Tier-1 초고속 세션 복원 | ✅ 배포 |
| **`multi-agent-mux-status`** | `4.3.0` | 실시간 Herdr 세션 및 레지스트리 드리프트 스냅샷 조회 | ✅ 배포 |
| **`multi-agent-mux-monitor`** | `4.3.0` | YAML ↔ 런타임 상태 간 자율 조정자 (Reconciler Loop) | ✅ 배포 |
| **`multi-agent-mux-delegate-job`** | `4.3.0` | MQTT 이벤트 채널 기반 비동기 단위 작업 위임 | ✅ 배포 |
| **`multi-agent-mux-loop`** | `4.3.0` | Planner-Creator-Reviewer 3자 자율 계획·실행·피어리뷰 루프 | ✅ 배포 |
| **`multi-agent-mux-orc-onboard`** | `4.3.0` | 오케스트레이터 UUID 격리 등록 및 서브 세션 오염 방지 | ✅ 배포 |
| **`multi-agent-mux-create`** | `4.4.0` | 에이전트 세션 신규 생성 및 Herdr 컨테이너 격리 스폰 | ✅ 배포 |
| **`multi-agent-mux-stop`** | `4.4.0` | 대화 UUID 원자적 캡처 및 세션 안전 종료 (Graceful Stop) | ✅ 배포 |
| **`multi-agent-mux-resume`** | `4.4.0` | 온디스크 대화 컨텍스트 기반 Tier-1 초고속 세션 복원 | ✅ 배포 |
| **`multi-agent-mux-status`** | `4.4.0` | 실시간 Herdr 세션 및 레지스트리 드리프트 스냅샷 조회 | ✅ 배포 |
| **`multi-agent-mux-monitor`** | `4.4.0` | YAML ↔ 런타임 상태 간 자율 조정자 (Reconciler Loop) | ✅ 배포 |
| **`multi-agent-mux-delegate-job`** | `4.4.0` | MQTT 이벤트 채널 기반 비동기 단위 작업 위임 | ✅ 배포 |
| **`multi-agent-mux-loop`** | `4.4.0` | Planner-Creator-Reviewer 3자 자율 계획·실행·피어리뷰 루프 | ✅ 배포 |
| **`multi-agent-mux-orc-onboard`** | `4.4.0` | 오케스트레이터 UUID 격리 등록 및 서브 세션 오염 방지 | ✅ 배포 |
---
## 📋 버전별 상세 변경 내역 (Changelog)
### 🚀 `v4.4.0` — Issue #5 Python 코어 마이그레이션 완결 및 `main` 병합 (2026-09-07)
> **주요 마일스톤 (MINOR Release)**: Issue #5 Phase 1~4 전 단계 완료 및 `refactor` → `main` 병합. 위임·루프 오케스트레이션의 구현 언어를 Bash에서 Python으로 옮기고, CAS 단일 상태 전이·섀도우 와처·자동 완료 게이트·Eager Import 불변 런타임을 도입했다. **공개 계약(스크립트 경로, CLI 인자·종료 코드, 이벤트 와이어 스키마 `schema_version=1`, YAML 레이아웃)은 한 건도 제거·변경되지 않았으며**, 모든 기본 동작 변경은 환경변수 한 개로 즉시 되돌릴 수 있다.
#### ⚖️ SemVer 판정 근거 (MINOR — `v4.4.0`, MAJOR `v5.0.0` 미채택)
SemVer 2.0.0 §8은 MAJOR를 **하위 호환을 깨는 공개 API 변경**에 한정한다. 본 릴리스는 규모는 크지만 그 조건을 충족하지 않는다.
| 판정 축 | 관측 사실 | 근거 |
| :--- | :--- | :---: |
| 공개 계약 제거/이동 | Issue #5 전 구간에서 **삭제·rename 파일 0건** | `git diff --name-status fc0bd96..HEAD` |
| 와이어 스키마 | `SCHEMA_VERSION = 1` 불변 | `mqtt_common.py:135` |
| 스크립트 리터럴 경로 | `scripts/*.py` 4종 전부 존속 (호환 shim) | Phase 1 D2 |
| CLI 인자·종료 코드 | `run_loop.sh`·`publish_event`·`job_subscriber` 계약 회귀 통과 | G-1~G-9 |
| 기본 동작 변경의 가역성 | `MAM_DELEGATION_PY=0` / `MAM_ENGINE_CAS=0` / `MAM_LOOP_PY=0` / `MAM_LOOP_FREEZE=1` 로 이전 동작 완전 복원 (레거시 본체 존치, 968줄 셸 루프 포함) | `test_issue5_phase3_loop.py`, `test_issue5_phase4_runtime.py` |
| 최고위험 신규 기능 | 자동 완료는 **기본 비활성** 옵트인 | `MAM_AUTO_COMPLETE` 기본값 `0` |
> **운영자 조치 필요 사항 없음**: 마이그레이션 절차, 설정 변환, 재배포가 요구되지 않는다. 이것이 MAJOR를 채택하지 않은 결정적 이유다. 다만 `MAM_VERSION` 불일치는 새로 fail-closed 거부되므로, **프레임워크 트리는 부분 갱신하지 말고 통째로 배포해야 한다**(§ 아래 주의).
#### 🌟 신규 기능 및 아키텍처 확장
* **Phase 1 — `lib_py.delegation` 패키지 추출**: `v4.3.0`에서 선행 완료(하단 항목 참조).
* **Phase 2a — CAS 단일 상태 전이 엔진 및 섀도우 와처**: 잡 레코드 전이를 `claim`/`redispatch` 시점에 발급되는 불투명 `dispatch_token`을 선결 조건으로 하는 compare-and-set으로 결속. 관측 증거 수집(`attribution.py`)·판정 정책(`policy.py`)·증거 저장소(`store.py`)를 분리하고, `shadow.py`가 실제 전이 없이 "Would-Complete" 판정만 기록한다.
* **Phase 2b — 자동 완료 게이트 (`autocomplete.py`)**: 섀도우 증거가 충분할 때에만 잡을 자동 종결하는 평가기. `MAM_AUTO_COMPLETE`(기본 `0`), `MAM_AUTO_COMPLETE_BACKENDS`로 백엔드 단위 옵트인. CAS가 롤백된 상태(`MAM_ENGINE_CAS=0`)에서는 스스로 비활성화한다.
* **Phase 2b — 내구성 있는 보류 알림 (`notifier.py`)**: 알림 의도를 잡 레코드에 저장하고 CAS 락 바깥에서 발행한 뒤 `notification_settled` 부기 요청으로 조건부 정산. 재시도는 새 와이어 시퀀스를 받으므로 단조 시퀀스 가드로는 중복을 식별할 수 없고, 안정적인 `(seq, event, timestamp)` 의도 신원으로 중복을 판별한다.
* **Phase 3 — `run_loop.sh` 얇은 래퍼 전환 및 `lib_py.loop` 승격**: 936줄 Bash 오케스트레이션을 단일 제어 구조의 Python 모듈로 이식. `run_loop.sh`는 CLI 계약과 기존 정적 검사 앵커를 보존하는 래퍼가 되었고, `MAM_LOOP_PY=0`으로 레거시 셸 루프를 그대로 실행할 수 있다.
* **Phase 3 — Strict 판정 파서 (`parser.py`)**: 마크다운 코드 펜스(` ``` `, `~~~`) 내부를 제거한 뒤 **마지막 비공백 라인**만을 판정으로 인정한다. 리포트 본문의 예시 코드에 적힌 `[VERDICT: PASS]`가 실제 판정으로 오인되던 결함(`baseline.md` Gap)을 해소했다. 판정 부재·`PASS`/`NOT PASS` 모호 충돌·미지 태그는 모두 fail-closed `NOT PASS`.
* **Phase 3 — 원자적 체크포인트 및 우아한 정지 (`checkpoint.py`)**: `.mam/loop-checkpoint.json`에 회차·활성 잡·계획·리뷰 상태·기준 커밋을 임시 파일 + `replace` 원자 커밋으로 기록. SIGINT/SIGTERM 수신 시 서브프로세스를 정리하고 체크포인트를 남긴 뒤 가드를 해제하고 종료(130/143).
* **Phase 4 — Eager Import 불변 런타임 (`eager.py`)**: 기동 최우선 단계에서 표준·프레임워크 코어 모듈 전량을 `sys.modules`에 상주시켜, 루프 실행 중 디스크의 `.py`가 편집되어도 런타임이 영향을 받지 않는다. `PYTHONDONTWRITEBYTECODE=1`로 `.pyc` 파편에 의한 작업 트리 오염을 차단한다.
* **Phase 4 — B-13 Freeze 스냅샷 제거**: Bash가 실행 중 스크립트를 디스크에서 재독해하며 발생하던 크래시(B-13)의 원인이 Python 상주 프로세스 전환으로 근본 해소되었으므로, 임시 비계였던 `/tmp/mam-loop-freeze.XXXXXX` 트리 복사를 기본 경로에서 철거했다. 턴당 수백 개 파일 복사 오버헤드가 사라진다.
#### 🔒 롤백 및 안전장치
* **단일 환경변수 롤백 4종**: `MAM_DELEGATION_PY=0`(위임 셸 헬퍼 레거시 본체), `MAM_ENGINE_CAS=0`(무조건 병합 복원), `MAM_LOOP_PY=0`(레거시 셸 루프), `MAM_LOOP_FREEZE=1`(Freeze 스냅샷 재활성화). 재배포·revert 불필요.
* **⚠️ 부분 배포 금지 (신규 fail-closed 게이트)**: `lib.sh`의 `MAM_VERSION`과 `lib_py/loop/eager.py`의 `FRAMEWORK_VERSION`이 다르면 `verify_framework_version()`이 `RuntimeError`로 루프 기동을 거부한다. 두 파일 중 하나만 갱신된 혼재 트리는 실행되지 않으므로, 프레임워크는 항상 트리 단위로 배포한다.
* **4-Way 락스텝 자동 검증**: `test_version_consistency.py`가 `lib.sh` ↔ `eager.py` ↔ `VERSIONS.md`(현재 버전 + 매트릭스 8행) ↔ 8개 `SKILL.md` frontmatter의 완전 일치를 강제한다. `eager.py` 커버리지는 본 릴리스에서 신규 추가되었다.
#### ✅ 품질 검증
* 전체 테스트 스위트 **750개 통과, 0 실패, 0 skip** (Issue #5 착수 시점 510개 대비 +240).
* Issue #5 전용 회귀: `test_issue5_phase{0,1,2a,2b,3,4}_*.py`.
* **테스트 격리 결함 1건 수정 (`tests/conftest.py`)**: `lib.sh`가 export한 `MAM_VERSION`이 pytest를 기동한 셸에서 상속되어, 루프 테스트가 *검사 대상 트리*가 아니라 *러너를 띄운 셸이 언제 `lib.sh`를 source했는지*에 따라 통과·실패하고 있었다. 지금까지는 상속값과 상수가 우연히 같아 잠복해 있었고, 본 릴리스의 버전 상승이 이를 드러냈다(4건 실패). 세션 스코프 fixture가 상속된 값을 제거하여 스위트가 트리를 측정하도록 바로잡았다.
- 프로덕션 경로는 영향 없음: `run_loop.sh:17`이 실행 최초에 `lib.sh`를 source하고 `lib.sh:32-33`이 `MAM_VERSION`을 무조건 재export하므로, 낡은 상속값은 파이썬 기동 전에 항상 덮어써진다(`MAM_VERSION=4.3.0 bash -c 'source lib.sh; echo $MAM_VERSION'` → `4.4.0`).
### 🚀 `v4.3.0` — `lib_py.delegation` 패키지 추출 및 장수 MQTT 연결 프로토타입 (2026-09-06)
> **주요 마일스톤 (MINOR Release)**: Issue #5 Phase 1. `lib.sh`의 위임 헬퍼 3종과 `multi-agent-mux-delegate-job/scripts/*.py` 4종을 `lib_py/delegation/` 파이썬 패키지로 추출. 스크립트 경로는 와이어 계약이므로 호환 shim으로 보존하며, 프로덕션 동작·이벤트 스키마·자동완료 정책은 한 줄도 바뀌지 않는다.
@@ -21,12 +21,12 @@
| 단계 | 작업 목표 | 세부 구현 내용 | 필수 완료 게이트 (Gate Criteria) | 롤백 절차 (Rollback Path) |
|---|---|---|---|---|
| **Phase 0**<br>*(현재)* | **사전 계약 고정 및 Fixture 수집** | • CLI, 이벤트, 리포트, 락 계약 기준선 문서화<br>• Herdr 0.8.2 네이티브 캡처 및 복합 Watcher 시나리오 2계층 분리<br>• 6개 백엔드 실측 증거 행렬 수집 | • 510개 전체 테스트 수집 및 회귀 0-Fail (100% 통과)<br>• Fixture 스키마 및 증거 경계 검증 통과<br>• 프로덕션 코드 무변경 diff 검증 | 미추적 산출물 즉시 삭제 (`rm -rf docs/contracts/issue-5 tests/fixtures/issue_5 tests/test_issue5_phase0_contracts.py`) |
| **Phase 0**<br>*(완료)* | **사전 계약 고정 및 Fixture 수집** | • CLI, 이벤트, 리포트, 락 계약 기준선 문서화<br>• Herdr 0.8.2 네이티브 캡처 및 복합 Watcher 시나리오 2계층 분리<br>• 6개 백엔드 실측 증거 행렬 수집 | • 510개 전체 테스트 수집 및 회귀 0-Fail (100% 통과)<br>• Fixture 스키마 및 증거 경계 검증 통과<br>• 프로덕션 코드 무변경 diff 검증 | 미추적 산출물 즉시 삭제 (`rm -rf docs/contracts/issue-5 tests/fixtures/issue_5 tests/test_issue5_phase0_contracts.py`) |
| **Phase 1**<br>*(완료 v4.3.0)* | **`lib_py/delegation/` 추출** | • `lib.sh` L1833 이하 위임 헬퍼를 파이썬 서비스 클래스로 추출<br>• `start_watchdog`을 내부 명칭 `ensure_subscriber_daemon`으로 명명(기존 함수 별칭 보존)<br>• 장수 프로세스 단일 MQTT 연결 재사용 프로토타입 | • CLI/non-fatal/HMAC/seq/디스크 폴백 회귀 100% 통과<br>• 데몬 수명 및 PID 계약 일치 확인<br>• **자동완료 정책 변경 없음** | `MAM_DELEGATION_PY=0`으로 보존된 레거시 인라인 본체(`_*_legacy`)로 즉시 분기 (재배포·revert 불필요; 레거시 본체 제거는 Phase 4) |
| **Phase 2a**<br>*(완료, shadow-only)* | **`lib_py/loop/` 코어 & Shadow Watcher** | • `engine.py` (단일 전이 주체), `watcher.py` (`herdr agent wait` 래핑) 구현<br>• 모든 Writer에 대한 단일 CAS 트랜잭션 경계 구현<br>• 자동완료를 수행하지 않고 "Would-Complete" 로깅만 수행하는 Shadow 모드 가동 | • 락 내 비동기/I/O 배제 검증<br>• 소켓 단절/스냅샷 재연결 백오프 검증<br>• Shadow 모드가 레지스트리 상태를 쓰지 않음을 검증 | 1) Shadow 모니터 프로세스 종료 및 인메모리 큐 폐기<br>2) CAS 서비스는 하위 호환 모드로 유지하거나 `MAM_ENGINE_CAS=0` 플래그로 비활성화하여 레거시 무조건 필드 병합(`update_job_status`)으로 복귀<br>3) 기존 셸 루프 상태 및 레코드 불변 유지 |
| **Phase 2b**<br>*(완료, 기본 비활성)* | **이중 감지 자동완료 활성화 (Flag-Gated)** | • 4중 실행 귀속 + 리포트 확정 계약 + 단일 CAS 전이 게이트 연동<br>• Pending Notification 지연 알림 및 크래시 복구 구현<br>• 검증된 백엔드/작업에 한해 opt-in 플래그로 활성화 (기본값 OFF) | • 부수효과 작업 예외 및 무판정 fail-closed 테스트 완료<br>• 경쟁/재시작 시나리오 통과<br>• 플래그 OFF 시 기존 explicit event 경로 100% 보존 | 환경변수/플래그 `MAM_AUTO_COMPLETE=0` 설정; 이미 확정된 terminal 레코드는 보존하고 신규 자동완료만 중단 |
| **Phase 3** | **`run_loop.sh` Thin Wrapper 전환 및 전면 회귀** | • `run_loop.sh`를 인자 전달 래퍼(`exec python3 -m lib_py.loop "$@"`)로 전환<br>• 플래너/리뷰어/반론/승격 오케스트레이션 로직 완전 이식<br>• 엄격한 판정 파서(Strict Parser) 적용 | • 5개 subprocess 전용 테스트(~1,621줄) 포함 전체 481개+ 테스트 0-Fail<br>• 시그널, 루프 가드, 임의 CWD 및 공백 경로 검증 통과 | **우아한 핸드오프 시퀀스**:<br>1) Quiesce: 실행 중인 Python 루프 프로세스에 종료 신호를 전달하여 신규 디스패치 중단<br>2) Checkpoint: 현재 루프 회차, 활성 Job ID 및 리뷰 상태를 `.mam/loop-checkpoint.json`에 원자적 기록<br>3) Exit: Python 루프 정상 종료 및 가드 해제<br>4) Resume: 백업된 셸 원본 스크립트로 `run_loop.sh` 복원 후 체크포인트 기반 재개 검증 |
| **Phase 4** | **불변 런타임 검증 및 Freeze 제거** | • 기동 시 전체 모듈 상주(Eager Import) 및 자식 템플릿 불변성 검증<br>• 작업 도중 스킬 파일 교체 및 늦은 경로 스트레스 테스트 통과<br>• `/tmp/mam-loop-freeze.XXXXXX` 우회책 완전 제거 | • 런타임 자기수정 크래시(B-13) 재발 방지 검증<br>• Live Helper 버전 호환 게이트 검증 통과<br>• 운영 문서 및 배포 스크립트 갱신 | Freeze 복사 로직(`run_loop.sh:112-127`) 재활성화 및 라이브 헬퍼 버전 검사 복구 |
| **Phase 3**<br>*(완료 v4.4.0)* | **`run_loop.sh` Thin Wrapper 전환 및 전면 회귀** | • `run_loop.sh`를 인자 전달 래퍼(`exec python3 -m lib_py.loop "$@"`)로 전환<br>• 플래너/리뷰어/반론/승격 오케스트레이션 로직 완전 이식<br>• 엄격한 판정 파서(Strict Parser) 적용 | • 5개 subprocess 전용 테스트(~1,621줄) 포함 전체 481개+ 테스트 0-Fail<br>• 시그널, 루프 가드, 임의 CWD 및 공백 경로 검증 통과 | **우아한 핸드오프 시퀀스**:<br>1) Quiesce: 실행 중인 Python 루프 프로세스에 종료 신호를 전달하여 신규 디스패치 중단<br>2) Checkpoint: 현재 루프 회차, 활성 Job ID 및 리뷰 상태를 `.mam/loop-checkpoint.json`에 원자적 기록<br>3) Exit: Python 루프 정상 종료 및 가드 해제<br>4) Resume: 백업된 셸 원본 스크립트로 `run_loop.sh` 복원 후 체크포인트 기반 재개 검증 |
| **Phase 4**<br>*(완료 v4.4.0)* | **불변 런타임 검증 및 Freeze 제거** | • 기동 시 전체 모듈 상주(Eager Import) 및 자식 템플릿 불변성 검증<br>• 작업 도중 스킬 파일 교체 및 늦은 경로 스트레스 테스트 통과<br>• `/tmp/mam-loop-freeze.XXXXXX` 우회책 완전 제거 | • 런타임 자기수정 크래시(B-13) 재발 방지 검증<br>• Live Helper 버전 호환 게이트 검증 통과<br>• 운영 문서 및 배포 스크립트 갱신 | Freeze 복사 로직(`run_loop.sh:112-127`) 재활성화 및 라이브 헬퍼 버전 검사 복구 |
---
@@ -36,7 +36,8 @@ Phase 3에서 `run_loop.sh`가 Python `lib_py.loop`로 위임됨에 따라, Bash
- 기존 테스트의 락/가드 해제 계약(`_mam_release_guard`)은 외부 주입 스냅샷 디렉터리가 있을 경우 그대로 안전하게 정리합니다.
### 2-3. 라이브 헬퍼 버전 호환성 게이트 (`MAM_VERSION`)
- `lib.sh`의 `MAM_VERSION`("4.3.0")과 프로세스 런타임의 프로토콜 버전을 동기화하고, 불일치 발생 시 안전하게 fail-closed 거부합니다.
- `lib.sh`의 `MAM_VERSION`과 프로세스 런타임의 프로토콜 버전(`eager.FRAMEWORK_VERSION`, 현재 `4.4.0`)을 동기화하고, 불일치 발생 시 안전하게 fail-closed 거부합니다.
- 이 게이트 때문에 프레임워크 트리는 **부분 갱신이 불가능**합니다. 두 상수 중 하나만 배포된 혼재 트리는 루프 기동 시점에 `RuntimeError`로 거부되므로, 배포는 항상 트리 단위로 수행합니다.
---
+3 -3
View File
@@ -1,8 +1,8 @@
# 📑 Issue #5 Task Checklist & Verification Evidence
- **Document Version**: Rev.8 (Phase 3 실행 완료 — P3-01~P3-03 증거 기록)
- **Document Version**: Rev.9 (Phase 4 완료 및 `v4.4.0` 릴리스 버전 락스텝 반영)
- **Issue**: [Gitea Issue #5](https://git.godopu.com/tmpl/multi-agent-mux/issues/5)
- **Status**: Phase 0 Complete / **Phase 1 Complete (v4.3.0)** / **Phase 2a Complete (shadow-only)** / **Phase 2b Complete (default-off)** / **Phase 3 Complete (thin wrapper)** / Phase 4 Staged
- **Status**: Phase 0 Complete / **Phase 1 Complete (v4.3.0)** / **Phase 2a Complete (shadow-only)** / **Phase 2b Complete (default-off)** / **Phase 3 Complete (thin wrapper)** / **Phase 4 Complete (freeze removed)** — 전 단계 `main` 병합 및 `v4.4.0` 릴리스 완료
---
@@ -131,7 +131,7 @@
## Phase 4: 불변 런타임 검증 및 Freeze 제거 (완료)
- [x] **P4-01** eager import+child/helper/template 실행 버전 정책 구현/검증.
- *증거*: `.agents/skills/lib_py/loop/eager.py` 구현 및 `runner.LoopRunner.__init__`에서 최우선 호출. 모든 표준/프레임워크 코어 모듈(47개+)을 기동 시점에 `sys.modules`에 상주시킴. `sys.dont_write_bytecode = True` 및 `PYTHONDONTWRITEBYTECODE=1` 환경 설정으로 `.pyc` 디스크 오염 원천 차단. `FRAMEWORK_VERSION="4.3.0"`과 `MAM_VERSION` 불일치 시 fail-closed 검증 (`test_p4_01`).
- *증거*: `.agents/skills/lib_py/loop/eager.py` 구현 및 `runner.LoopRunner.__init__`에서 최우선 호출. 모든 표준/프레임워크 코어 모듈(47개+)을 기동 시점에 `sys.modules`에 상주시킴. `sys.dont_write_bytecode = True` 및 `PYTHONDONTWRITEBYTECODE=1` 환경 설정으로 `.pyc` 디스크 오염 원천 차단. `FRAMEWORK_VERSION`(현재 `4.4.0`)과 `MAM_VERSION` 불일치 시 fail-closed 검증 (`test_p4_01`). 두 상수의 값 일치는 `tests/test_version_consistency.py`가 소유하며, `test_p4_01`은 게이트 동작만 검증하므로 릴리스 버전 상승 시 이 테스트를 수정할 필요가 없다.
- [x] **P4-02** 실행 중 코드 교체와 늦은 재심/승격/rollback 스트레스 검증.
- *증거*: `tests/test_issue5_phase4_runtime.py::test_p4_02_midflight_code_replacement_stress`. 실행 중인 서브프로세스의 디스크 상 소스 파일 및 워커 모듈을 문법 오류(`INVALID SYNTAX`, `unexpected EOF`)로 치환/파괴한 상태에서도 메모리 상주 바이트코드와 AST를 통해 판정 파싱(`parser.parse_verdict`), 체크포인트 원자적 기록/복구(`checkpoint.save_checkpoint`/`load_checkpoint`)가 무결하게 완결됨을 실증.
- [x] **P4-03** gate 통과 후에만 Freeze 제거 및 운영 문서 갱신.
@@ -1,10 +1,11 @@
# 🚀 MAM 메시징 백플레인 전환 실행 로드맵 (`implementation_plan.md`)
- **문서 버전**: v1.2.0
- **문서 버전**: v1.3.0
- **작성/관리 주체**: Multi-Agent Orchestration Team (`claude`, `agy`, `hermes`, `grok`)
- **이관 사유/일자**: 2026-09-07 (루트 마크다운 정리 작업으로 docs/contracts/nats-backplane/ 이관)
- **기준 커밋**: `916185c` (306/306 baseline tests passing)
- **문서 목적**: MAM의 메시징 인프라를 공개 HiveMQ 브로커에서 `nats-server` 전용 사설 브로커로 무중단 전환하기 위한 5개 트랙(Track 0~3, Track 1R)과 6단계 마일스톤(M0~M4, M2b)의 구체적 실행 지침 및 진행 상황 추적.
- **연계 문서**: [`NATS_REPORT.md`](nats-docker/NATS_REPORT.md), [`PRIVATE_SERVER.md`](nats-docker/PRIVATE_SERVER.md), [`IMPROVEMENTS.md`](IMPROVEMENTS.md)
- **연계 문서**: [`NATS_REPORT.md`](../../../nats-docker/NATS_REPORT.md), [`PRIVATE_SERVER.md`](../../../nats-docker/PRIVATE_SERVER.md), [`IMPROVEMENTS.md`](../../../IMPROVEMENTS.md)
---
@@ -143,12 +144,12 @@ M0 (문서 정합성) ──> M1 (Track 0 내결함성) ──> M2a (로컬 스
| 대상 파일 | 갱신 내용 |
|---|---|
| [`MESSAGING.md`](MESSAGING.md) | 브로커 표준을 `nats-server`로 갱신, F-1/C1 해소 기록, F-5 영속 세션 서술 정정, 10개 환경변수 및 해석 계층 문서화 |
| [`IMPROVEMENTS.md`](IMPROVEMENTS.md) | B-14/B-15 완료 상태 반영, O-6 신설, B-17/B-18 신설 등록 |
| [`VERSIONS.md`](VERSIONS.md) | `v2.0.0` 릴리스 노트에 메시징 백플레인 고도화 및 내결함성 패치 기록 |
| [`PRIVATE_SERVER.md`](nats-docker/PRIVATE_SERVER.md) | 스파이크 결과 반영 및 최종 가이드 확정 |
| [`deploy/install.sh`](deploy/install.sh) | `requirements.txt` 확인 (paho 유지) 및 개인 브로커 안내 추가 |
| [`.mam.env`](.mam.env) | `MQTT_BROKER`, `MQTT_PORT`, `MQTT_TLS` 기본 템플릿 확정 |
| [`MESSAGING.md`](../../../MESSAGING.md) | 브로커 표준을 `nats-server`로 갱신, F-1/C1 해소 기록, F-5 영속 세션 서술 정정, 10개 환경변수 및 해석 계층 문서화 |
| [`IMPROVEMENTS.md`](../../../IMPROVEMENTS.md) | B-14/B-15 완료 상태 반영, O-6 신설, B-17/B-18 신설 등록 |
| [`VERSIONS.md`](../../../VERSIONS.md) | `v2.0.0` 릴리스 노트에 메시징 백플레인 고도화 및 내결함성 패치 기록 |
| [`PRIVATE_SERVER.md`](../../../nats-docker/PRIVATE_SERVER.md) | 스파이크 결과 반영 및 최종 가이드 확정 |
| [`deploy/install.sh`](../../../deploy/install.sh) | `requirements.txt` 확인 (paho 유지) 및 개인 브로커 안내 추가 |
| [`.mam.env (템플릿: .mam.env.example)`](../../../.mam.env.example) | `MQTT_BROKER`, `MQTT_PORT`, `MQTT_TLS` 기본 템플릿 확정 |
---
+25
View File
@@ -1065,6 +1065,31 @@ print(str(uuid.uuid4()))
# lib_py, which is why test_tier1_unit.py's inserts stay legal.)
# ==============================================================================
# ==============================================================================
# Ambient MAM_VERSION isolation.
#
# lib.sh exports MAM_VERSION, so any shell that has sourced it — an agent
# session, a developer's terminal — hands that value down to pytest and on to
# every subprocess the suite spawns. lib_py.loop.eager.eager_load() compares it
# against FRAMEWORK_VERSION and refuses to start on a mismatch, so an inherited
# value from a *pre-upgrade* shell makes the loop tests fail against a tree that
# is perfectly consistent with itself.
#
# The suite must measure the tree under test, not the version its launcher
# happened to source, so the ambient value is dropped for the whole session.
# Tests that exercise the gate set MAM_VERSION explicitly and are unaffected.
# ==============================================================================
@pytest.fixture(scope="session", autouse=True)
def _drop_ambient_mam_version():
previous = os.environ.pop("MAM_VERSION", None)
try:
yield
finally:
if previous is not None:
os.environ["MAM_VERSION"] = previous
@pytest.fixture(scope="session", autouse=True)
def delegation_tree_provenance_guard(tmp_path_factory):
yield
+5 -3
View File
@@ -36,9 +36,11 @@ def test_p4_01_eager_import_completeness_and_bytecode_inhibition(monkeypatch):
assert sys.dont_write_bytecode is True
assert os.environ.get("PYTHONDONTWRITEBYTECODE") == "1"
# Verify framework version constant sync
assert eager.FRAMEWORK_VERSION == "4.3.0"
eager.verify_framework_version("4.3.0")
# Verify framework version constant sync. The literal value is not pinned
# here: tests/test_version_consistency.py owns the lockstep between
# eager.FRAMEWORK_VERSION, lib.sh's MAM_VERSION, VERSIONS.md and the eight
# SKILL.md files, so a release bump must not have to edit this file too.
eager.verify_framework_version(eager.FRAMEWORK_VERSION)
# Verify mismatch raises RuntimeError
monkeypatch.setenv("MAM_VERSION", "9.9.9")
+49
View File
@@ -11,6 +11,7 @@ REPO_ROOT = Path(__file__).resolve().parent.parent
LIB_SH = REPO_ROOT / ".agents" / "skills" / "lib.sh"
VERSIONS_MD = REPO_ROOT / "VERSIONS.md"
SKILLS_DIR = REPO_ROOT / ".agents" / "skills"
EAGER_PY = SKILLS_DIR / "lib_py" / "loop" / "eager.py"
SKILL_NAMES = [
"multi-agent-mux-create",
@@ -46,6 +47,15 @@ def _get_versions_md_versions():
return current_framework_ver, matrix_dict
def _get_eager_py_framework_version():
"""Read FRAMEWORK_VERSION statically — importing lib_py.loop.eager would
pull the whole framework onto sys.path just to read one constant."""
text = EAGER_PY.read_text(encoding="utf-8")
m = re.search(r'^FRAMEWORK_VERSION\s*=\s*"(\d+\.\d+\.\d+)"', text, re.M)
assert m, f"Failed to parse FRAMEWORK_VERSION in {EAGER_PY}"
return m.group(1)
def _get_skill_md_frontmatter_version(skill_name: str):
skill_file = SKILLS_DIR / skill_name / "SKILL.md"
assert skill_file.is_file(), f"Skill file not found: {skill_file}"
@@ -78,6 +88,45 @@ def test_three_way_version_lockstep():
fm_ver = _get_skill_md_frontmatter_version(skill)
assert fm_ver == lib_ver, f"{skill}/SKILL.md version ({fm_ver}) != lib.sh ({lib_ver})"
# 4. Runtime constant in lib_py/loop/eager.py.
eager_ver = _get_eager_py_framework_version()
assert eager_ver == lib_ver, (
f"eager.py FRAMEWORK_VERSION ({eager_ver}) != lib.sh MAM_VERSION ({lib_ver})"
)
def test_runtime_version_gate_rejects_a_partially_bumped_tree():
"""A tree where only one of the two runtime constants was bumped must not run.
lib.sh exports MAM_VERSION into the environment and eager_load() compares it
against FRAMEWORK_VERSION, so a half-updated deployment fails closed at loop
startup rather than running two versions of the framework against each other.
This guards the mechanism; the values themselves are pinned by the lockstep
test above.
"""
import importlib.util
spec = importlib.util.spec_from_file_location("_eager_under_test", EAGER_PY)
eager = importlib.util.module_from_spec(spec)
spec.loader.exec_module(eager)
assert eager.FRAMEWORK_VERSION == _get_lib_sh_mam_version()
env_before = os.environ.get("MAM_VERSION")
os.environ["MAM_VERSION"] = "0.0.0-stale"
try:
try:
eager.verify_framework_version()
except RuntimeError as exc:
assert "MAM_VERSION mismatch" in str(exc)
else:
raise AssertionError("a stale MAM_VERSION was accepted by the runtime gate")
finally:
if env_before is None:
os.environ.pop("MAM_VERSION", None)
else:
os.environ["MAM_VERSION"] = env_before
def test_mam_version_is_not_env_overridable():
"""T-0 (Constraint 1): MAM_VERSION cannot be spoofed by caller environment."""