chore(release): bump framework and 8 skills to v3.1.0 (MINOR)
- Define immutable MAM_VERSION="3.1.0" runtime constant in lib.sh - Bump YAML frontmatter version to 3.1.0 across all 8 skill packages - Document v3.1.0 changelog, 2-tier TUI readiness architecture, and migration guide in VERSIONS.md - Document new tuning knobs (MAM_KILL_ON_READY_TIMEOUT, MAM_DIALOG_TAIL_LINES, MAM_READY_EMPTY_GIVEUP) in .mam.env.example - Add 3-way lockstep and immutability test suite in tests/test_version_consistency.py
This commit is contained in:
@@ -25,6 +25,12 @@ SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
export PYTHONPATH="$SKILL_DIR:${PYTHONPATH:-}"
|
export PYTHONPATH="$SKILL_DIR:${PYTHONPATH:-}"
|
||||||
WORKSPACE_ROOT="${WORKSPACE_ROOT:-$(cd "$SKILL_DIR/../.." && pwd)}"
|
WORKSPACE_ROOT="${WORKSPACE_ROOT:-$(cd "$SKILL_DIR/../.." && pwd)}"
|
||||||
export WORKSPACE_ROOT
|
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="3.1.0"
|
||||||
|
export MAM_VERSION
|
||||||
AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$WORKSPACE_ROOT/.mam/agent-sessions.yaml}"
|
AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$WORKSPACE_ROOT/.mam/agent-sessions.yaml}"
|
||||||
|
|
||||||
_sanitize_herdr_agent_name() {
|
_sanitize_herdr_agent_name() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-mux-create
|
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."
|
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: 3.0.1
|
version: 3.1.0
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ if [ "$TUI_READY_RC" -ne 0 ]; then
|
|||||||
{
|
{
|
||||||
echo "=== MAM Diagnostic Dump ==="
|
echo "=== MAM Diagnostic Dump ==="
|
||||||
echo "Date: $(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
echo "Date: $(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
||||||
|
echo "MAM Version: ${MAM_VERSION:-unknown}"
|
||||||
echo "Session: $SESSION_NAME"
|
echo "Session: $SESSION_NAME"
|
||||||
echo "Agent: $AGENT"
|
echo "Agent: $AGENT"
|
||||||
echo "ReturnCode: $TUI_READY_RC"
|
echo "ReturnCode: $TUI_READY_RC"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-mux-delegate-job
|
name: multi-agent-mux-delegate-job
|
||||||
description: "Delegate a unit of work to any autonomous agent (claude-code, hermes, agy, cline, grok-build, codex, or a human) and observe it asynchronously over an MQTT event channel. Supported roles include orchestrator, worker, and reviewer."
|
description: "Delegate a unit of work to any autonomous agent (claude-code, hermes, agy, cline, grok-build, codex, or a human) and observe it asynchronously over an MQTT event channel. Supported roles include orchestrator, worker, and reviewer."
|
||||||
version: 3.0.1
|
version: 3.1.0
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos, windows]
|
platforms: [linux, macos, windows]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-mux-loop
|
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."
|
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: 3.0.1
|
version: 3.1.0
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-mux-monitor
|
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."
|
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: 3.0.1
|
version: 3.1.0
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-mux-orc-onboard
|
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.
|
description: "Register current or specified orchestrator session UUID into agent-sessions.yaml orchestrator_uuids list to prevent sub-agent discovery capture."
|
||||||
version: 3.0.1
|
version: 3.1.0
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-mux-resume
|
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."
|
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: 3.0.1
|
version: 3.1.0
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-mux-status
|
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."
|
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: 3.0.1
|
version: 3.1.0
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
name: multi-agent-mux-stop
|
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."
|
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: 3.0.1
|
version: 3.1.0
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
@@ -158,6 +158,19 @@
|
|||||||
#default: 2
|
#default: 2
|
||||||
# MAM_MAX_PANE_ROWS=2
|
# MAM_MAX_PANE_ROWS=2
|
||||||
|
|
||||||
|
# Kill the session instead of preserving it when TUI readiness times out.
|
||||||
|
#default: 0
|
||||||
|
# MAM_KILL_ON_READY_TIMEOUT=0
|
||||||
|
|
||||||
|
# Number of trailing non-blank pane lines scanned for blocking modal signatures.
|
||||||
|
#default: 8
|
||||||
|
# MAM_DIALOG_TAIL_LINES=8
|
||||||
|
|
||||||
|
# Consecutive empty captures before wait_for_tui_ready declares the pane unobservable.
|
||||||
|
# NOTE: distinct from SKS_EMPTY_GIVEUP, which governs send_keys_safe quiescence (default 3).
|
||||||
|
#default: 5
|
||||||
|
# MAM_READY_EMPTY_GIVEUP=5
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# deploy / distribution source (for forks/mirrors)
|
# deploy / distribution source (for forks/mirrors)
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
|
|||||||
+70
-16
@@ -6,37 +6,91 @@
|
|||||||
|
|
||||||
## 📌 현재 버전 개요 (Current Release)
|
## 📌 현재 버전 개요 (Current Release)
|
||||||
|
|
||||||
- **프레임워크 버전**: `v3.0.1`
|
- **프레임워크 버전**: `v3.1.0`
|
||||||
- **최신 릴리스 일시**: 2026-08-27 (KST)
|
- **최신 릴리스 일시**: 2026-08-28 (KST)
|
||||||
- **기준 브랜치**: `main`
|
- **기준 브랜치**: `main`
|
||||||
- **핵심 아키텍처**:
|
- **핵심 아키텍처**:
|
||||||
- **Herdr Shim Routing & Multi-Workspace Isolation Engine**: `HERDR_WORKSPACE_ID` 환경 변수 스코핑 및 `$WORKSPACE_ROOT/.mam/herdr_workspace_id` 영속화 메커니즘을 통해 다중 워크스페이스 동시 실행 시 페인 교차 오염 원천 차단
|
- **2-Tier TUI Readiness Model (`S ∨ (W ∧ C)`) & Modal Priority**: 강한 토큰(`S`) 단독 충족 및 약한 토큰(`W`) + 보강 패턴(`C`) 결합 판정식 도입, 모달 선행 검사 및 힌트 분리를 통한 다이얼로그 기아(starvation) 원천 해소
|
||||||
- **Atomic Safe Paste Insertion (`pane send-text`)**: 미지원 서브커맨드(`agent send`) 제거 및 `pane send-text` 단일 삽입 계약 도입, `send_keys_safe` 실패 전파(`rc 3`) 및 중복 제출(Double Submit) 방지
|
- **Adapter Modal Contract (`T-2d`)**: `BaseAgentAdapter` 내 `modal_tokens` 프로퍼티 신설 및 Cline/Claude 맞춤형 모달 시그니처 팩트 브리지 통합
|
||||||
- **Strict Exact-Match Single Pane Resolver**: 부분 문자열 매칭(`in tn`) 완전 제거, 단일 중앙 `_resolve_herdr_pane_id` 헬퍼 기반 5대 서브커맨드(`has-session`, `kill-session`, `capture-pane`, `send-keys`, `paste-buffer`) 무결성 정립
|
- **Fail-Closed Exact Pane Resolver & Multi-Workspace Isolation Engine**: `_resolve_herdr_pane_id` 동종 페인 다중 매치 시 fail-closed(`exit 1`) 차단, `HERDR_WORKSPACE_ID` 스코핑 및 `$WORKSPACE_ROOT/.mam/herdr_workspace_id` 영속화
|
||||||
- **TUI Readiness & Dialog Token Precision**: `_MAM_DIALOG_TOKENS` 일반 팁(`Yes, try it`) 오탐 제거 및 풀스크린 모달 Escape 거절 브랜치 분리
|
- **Atomic Safe Paste Insertion & Preserved Diagnostic Dumps**: `pane send-text` 단일 안전 삽입 계약, TUI 미준비 시 세션 보존(`exit 0`) 및 `.mam/diagnostics/` 진단 덤프 생성
|
||||||
- **Comprehensive Test Suite Milestone**: 412개 전체 테스트 100% PASS (412 passed / 0 failed).
|
- **Runtime Framework Version Constant (`MAM_VERSION`) & 3-Way Lockstep**: `lib.sh` 내 `MAM_VERSION="3.1.0"` 런타임 진실 공급원 정의 및 3자 동기화 가드 체계 구축
|
||||||
|
- **Comprehensive Test Suite Milestone**: 436개 전체 테스트 100% PASS (436 passed / 0 failed).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧭 스킬 패키지 버전 매트릭스 (Skills Version Matrix)
|
## 🧭 스킬 패키지 버전 매트릭스 (Skills Version Matrix)
|
||||||
|
|
||||||
모든 8개 스킬은 YAML frontmatter 메타데이터(`author`, `version`, `platforms`, `environments`) 표준화를 통해 `v3.0.1`으로 동기화되어 배포됩니다.
|
모든 8개 스킬은 YAML frontmatter 메타데이터(`author`, `version`, `platforms`, `environments`) 표준화를 통해 `v3.1.0`으로 동기화되어 배포됩니다.
|
||||||
|
|
||||||
| 스킬명 | 버전 | 역할 및 주요 책임 | 상태 |
|
| 스킬명 | 버전 | 역할 및 주요 책임 | 상태 |
|
||||||
| :--- | :---: | :--- | :---: |
|
| :--- | :---: | :--- | :---: |
|
||||||
| **`multi-agent-mux-create`** | `3.0.1` | 에이전트 세션 신규 생성 및 Herdr 컨테이너 격리 스폰 | ✅ 배포 |
|
| **`multi-agent-mux-create`** | `3.1.0` | 에이전트 세션 신규 생성 및 Herdr 컨테이너 격리 스폰 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-stop`** | `3.0.1` | 대화 UUID 원자적 캡처 및 세션 안전 종료 (Graceful Stop) | ✅ 배포 |
|
| **`multi-agent-mux-stop`** | `3.1.0` | 대화 UUID 원자적 캡처 및 세션 안전 종료 (Graceful Stop) | ✅ 배포 |
|
||||||
| **`multi-agent-mux-resume`** | `3.0.1` | 온디스크 대화 컨텍스트 기반 Tier-1 초고속 세션 복원 | ✅ 배포 |
|
| **`multi-agent-mux-resume`** | `3.1.0` | 온디스크 대화 컨텍스트 기반 Tier-1 초고속 세션 복원 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-status`** | `3.0.1` | 실시간 Herdr 세션 및 레지스트리 드리프트 스냅샷 조회 | ✅ 배포 |
|
| **`multi-agent-mux-status`** | `3.1.0` | 실시간 Herdr 세션 및 레지스트리 드리프트 스냅샷 조회 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-monitor`** | `3.0.1` | YAML ↔ 런타임 상태 간 자율 조정자 (Reconciler Loop) | ✅ 배포 |
|
| **`multi-agent-mux-monitor`** | `3.1.0` | YAML ↔ 런타임 상태 간 자율 조정자 (Reconciler Loop) | ✅ 배포 |
|
||||||
| **`multi-agent-mux-delegate-job`** | `3.0.1` | MQTT 이벤트 채널 기반 비동기 단위 작업 위임 | ✅ 배포 |
|
| **`multi-agent-mux-delegate-job`** | `3.1.0` | MQTT 이벤트 채널 기반 비동기 단위 작업 위임 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-loop`** | `3.0.1` | Planner-Creator-Reviewer 3자 자율 계획·실행·피어리뷰 루프 | ✅ 배포 |
|
| **`multi-agent-mux-loop`** | `3.1.0` | Planner-Creator-Reviewer 3자 자율 계획·실행·피어리뷰 루프 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-orc-onboard`** | `3.0.1` | 오케스트레이터 UUID 격리 등록 및 서브 세션 오염 방지 | ✅ 배포 |
|
| **`multi-agent-mux-orc-onboard`** | `3.1.0` | 오케스트레이터 UUID 격리 등록 및 서브 세션 오염 방지 | ✅ 배포 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📋 버전별 상세 변경 내역 (Changelog)
|
## 📋 버전별 상세 변경 내역 (Changelog)
|
||||||
|
|
||||||
|
### 🚀 `v3.1.0` — 2-Tier TUI Readiness Model, Adapter Modal Contract & Fail-Closed Pane Resolution (2026-08-28)
|
||||||
|
|
||||||
|
> **주요 마일스톤**: 다이얼로그 기아(starvation) 구조적 해소를 위한 2계층 TUI 준비 판정 모델(`S ∨ (W ∧ C)`), 모달/힌트 2계층 토큰 분리, 어댑터별 `modal_tokens` 계약(`T-2d`) 정립, 동종 페인 다중 매치 fail-closed 방어, 준비 실패 세션 진단 보존(`create_session.sh`), `lib.sh` 런타임 버전 상수(`MAM_VERSION="3.1.0"`) 신설 및 436개 전체 테스트 100% PASS 달성.
|
||||||
|
|
||||||
|
#### ⚠️ 동작 변경 및 마이그레이션 안내
|
||||||
|
* **B-1: TUI 미준비 세션 보존 (`create_session.sh`)**:
|
||||||
|
- TUI 준비 감지 타임아웃 발생 시, PID가 생존해 있다면 세션을 강제 종료(`kill-session`)하지 않고 `status: running`, `last_visible_status: tui-ready-timeout`으로 등록한 뒤 `exit 0`(성공)으로 반환합니다.
|
||||||
|
- 구 `v3.0.1`의 무조건 롤백 및 종료 동작을 원할 경우 `MAM_KILL_ON_READY_TIMEOUT=1`을 설정하십시오.
|
||||||
|
* **B-2: 프로세스 사망 시 종료 코드 변경**:
|
||||||
|
- `create_session.sh` 실행 중 PID가 사망한 경우 명시적 구분 코드 `42`(`MAM_EXIT_READY_TIMEOUT`)로 종료합니다.
|
||||||
|
* **B-3: 동종 페인 다중 매치 시 Fail-Closed 거부 (`_resolve_herdr_pane_id`)**:
|
||||||
|
- 동일한 에이전트 종류의 페인이 여러 개 발견되고 정확한 세션명 일치가 실패할 경우, 임의의 첫 번째 페인을 선택하지 않고 즉시 `exit 1`로 실패하여 교차 세션 오염을 원천 차단합니다.
|
||||||
|
* **B-4 & B-5: 환경변수 전파 (`WORKSPACE_ROOT`, `MAM_VERSION`)**:
|
||||||
|
- `WORKSPACE_ROOT` 및 `MAM_VERSION`이 자식 프로세스로 자동 `export`됩니다. `MAM_VERSION`은 런타임 위조 방지를 위해 환경변수 오버라이드가 차단됩니다.
|
||||||
|
|
||||||
|
#### 🔧 기존 워크스페이스 사용자 안내
|
||||||
|
기존 배포된 워크스페이스 사용자는 `.mam.env`에 아래 3종의 신규 환경변수를 추가하여 동작을 튜닝할 수 있습니다:
|
||||||
|
|
||||||
|
| 변수명 | 기본값 | 설명 |
|
||||||
|
| :--- | :---: | :--- |
|
||||||
|
| `MAM_KILL_ON_READY_TIMEOUT` | `0` | `1`로 설정 시 TUI 준비 타임아웃 발생 시 세션을 보존하지 않고 강제 종료(v3.0.1 동작) |
|
||||||
|
| `MAM_DIALOG_TAIL_LINES` | `8` | 블로킹 모달 시그니처를 검사할 페인 하단 비공백 라인 수 |
|
||||||
|
| `MAM_READY_EMPTY_GIVEUP` | `5` | `wait_for_tui_ready`가 페인을 관측 불가(Headless)로 판정하기까지의 연속 빈 캡처 횟수 |
|
||||||
|
|
||||||
|
#### 1. 2계층 TUI 준비 판정 모델 (`S ∨ (W ∧ C)`)
|
||||||
|
* **단독 충분 강한 신호 (`S`)**: `strong_ready_tokens` 또는 8자 이상의 유의미한 `input_placeholder`(`Ask anything...`) 일치 시 준비 완료 선언.
|
||||||
|
* **보강 결합 약한 신호 (`W ∧ C`)**: `weak_ready_tokens`(`history`, `Chat` 등)는 `input_prompt`(`❯`, `>`) 또는 `input_rule_pattern`(`─{10,}`)과 동시 일치할 때만 준비 완료로 판정하여 오탐 차단.
|
||||||
|
* **하강 호환성 (Fallback)**: `input_*` 속성이 미정의된 에이전트(Hermes 등)는 강한 토큰 단독 검사로 안전하게 하강.
|
||||||
|
|
||||||
|
#### 2. 모달/힌트 토큰 분리 및 어댑터 `modal_tokens` 계약 (`T-2a` / `T-2d`)
|
||||||
|
* **토큰 집합 분리**: `_MAM_MODAL_TOKENS`(고신뢰 블로킹 모달)와 `_MAM_HINT_TOKENS`(자연어 TUI 안내 팁)를 분리. `_pane_dialog_open`이 힌트 텍스트로 인해 영구 차단(Starvation)되는 결함 해소. `_MAM_DIALOG_TOKENS`는 하위호환용 합집합으로 존치.
|
||||||
|
* **`BaseAgentAdapter.modal_tokens`**: 에이전트별 특화 모달(Claude의 `Try the new fullscreen renderer?`, Cline의 `Select API Provider` 등)을 팩트 브리지(`MAM_MODAL_TOKENS`)로 통합.
|
||||||
|
|
||||||
|
#### 3. Fail-Closed 페인 해석 및 워크스페이스 스코프 강화 (`R-1` / `R-2`)
|
||||||
|
* `_resolve_herdr_pane_id`에서 다중 매치 시 `sys.exit(1)` 처리 및 `export WORKSPACE_ROOT` 보강으로 격리 안정성 확보.
|
||||||
|
|
||||||
|
#### 4. 준비 실패 세션 진단 보존 및 `MAM_VERSION` 스탬프
|
||||||
|
* `create_session.sh` 실패/타임아웃 시 `.mam/diagnostics/<session>-<timestamp>.txt`로 페인 덤프 및 `MAM Version` 스탬프 자동 기록.
|
||||||
|
|
||||||
|
#### 5. 런타임 버전 상수 `MAM_VERSION` 신설 및 3자 락스텝 검증
|
||||||
|
* `lib.sh` 내 `MAM_VERSION="3.1.0"` 선언 및 `test_version_consistency.py`를 통한 `lib.sh` ↔ `VERSIONS.md` ↔ 8개 `SKILL.md` 3자 일치 자동 검증.
|
||||||
|
|
||||||
|
#### 6. 신규 환경변수 3종 문서화
|
||||||
|
* `.mam.env.example`에 `MAM_KILL_ON_READY_TIMEOUT`, `MAM_DIALOG_TAIL_LINES`, `MAM_READY_EMPTY_GIVEUP` 3종 등록.
|
||||||
|
|
||||||
|
#### 7. 테스트 스위트 확장: 412 → 436 (+24, 100% PASS)
|
||||||
|
* `test_c1_tui_readiness.py` (21 tests), `test_adapter_modal_tokens_contract`, `test_version_consistency.py` 신설 등 총 436개 테스트 무결점 통과.
|
||||||
|
|
||||||
|
#### 8. 교차 피어 리뷰 이력
|
||||||
|
* F-1~F-8 및 R-1, R-2 총 10건의 피어 리뷰 이슈 도출 및 해소:
|
||||||
|
- F-1 (`Yes, try it` 팁 오탐 제거), F-2 (업셀 모달 선행 검사), F-3 (변수 스코프 격리), F-4 (리뷰어 실측 검증 후 자진 철회), F-5/F-6/F-7 (어댑터 팩트 연동 및 세션 패턴 보강), F-8 (비-클로드 어댑터 modal_tokens 계약 정립), R-1 (Fail-closed 페인 리졸버), R-2 (`WORKSPACE_ROOT` export 전파).
|
||||||
|
- 계획 단계 챌린지(`b9c29c3b`)를 통한 C-1 (`MAM_VERSION` 3자 락스텝) 및 C-2 (마이그레이션 안내) 수용.
|
||||||
|
|
||||||
### 🚀 `v3.0.1` — Herdr Shim Routing Contract Refactor, Multi-Workspace Isolation & 412-Test Milestone (2026-08-27)
|
### 🚀 `v3.0.1` — Herdr Shim Routing Contract Refactor, Multi-Workspace Isolation & 412-Test Milestone (2026-08-27)
|
||||||
|
|
||||||
> **주요 마일스톤**: Herdr 심 라우팅 5대 결함(ISSUE-1~5) 및 F-1~F-4 보완 완결, `HERDR_WORKSPACE_ID` 환경 변수 스코핑 및 파일 기반 격리 영속화 엔진 탑재, `pane send-text` 기반 단일 안전 삽입 계약 정립, 부분 문자열 매칭(`in tn`) 완전 제거, 412개 전체 테스트 100% PASS 달성.
|
> **주요 마일스톤**: Herdr 심 라우팅 5대 결함(ISSUE-1~5) 및 F-1~F-4 보완 완결, `HERDR_WORKSPACE_ID` 환경 변수 스코핑 및 파일 기반 격리 영속화 엔진 탑재, `pane send-text` 기반 단일 안전 삽입 계약 정립, 부분 문자열 매칭(`in tn`) 완전 제거, 412개 전체 테스트 100% PASS 달성.
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# ==============================================================================
|
||||||
|
# test_version_consistency.py — 3-Way Version Lockstep & Immutability Test Suite
|
||||||
|
# ==============================================================================
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
SKILL_NAMES = [
|
||||||
|
"multi-agent-mux-create",
|
||||||
|
"multi-agent-mux-stop",
|
||||||
|
"multi-agent-mux-resume",
|
||||||
|
"multi-agent-mux-status",
|
||||||
|
"multi-agent-mux-monitor",
|
||||||
|
"multi-agent-mux-delegate-job",
|
||||||
|
"multi-agent-mux-loop",
|
||||||
|
"multi-agent-mux-orc-onboard",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _get_lib_sh_mam_version():
|
||||||
|
cmd = f'source "{LIB_SH}" && echo "$MAM_VERSION"'
|
||||||
|
res = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, cwd=str(REPO_ROOT))
|
||||||
|
assert res.returncode == 0, f"Failed to source lib.sh: {res.stderr}"
|
||||||
|
return res.stdout.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_versions_md_versions():
|
||||||
|
text = VERSIONS_MD.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
# 1. Current release framework version
|
||||||
|
m_curr = re.search(r"-\s*\*\*프레임워크 버전\*\*:\s*`v(\d+\.\d+\.\d+)`", text)
|
||||||
|
assert m_curr, "Failed to parse Current Release framework version in VERSIONS.md"
|
||||||
|
current_framework_ver = m_curr.group(1)
|
||||||
|
|
||||||
|
# 2. Skill matrix table versions
|
||||||
|
table_matches = re.findall(r"\|\s*\*\*`([^`]+)`\*\*\s*\|\s*`(\d+\.\d+\.\d+)`\s*\|", text)
|
||||||
|
matrix_dict = dict(table_matches)
|
||||||
|
|
||||||
|
return current_framework_ver, matrix_dict
|
||||||
|
|
||||||
|
|
||||||
|
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}"
|
||||||
|
content = skill_file.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
# Strict frontmatter parsing
|
||||||
|
fm_match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
|
||||||
|
assert fm_match, f"No YAML frontmatter found in {skill_file}"
|
||||||
|
fm_data = yaml.safe_load(fm_match.group(1))
|
||||||
|
assert isinstance(fm_data, dict) and "version" in fm_data, f"No version in frontmatter of {skill_file}"
|
||||||
|
return str(fm_data["version"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_three_way_version_lockstep():
|
||||||
|
"""T-4: lib.sh(MAM_VERSION) == VERSIONS.md(Current + Matrix 8 items) == 8x SKILL.md frontmatters."""
|
||||||
|
# 1. lib.sh runtime constant
|
||||||
|
lib_ver = _get_lib_sh_mam_version()
|
||||||
|
assert lib_ver != "", "MAM_VERSION in lib.sh is empty"
|
||||||
|
|
||||||
|
# 2. VERSIONS.md
|
||||||
|
vmd_curr, vmd_matrix = _get_versions_md_versions()
|
||||||
|
assert lib_ver == vmd_curr, f"lib.sh MAM_VERSION ({lib_ver}) != VERSIONS.md current ({vmd_curr})"
|
||||||
|
|
||||||
|
for skill in SKILL_NAMES:
|
||||||
|
assert skill in vmd_matrix, f"Skill {skill} missing from VERSIONS.md matrix"
|
||||||
|
assert vmd_matrix[skill] == lib_ver, f"VERSIONS.md matrix for {skill} ({vmd_matrix[skill]}) != lib.sh ({lib_ver})"
|
||||||
|
|
||||||
|
# 3. 8x SKILL.md files
|
||||||
|
for skill in SKILL_NAMES:
|
||||||
|
fm_ver = _get_skill_md_frontmatter_version(skill)
|
||||||
|
assert fm_ver == lib_ver, f"{skill}/SKILL.md version ({fm_ver}) != lib.sh ({lib_ver})"
|
||||||
|
|
||||||
|
|
||||||
|
def test_mam_version_is_not_env_overridable():
|
||||||
|
"""T-0 (Constraint 1): MAM_VERSION cannot be spoofed by caller environment."""
|
||||||
|
cmd = f'source "{LIB_SH}" && echo "$MAM_VERSION"'
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["MAM_VERSION"] = "9.9.9"
|
||||||
|
res = subprocess.run(["bash", "-c", cmd], capture_output=True, text=True, env=env, cwd=str(REPO_ROOT))
|
||||||
|
assert res.returncode == 0
|
||||||
|
assert res.stdout.strip() != "9.9.9", "MAM_VERSION was improperly overwritten by caller environment"
|
||||||
|
assert res.stdout.strip() == _get_lib_sh_mam_version()
|
||||||
Reference in New Issue
Block a user