docs: add VERSIONS.md, resolve C-6 stop_session usage/comments drift, and prune LOG.md
This commit is contained in:
@@ -0,0 +1,391 @@
|
||||
# 📐 구현 계획서 Rev.2 — C-6: `stop_session.sh` 레거시 주석 및 구버전 사용법 정리
|
||||
|
||||
- **Job ID**: `32167a9d` (Rev.1 = `73b18819`)
|
||||
- **Planner**: claude (session: `herdr:canary-projects-multi-agent-mux-creator-claude`)
|
||||
- **Role**: Planner (`MULTI_AGENT_RULES.md` §1 — 본 작업에서 저장소 코드 0건 수정)
|
||||
- **반영 대상 Challenge**: `8b6b574f` (agy, Worker / Plan Reviewer) — `[VERDICT: PASS WITH CHALLENGE]`
|
||||
- **기준 커밋**: `5ed39f8` (`refactor`, 작업 트리에 미추적 `VERSIONS.md` 1건)
|
||||
- **백로그 항목**: C-6 / 로드맵 P2-3
|
||||
|
||||
---
|
||||
|
||||
## 0. 요약
|
||||
|
||||
**Challenge 는 타당합니다. 전면 수용합니다.** 격리 클론에서 실제 `mam_sandbox` 픽스처로 실행해 재현했습니다 — Rev.1 §4.2-(2) 는 4개 하위 케이스 중 **3개가 `rc=2` 로 실패**했을 것입니다.
|
||||
|
||||
다만 Rev.2 는 챌린저의 권고안을 그대로 채택하지 않고 **두 가지를 더합니다**.
|
||||
|
||||
1. 챌린저 권고(`valid_session` 사용)는 증상을 해소하지만, 가드를 **C-6 과 무관한 불변식**(`:91-100` 에이전트 접미사 명명 규칙)에 결합시킵니다. `rc=2` 가 **5가지 서로 다른 원인**에 공유되고 있다는 것이 이 오탐의 근본 원인이므로, Rev.2 는 종료 코드 대신 **stderr 메시지를 단언**해 원인 결합 자체를 제거합니다.
|
||||
2. 확정 가드를 **뮤테이션으로 검증하는 과정에서, 챌린저도 저도 놓쳤던 구멍 1건**을 찾았습니다 — Rev.1 이 §1.1 에 결함으로 등재한 `usage():41` 의 `--agent claude|agy` 과소 표기를, Rev.1·챌린저 양쪽 가드 모두 **탐지하지 못합니다**(M3). Rev.2 에서 닫았습니다.
|
||||
|
||||
| 항목 | Rev.1 | Rev.2 |
|
||||
|---|---|---|
|
||||
| §4.2-(2) 세션명 | `nosuch` (**오탐 — 3/4 rc=2**) | `test-project-creator-claude` |
|
||||
| §4.2-(2) 단언 | `rc != 2` 단독 | **stderr 메시지 단언** + `rc != 2` 보조 |
|
||||
| `usage()` 에이전트 목록 검증 | **없음 (M3 구멍)** | **추가** |
|
||||
| 가드 뮤테이션 검증 | 계획만 제시 | **3종 실측 완료** |
|
||||
| 나머지(§1~§3, §5, §7) | — | 변경 없음 |
|
||||
|
||||
---
|
||||
|
||||
## 1. Challenge 판정 — 수용 (실측 재현)
|
||||
|
||||
### 1.1 챌린저 지적의 사실 확인
|
||||
|
||||
챌린저가 인용한 블록은 실재합니다. 정확한 위치는 **`:91-100`**(챌린저 표기 `:92-100`), `exit 2` 는 **`:98`** 입니다.
|
||||
|
||||
```bash
|
||||
# stop_session.sh:91-100
|
||||
# --agent 미지정 시 이름 suffix 로 fallback (P1-F)
|
||||
if [ -z "$AGENT" ]; then
|
||||
case "$SESSION_NAME" in
|
||||
*-creator-claude|*-planner-claude|*-reviewer-claude) AGENT=claude ;;
|
||||
...
|
||||
*) echo "ERROR: cannot infer agent from '$SESSION_NAME'; pass --agent" >&2; exit 2 ;; # :98
|
||||
esac
|
||||
fi
|
||||
```
|
||||
|
||||
챌린저가 지적한 **실행 순서도 정확**합니다. YAML 존재 검사는 `:80`, 에이전트 추론은 `:91` 이므로 추론이 뒤에 옵니다. 그리고 `tests/conftest.py:15-52` 의 `mam_sandbox` 픽스처는 `agent-sessions.yaml` 을 **실제로 생성합니다**(`herdr_sessions: []`). 따라서 `:80` 은 통과하고 `:98` 에 도달합니다 — "샌드박스 상태에 따라 결과가 뒤바뀐다"는 챌린저의 우려가 아니라, **결정론적으로 항상 실패**합니다.
|
||||
|
||||
### 1.2 실측 — 격리 클론 + 실제 `mam_sandbox` 픽스처
|
||||
|
||||
`git clone --local --no-hardlinks` 로 만든 클론에 프로브 테스트를 넣어 측정했습니다.
|
||||
|
||||
| `--session` | 추가 인자 | rc | stderr 첫 줄 |
|
||||
|---|---|---|---|
|
||||
| `nosuch` | `--reason x` | **2** | `cannot infer agent from 'nosuch'` |
|
||||
| `nosuch` | `--purge-conversation` | **2** | `cannot infer agent from 'nosuch'` |
|
||||
| `nosuch` | `--yes` | **2** | `cannot infer agent from 'nosuch'` |
|
||||
| `nosuch` | `--agent hermes` | 1 | `session 'nosuch' not in …yaml` |
|
||||
| `test-project-creator-claude` | `--reason x` | 1 | `session … not in …yaml` |
|
||||
| `test-project-creator-claude` | `--purge-conversation` | 1 | `session … not in …yaml` |
|
||||
| `test-project-creator-claude` | `--yes` | 1 | `session … not in …yaml` |
|
||||
| `test-project-creator-claude` | `--agent hermes` | 1 | `session … not in …yaml` |
|
||||
| `test-project-creator-claude` | `--purge-conversation --yes` | 1 | `session … not in …yaml` |
|
||||
|
||||
**Rev.1 의 `assert r.returncode != 2` 는 4개 중 3개에서 실패**합니다(`--agent` 를 준 케이스만 추론을 건너뛰어 통과). Challenge 확정.
|
||||
|
||||
부수 확인: Rev.1 §9 한계에서 "`--purge-conversation` 을 `--yes` 없이 호출 시 rc=1 인지 rc=3 인지 구현 시 실측 필요"라고 남겼던 항목도 해소되었습니다 — **rc=1**(레지스트리 조회가 확인 프롬프트보다 먼저)입니다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 챌린저 권고안 평가 — 채택하되 보강
|
||||
|
||||
### 2.1 권고안은 작동합니다
|
||||
|
||||
`valid_session = "test-project-creator-claude"` 는 `*-creator-claude` 에 접미사 매칭되어 `AGENT=claude` 로 추론되고, 4개 케이스 전부 rc=1 로 끝납니다(위 표 하단 5행). **측정으로 확인했습니다.**
|
||||
|
||||
### 2.2 그러나 근본 원인은 세션명이 아니라 `rc=2` 의 과부하입니다
|
||||
|
||||
`stop_session.sh` 에서 `exit 2` 는 **5곳**에서 발생합니다.
|
||||
|
||||
| 행 | 원인 |
|
||||
|---|---|
|
||||
| `:67` | 폐지 플래그(`--mode`/`--capture-id`/`--graceful`) |
|
||||
| `:70` | `unknown arg` |
|
||||
| `:76` | `invalid agent type` |
|
||||
| `:79` | `--session` 누락 |
|
||||
| `:98` | **`cannot infer agent`** ← 이번 오탐의 원인 |
|
||||
|
||||
가드가 검증하려는 것은 오직 `:70` 하나("도움말이 광고하는 플래그를 파서가 unknown 으로 튕기지 않는다")인데, `rc != 2` 는 나머지 4개와 구별하지 못합니다. 챌린저의 `valid_session` 은 `:98` 만 회피할 뿐 **`:76`·`:79` 는 여전히 구별하지 못하며**, 더 나쁘게는 가드를 `:91-100` 의 **에이전트 접미사 명명 규칙에 결합**시킵니다. 훗날 역할명이 추가되거나 `creator` 가 개명되면, C-6 가드가 C-6 과 무관한 이유로 깨지고 실패 메시지도 C-6 을 가리키지 않습니다.
|
||||
|
||||
### 2.3 Rev.2 의 보강 — stderr 메시지 단언
|
||||
|
||||
```python
|
||||
assert "unknown arg" not in r.stderr # 파서가 이 플래그를 모른다고 하지 않았다
|
||||
assert "deprecated" not in r.stderr # 폐지 플래그로 취급하지도 않았다
|
||||
assert r.returncode != 2 # (보조) 위 둘을 빠져나간 rc=2 도 없다
|
||||
```
|
||||
|
||||
이 단언은 5개 원인 중 정확히 검증 대상인 것만 지목합니다. 실측 표에서 확인되듯 `nosuch` 케이스의 stderr 는 `cannot infer agent` 이므로 **메시지 단언만으로는 세션명이 무엇이든 통과**합니다 — 즉 챌린저 권고보다 엄밀히 더 견고합니다.
|
||||
|
||||
**두 가지를 모두 채택합니다**: 챌린저의 `valid_session`(원인 제거) + 메시지 단언(결합 제거). 어느 한쪽이 미래에 무력화돼도 다른 쪽이 남습니다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 🆕 Rev.2 신규 발견 — 가드가 `usage():41` 결함을 놓침 (M3)
|
||||
|
||||
확정 가드를 뮤테이션 검증하던 중 발견했습니다. **챌린저도 Rev.1 도 지적하지 못한 구멍입니다.**
|
||||
|
||||
Rev.1 §1.1 은 `usage():41` 의 `[--agent claude|agy]` 가 검증기(`:74-77`)의 4종 수용과 어긋난다고 **결함으로 등재**했습니다. 그런데 Rev.1·챌린저 양쪽 가드 모두 이 결함을 탐지하지 못합니다.
|
||||
|
||||
**뮤테이션 M3**: 수정된 클론에서 `usage()` 의 에이전트 목록만 `claude|agy` 로 되돌림
|
||||
|
||||
```
|
||||
결과: 1 passed ← 가드가 통과시킴 ❌
|
||||
```
|
||||
|
||||
C-6 이 고치기로 한 결함 중 하나가 가드 밖에 있었던 셈입니다. Rev.2 에서 다음 3줄로 닫았습니다.
|
||||
|
||||
```python
|
||||
for agent in ("claude", "agy", "hermes", "cline"):
|
||||
assert agent in res.stdout, f"usage() omits supported agent {agent}"
|
||||
```
|
||||
|
||||
**재검증**: 강화 후 baseline `1 passed`, M3 재적용 시 `1 failed`. 구멍이 닫혔음을 실측했습니다.
|
||||
|
||||
---
|
||||
|
||||
## 4. 확정 회귀 가드
|
||||
|
||||
### 4.1 설계 원칙 (Rev.1 §4.1 유지)
|
||||
|
||||
직전 리뷰 `31730364` 에서 뮤테이션으로 드러난 실패 사례 — `test_delegate_agent_resolution_and_fallback` 이 테스트 파일 안에 `case` 문을 복사해 실행한 탓에 생산 코드 결함을 완전히 되돌려도 통과 — 를 반복하지 않도록, 가드는 `stop_session.sh` 를 **직접 실행하고 그 파일을 직접 읽습니다**.
|
||||
|
||||
### 4.2 확정 코드 — `tests/test_tier2_component.py` 에 추가
|
||||
|
||||
```python
|
||||
def test_comp_stop_usage_matches_parser(mam_sandbox):
|
||||
"""C-6: help text and parser must not drift apart."""
|
||||
script = mam_sandbox / ".agents" / "skills" / "multi-agent-mux-stop" / "scripts" / "stop_session.sh"
|
||||
|
||||
# 에이전트 접미사 추론(:91-100)이 성립하는 이름 — rc=2 의 다섯 원인 중
|
||||
# 'cannot infer agent'(:98)를 배제하기 위함 (Challenge 8b6b574f)
|
||||
VALID = "test-project-creator-claude"
|
||||
|
||||
# 1) --help 는 성공하고, 폐지된 플래그를 광고하지 않는다
|
||||
res = subprocess.run(["bash", str(script), "--help"], capture_output=True, text=True)
|
||||
assert res.returncode == 0
|
||||
for dead in ("--mode", "--capture-id", "--graceful"):
|
||||
assert dead not in res.stdout, f"usage() still advertises {dead}"
|
||||
|
||||
# 1b) 검증기가 받는 에이전트는 전부 도움말에 나온다 (Rev.2 M3)
|
||||
for agent in ("claude", "agy", "hermes", "cline"):
|
||||
assert agent in res.stdout, f"usage() omits supported agent {agent}"
|
||||
|
||||
# 2) 도움말이 광고하는 플래그는 전부 파서가 받는다
|
||||
# rc=2 는 5가지 원인을 공유하므로 stderr 메시지로 직접 지목한다
|
||||
for flag, args in (("--reason", ["--reason", "x"]),
|
||||
("--purge-conversation", ["--purge-conversation"]),
|
||||
("--yes", ["--yes"]),
|
||||
("--agent", ["--agent", "hermes"])):
|
||||
r = subprocess.run(["bash", str(script), "--session", VALID] + args,
|
||||
capture_output=True, text=True)
|
||||
assert "unknown arg" not in r.stderr, f"usage() advertises {flag} but parser rejects it: {r.stderr}"
|
||||
assert "deprecated" not in r.stderr, f"usage() advertises deprecated {flag}: {r.stderr}"
|
||||
assert r.returncode != 2, f"{flag} -> rc=2: {r.stderr}"
|
||||
|
||||
# 3) 폐지된 플래그는 전용 메시지와 함께 rc=2 로 거부된다 (특별 취급 유지)
|
||||
for dead in ("--mode", "--capture-id", "--graceful"):
|
||||
r = subprocess.run(["bash", str(script), "--session", VALID, dead, "hard"],
|
||||
capture_output=True, text=True)
|
||||
assert r.returncode == 2
|
||||
assert "deprecated" in r.stderr
|
||||
|
||||
# 4) 헤더 주석도 폐지 플래그를 사용법으로 광고하지 않는다
|
||||
head = "".join(script.read_text().splitlines(keepends=True)[:35])
|
||||
assert "--mode soft|hard" not in head
|
||||
```
|
||||
|
||||
### 4.3 뮤테이션 검증 — Rev.2 에서 실측 완료
|
||||
|
||||
Rev.1 은 뮤테이션을 "구현자 필수 수행"으로 지시만 했으나, Rev.2 는 **계획 단계에서 직접 수행**했습니다. 격리 클론에 §3 단계 1~2 의 문서 수정을 적용한 뒤:
|
||||
|
||||
| # | 뮤테이션 | 기대 | 실측 |
|
||||
|---|---|---|---|
|
||||
| — | (baseline, 수정 적용 상태) | PASS | **1 passed** ✅ |
|
||||
| M1 | 파서에서 `--reason)` 분기 삭제 (도움말은 계속 광고) | FAIL | **1 failed** — `:19` `unknown arg` 단언 ✅ |
|
||||
| M2 | 헤더에 `[--mode soft\|hard]` 행 복원 | FAIL | **1 failed** — `:30` 헤더 단언 ✅ |
|
||||
| M3 | `usage()` 에이전트 목록을 `claude\|agy` 로 축소 | FAIL | 강화 전 **1 passed** ❌ → 강화 후 **1 failed** ✅ |
|
||||
|
||||
M1 이 가드의 핵심 가치를 증명합니다 — **도움말과 파서 중 한쪽만 바뀌면 즉시 실패**하며, 이것이 C-6 을 애초에 만든 드리프트입니다.
|
||||
|
||||
구현자는 위 표를 **재현**만 하면 됩니다(신규 설계 불필요).
|
||||
|
||||
---
|
||||
|
||||
## 5. 구현 계획 (Rev.1 대비 변경 없음)
|
||||
|
||||
### 단계 1 — 헤더 주석 교체 (`:2-30`, 29줄)
|
||||
|
||||
```bash
|
||||
# stop_session.sh — multi-agent-mux-stop 의 부속 스크립트
|
||||
# Usage:
|
||||
# bash stop_session.sh --session <name> [--agent claude|agy|hermes|cline] \
|
||||
# [--reason <reason>] [--purge-conversation] [--yes]
|
||||
#
|
||||
# 동작: 항상 graceful stop 입니다. send-keys 로 정상 종료를 유도하고
|
||||
# (미종료 시 SIGTERM → SIGKILL 폴백), kill 직전에 이 워크스페이스의
|
||||
# conversation id 를 row 에 확정 기록해 다음 resume 이 tier-1(race-free)
|
||||
# 으로 복원되게 합니다. status 는 running -> stopped 로 전이합니다.
|
||||
# 멱등: 이미 stopped 면 no-op + exit 0.
|
||||
#
|
||||
# 옵션:
|
||||
# --session <name> — 대상 세션 (필수)
|
||||
# --agent <type> — claude | agy | hermes | cline
|
||||
# (미지정 시 세션명 접미사로 추론; 추론 실패 시 exit 2)
|
||||
# --reason <reason> — 상태 전이 사유 (stop_reason). 기본값 manual_stop
|
||||
# --purge-conversation — 디스크의 conversation artifact 까지 삭제.
|
||||
# status=terminated, resumable=false 로 전이하며
|
||||
# resume 불가. --yes 없이는 확인 프롬프트(exit 3)
|
||||
# --yes — --purge-conversation 의 확인 프롬프트 생략
|
||||
#
|
||||
# 폐지된 옵션: --mode / --capture-id / --graceful 는 각각 exit 2 로 거부됩니다.
|
||||
# graceful 종료와 id 캡처는 이제 무조건 수행되며, soft/hard 모드
|
||||
# 구분은 --purge-conversation 유무로 대체되었습니다.
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 = success (or already-stopped no-op) | 1 = YAML not found / not registered
|
||||
# 2 = invalid args | 3 = interactive confirmation required (--yes 누락)
|
||||
# 4 = purge aborted (herdr session survived the kill chain)
|
||||
```
|
||||
|
||||
> **Rev.2 추가**: `--agent` 항목에 접미사 추론 동작(`:91-100`)을 한 줄 명기합니다. Challenge 가 드러냈듯 이 동작은 문서화되어 있지 않아 계획자·리뷰어 양쪽이 놓쳤던 부분입니다. C-6 의 취지("문서가 실제 동작과 일치할 것")에 정확히 부합합니다.
|
||||
|
||||
### 단계 2 — `usage()` 보강 (`:39-47`)
|
||||
|
||||
```bash
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 --session <name> [--agent claude|agy|hermes|cline] [--reason <reason>]
|
||||
[--purge-conversation] [--yes]
|
||||
|
||||
Arguments:
|
||||
--session <name> — target session name (required)
|
||||
--agent <type> — claude | agy | hermes | cline
|
||||
(inferred from the session-name suffix when omitted)
|
||||
--reason <reason> — stop_reason field (default: manual_stop)
|
||||
--purge-conversation — also delete on-disk conversation artifacts;
|
||||
status becomes terminated and resume is impossible
|
||||
--yes — skip the --purge-conversation confirmation prompt
|
||||
|
||||
Stop is always graceful and always captures the conversation id.
|
||||
(idempotent: stopping an already-stopped session is a no-op with exit 0)
|
||||
EOF
|
||||
}
|
||||
```
|
||||
|
||||
### 단계 3 — 내부 주석 3곳 + 경고 문자열 1곳
|
||||
|
||||
| 위치 | 조치 |
|
||||
|---|---|
|
||||
| `:157` | `# --capture-id: kill 직전에 …` → `# 캡처: kill 직전에 …` |
|
||||
| `:166` | `WARN: --capture-id requested but no conversation id resolved` → `WARN: no conversation id resolved before stop (nothing on disk yet)` |
|
||||
| `:172` | `# --graceful: send-keys 로 …` → `# graceful 종료: send-keys 로 …` |
|
||||
| `:257` | `# --capture-id: 항상 captured UUID 기록` → `# 항상 captured UUID 기록 (purge 가 아닐 때만)` |
|
||||
|
||||
### 단계 4 — `MESSAGING.md:346-348`
|
||||
|
||||
```
|
||||
| `stopped` | stopped via `multi-agent-mux-stop` (default); conversation preserved for resume | `stop` |
|
||||
| `terminated` | stopped with `--purge-conversation`, or herdr-dead detected; conversation deleted / session gone | `stop --purge-conversation`, `monitor` reconcile |
|
||||
| `archived` | legacy value — no producer since `--mode soft` was removed; kept in the validation whitelist for rows written by older versions | (none) |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 문서 동기화 (Rev.1 대비 변경 없음)
|
||||
|
||||
### 6.1 `IMPROVEMENTS.md` — 7곳
|
||||
|
||||
| 행 | 현재 | 변경 후 |
|
||||
|---|---|---|
|
||||
| `:3` | 최종 갱신일 `2026-08-16 (P3-1/A-4 …)` | 날짜·사유에 C-6 완료 반영 |
|
||||
| `:5` | 미해결 **6건** (… **레거시 1**) | 미해결 **5건** (… **레거시 0**) |
|
||||
| `:6` | 완료 **19건** | 완료 **20건**, 목록에 `C-6` 추가 |
|
||||
| `:107` | `## 4. … (Legacy Remnants — 1건)` | `… (Legacy Remnants — 0건 — 전원 완료)` (`:103` §3 표기법과 동일) |
|
||||
| `:109-110` | C-6 항목 | **삭제** (§5 로 이동) |
|
||||
| `:114` | `## 5. … (Completed Tasks — 19건)` | `… (Completed Tasks — 20건)` |
|
||||
| `:253` | `\| **P2-3** \| **C-6** \| 도움말 3줄 정정 \| 극소 \| — \|` | `… **(✅ 완료 — 가드 신설, 전체 263/263 PASS)** \|` |
|
||||
|
||||
§5 신규 항목:
|
||||
|
||||
```markdown
|
||||
### **C-6 (P2-3): `stop_session.sh` 레거시 주석 및 구버전 사용법 정리** — ✅ 완료
|
||||
- 헤더 주석이 광고하던 `--mode soft|hard` / `--capture-id` / `--graceful` 3종은 파서가 `exit 2` 로
|
||||
거부하는 폐지 플래그였습니다. 헤더 29줄을 현재 CLI 에 맞게 교체하고, `usage()` 에 누락돼 있던
|
||||
옵션 설명과 `--agent` 접미사 추론 동작을 보강했으며, Option B 이후 무의미해진 "워크스페이스에
|
||||
격리된" 표현과 내부 주석 3곳의 플래그 표기를 정리했습니다.
|
||||
- `MESSAGING.md` 상태 표가 제거된 플래그로 `stopped`/`terminated` 를 정의하던 것을 교정하고,
|
||||
생산자가 사라진 `archived` 를 레거시 값으로 명기했습니다.
|
||||
- 도움말과 파서의 일치를 강제하는 회귀 가드를 신설하고 뮤테이션 3종(M1~M3)으로 방어력을
|
||||
검증했습니다 — C-6 은 문서 과제라 기존 테스트가 전혀 잡지 못하던 영역입니다.
|
||||
```
|
||||
|
||||
**주의**: `:5` 의 "레거시 잔재 0건"과 `:107` §4 헤더는 **반드시 함께** 바꿉니다. 직전 3라운드 리뷰에서 이 쌍의 불일치가 매번 지적되었습니다.
|
||||
|
||||
### 6.2 `LOG.md`
|
||||
|
||||
`## 📌 1. 금일 작업 내용 요약` 아래 기존 `### 1) P3-1 …` **앞에** 신규 항목을 삽입하고 기존 P3-1 을 `### 2)` 로 조정합니다. 머리말 `- **최종 기록일시**` · `- **작업 상태**` 도 갱신합니다.
|
||||
|
||||
```markdown
|
||||
### 1) **C-6 (P2-3): `stop_session.sh` 레거시 주석 및 구버전 사용법 정리** — **완료**
|
||||
- **배경**: 헤더 주석이 폐지 플래그 3종을 사용법으로 광고했으나 파서는 전용 메시지와 함께
|
||||
`exit 2` 로 거부하고 있었음(실측). 백로그에는 "도움말 3줄"로 등재돼 있었으나 실제 대상은
|
||||
헤더 29줄 + `usage()` + 내부 주석 3곳 + `MESSAGING.md` 상태 표였음.
|
||||
- **주요 구현**: (파일별 변경 요약)
|
||||
- **검증**: `pytest` 263/263 PASS. 신규 가드에 대해 뮤테이션 M1~M3 전부 FAIL 확인.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. `archived` 사문 상태값 — Option A 확정
|
||||
|
||||
Rev.1 §7 에서 판단을 요청했고 **챌린저가 §4-3 에서 Option A 에 전적으로 동의**했으므로 확정합니다.
|
||||
|
||||
- **A. 현상 유지 + 문서 명기** — `atomic_yaml.py:18` 화이트리스트와 `reconcile.sh:474` 관용 목록은 손대지 않고, `MESSAGING.md` 에 "레거시 값, 현재 생산자 없음"을 명기 (§5 단계 4 에 반영 완료).
|
||||
- B(완전 은퇴)는 기존 데이터에 `archived` 행이 있으면 검증 실패로 **전체 쓰기가 막히므로** 마이그레이션이 필요합니다 — C-6("극소") 범위를 벗어납니다.
|
||||
|
||||
`MESSAGING.md` 를 C-6 범위에 포함하는 것도 챌린저가 §4-2 에서 동의했으므로 확정합니다.
|
||||
|
||||
---
|
||||
|
||||
## 8. 검증 절차
|
||||
|
||||
| # | 명령 / 확인 | 기대 |
|
||||
|---|---|---|
|
||||
| 1 | `bash -n .../stop_session.sh` | OK |
|
||||
| 2 | `bash stop_session.sh --help; echo $?` | rc=0, 폐지 플래그 미노출, 4개 에이전트 전부 노출 |
|
||||
| 3 | `--mode` / `--capture-id` / `--graceful` | rc=2 + `deprecated` 메시지 유지 |
|
||||
| 4 | `--agent bogus` | rc=2 (`invalid agent type`) |
|
||||
| 5 | `grep -rn -- "--mode soft" .agents/ *.md` | 0건 |
|
||||
| 6 | **뮤테이션 M1** — 파서에서 `--reason)` 삭제 | 가드 **FAIL** |
|
||||
| 7 | **뮤테이션 M2** — 헤더에 `--mode soft\|hard` 복원 | 가드 **FAIL** |
|
||||
| 8 | **뮤테이션 M3** — `usage()` 에이전트 목록 축소 | 가드 **FAIL** |
|
||||
| 9 | `pytest tests/ -q` | **263 passed** |
|
||||
| 10 | `env -u PYTHONPATH pytest tests/test_tier2_component.py -q` | 전부 통과 (환경 비의존) |
|
||||
| 11 | `IMPROVEMENTS.md` `:5` ↔ `:107` 대조 | 레거시 카운트 일치 |
|
||||
| 12 | `IMPROVEMENTS.md` `:6` ↔ `:114` 대조 | 둘 다 20건 |
|
||||
|
||||
9번은 약 6분 30초 소요됩니다(직전 실측 262 passed / 381.58s). 백그라운드 실행 권장.
|
||||
|
||||
10번 근거: 직전 라운드에서 신규 테스트가 주변 셸의 `PYTHONPATH` 에 의존해 CI 를 적색으로 만든 사례(N1)가 있었습니다. 확정 가드는 `subprocess.run(["bash", ...])` 만 쓰므로 해당 위험이 없으나 확인 절차는 유지합니다.
|
||||
|
||||
---
|
||||
|
||||
## 9. 변경 규모 및 리스크
|
||||
|
||||
| 파일 | 변경 |
|
||||
|---|---|
|
||||
| `stop_session.sh` | 헤더 29줄 교체, `usage()` 약 +10줄, 내부 주석 3곳 + 경고 문자열 1곳 |
|
||||
| `MESSAGING.md` | 3줄 |
|
||||
| `IMPROVEMENTS.md` | 7곳 + §5 신규 항목 |
|
||||
| `LOG.md` | 1개 블록 + 머리말 |
|
||||
| `tests/test_tier2_component.py` | +1 test |
|
||||
| **테스트 총계** | 262 → **263** |
|
||||
|
||||
| 리스크 | 평가 |
|
||||
|---|---|
|
||||
| 동작 회귀 | **없음.** 실행 경로 무변경. 유일한 예외 `:166` 경고 문자열은 단언하는 테스트 0건 확인 |
|
||||
| 가드 오탐 | **해소.** Challenge 원인(`:98`)을 세션명으로 제거하고, `rc=2` 과부하를 메시지 단언으로 우회 |
|
||||
| 가드 무력화 | **해소.** M1~M3 실측으로 방어력 증명 |
|
||||
| 카운트 불일치 재발 | §8 의 11·12번으로 차단 |
|
||||
|
||||
### 권장 커밋 분할
|
||||
|
||||
1. `docs(stop): rewrite stop_session.sh header and usage to match the current CLI (C-6)` — 단계 1~3
|
||||
2. `test(stop): guard help text against parser drift (C-6)` — §4
|
||||
3. `docs(messaging,improvements,log): sync status table and backlog for C-6` — 단계 4 + §6
|
||||
|
||||
2번을 1번 뒤에 두면, 가드가 1번 없이 실패하고 1번과 함께 통과함을 커밋 순서로 증명할 수 있습니다.
|
||||
|
||||
---
|
||||
|
||||
## 10. 한계
|
||||
|
||||
- 확정 가드는 **격리 클론에서 실행 검증**했으나, 저장소 본체에는 적용하지 않았습니다(Planner 역할). 클론은 검증 후 삭제했고 작업 트리는 계획 수립 전후 동일(`?? VERSIONS.md` 1건)합니다.
|
||||
- 뮤테이션 M1~M3 은 §5 단계 1~2 의 문서 수정을 클론에 **부분 적용**한 상태에서 수행했습니다(헤더 `--mode` 행 삭제 + `usage()` 확장). 단계 3·4 는 가드 대상이 아니므로 적용하지 않았습니다.
|
||||
- 전체 회귀(263)는 재실행하지 않았습니다. 262 passed / 381.58s 가 유효 기준이며 HEAD 가 `5ed39f8` 로 진행되었으므로 구현 시 재측정이 필요합니다.
|
||||
- `MESSAGING.md` 는 폐지 플래그 3종 검색으로 걸린 3줄만 확인했고 나머지는 감사하지 않았습니다.
|
||||
- `:91-100` 접미사 추론의 역할 목록(`creator`/`planner`/`reviewer`)이 실제 사용되는 역할 전부를 덮는지는 확인하지 않았습니다. C-6 범위 밖이며, 가드는 이 목록에 의존하지 않도록(§2.3) 설계했습니다.
|
||||
@@ -0,0 +1,233 @@
|
||||
# Cross-Code Review Report — Job 7ddb5350
|
||||
|
||||
- **Job ID**: 7ddb5350
|
||||
- **Target**: C-6 (P2-3) — `stop_session.sh` legacy comment and outdated usage text cleanup, `IMPROVEMENTS.md`/`LOG.md` synchronization, `MESSAGING.md` status table correction, regression guard addition, and `VERSIONS.md` creation
|
||||
- **Reviewer**: cline
|
||||
- **Output Report Path**: `.mam/jobs/7ddb5350/cline-reports/report-final.md`
|
||||
- **Base commit**: `5ed39f8` (fix(agents): harden shell adapter bridge and address double-check review feedback)
|
||||
- **Working-tree state**: 5 tracked modified files + 1 untracked new file (`VERSIONS.md`)
|
||||
|
||||
---
|
||||
|
||||
## 1. Delta Description
|
||||
|
||||
This changeset resolves backlog item C-6 (roadmap P2-3): cleaning up legacy comments and outdated usage text in `stop_session.sh` that advertised deprecated flags (`--mode soft|hard`, `--capture-id`, `--graceful`) as valid usage, while the parser rejects them with `exit 2`. The scope expanded beyond the brief's "3-line fix" estimate to cover all documentation surfaces with the same defect.
|
||||
|
||||
| File | Change Summary |
|
||||
|------|---------------|
|
||||
| `.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh` | Header comment block (29 lines) rewritten to match current CLI; `usage()` expanded with full argument descriptions; 3 internal comments + 1 warning string modernized; removed "워크스페이스에 격리된" (Option B obsolete terminology) |
|
||||
| `MESSAGING.md` | Session state table (3 rows) corrected: `stopped`/`terminated` now reference current CLI; `archived` marked as legacy with no producer |
|
||||
| `IMPROVEMENTS.md` | C-6 moved from §4 (open) to §5 (completed); header counts updated (6→5 open, 19→20 completed); roadmap P2-3 row updated with verification status |
|
||||
| `LOG.md` | New §1 entry for C-6 work; prior sections renumbered (duplicate "2)" numbering fixed); header timestamp updated |
|
||||
| `tests/test_tier2_component.py` | New regression guard `test_comp_stop_usage_matches_parser` (+45 lines): verifies help-parser consistency across 4 dimensions |
|
||||
| `VERSIONS.md` (new) | 135-line version history document covering v1.0.0–v2.0.0 changelog, skills version matrix, and verification standards |
|
||||
|
||||
**Net diff**: 5 files changed, 107 insertions(+), 45 deletions(-) + 1 new untracked file (135 lines).
|
||||
|
||||
---
|
||||
|
||||
## 2. Review Methodology
|
||||
|
||||
This review examines the changeset from three perspectives as required by the brief:
|
||||
|
||||
1. **Lint (정적 검사)**: Syntax validation, comment-code consistency, orphaned reference detection
|
||||
2. **Operability (동작성)**: Runtime behavior verification, parser-help alignment, exit code correctness
|
||||
3. **Loss (유실)**: Completeness of cleanup, documentation-code drift, regression guard effectiveness
|
||||
|
||||
---
|
||||
|
||||
## 3. Findings
|
||||
|
||||
### 3.1 Lint (정적 검사) — PASS
|
||||
|
||||
**V1: Bash syntax validation**
|
||||
- `bash -n stop_session.sh` → **OK** ✅
|
||||
- `bash -n lib.sh` → **OK** ✅
|
||||
|
||||
**V2: Header comment ↔ parser consistency**
|
||||
The header (lines 3–25) now documents exactly the 5 current CLI arguments and lists the 3 deprecated flags with their rejection behavior:
|
||||
|
||||
| Header advertises | Parser handles (line) | Match? |
|
||||
|---|---|---|
|
||||
| `--session <name>` | `:69` `--session) SESSION_NAME="$2"; shift 2` | ✅ |
|
||||
| `--agent claude\|agy\|hermes\|cline` | `:70` `--agent) AGENT="$2"; shift 2` + `:84` validation case | ✅ |
|
||||
| `--reason <reason>` | `:73` `--reason) REASON="$2"; shift 2` | ✅ |
|
||||
| `--purge-conversation` | `:71` `--purge-conversation) PURGE=1; shift` | ✅ |
|
||||
| `--yes` | `:72` `--yes) YES=1; shift` | ✅ |
|
||||
| Deprecated: `--mode`/`--capture-id`/`--graceful` → exit 2 | `:74-77` case → exit 2 | ✅ |
|
||||
|
||||
**V3: Orphaned deprecated-flag references in production code**
|
||||
- `grep -rn '--mode soft' .agents/ *.md` (excluding `.mam/` and `.agents/reports/`): **3 hits, all correct**:
|
||||
- `IMPROVEMENTS.md:114` — C-6 completed entry *describing* what was fixed (historical record) ✅
|
||||
- `LOG.md:12` — C-6 work log *describing* what was fixed (historical record) ✅
|
||||
- `MESSAGING.md:348` — `archived` row explaining `--mode soft` was removed (legacy documentation) ✅
|
||||
- **Zero orphaned references in production `.agents/` scripts** advertising deprecated flags as valid usage ✅
|
||||
|
||||
### 3.2 Operability (동작성) — PASS
|
||||
|
||||
**V4: `--help` output verification**
|
||||
```
|
||||
$ stop_session.sh --help; echo $?
|
||||
Usage: ... --session <name> [--agent claude|agy|hermes|cline] [--reason <reason>]
|
||||
[--purge-conversation] [--yes]
|
||||
Arguments:
|
||||
--session <name> — target session name (required)
|
||||
--agent <type> — claude | agy | hermes | cline
|
||||
--reason <reason> — stop_reason field (default: manual_stop)
|
||||
--purge-conversation — also delete on-disk conversation artifacts; ...
|
||||
--yes — skip the --purge-conversation confirmation prompt
|
||||
Stop is always graceful and always captures the conversation id.
|
||||
rc=0
|
||||
```
|
||||
- rc=0 ✅
|
||||
- No deprecated flags (`--mode`, `--capture-id`, `--graceful`) advertised ✅
|
||||
- All 4 agents (claude, agy, hermes, cline) listed ✅
|
||||
|
||||
**V5: Deprecated flag rejection**
|
||||
```
|
||||
$ stop_session.sh --session x --mode hard; echo $?
|
||||
rc=2
|
||||
```
|
||||
- `--mode`/`--capture-id`/`--graceful` all rejected with rc=2 and "deprecated" message ✅
|
||||
|
||||
**V6: MESSAGING.md ↔ code alignment**
|
||||
| MESSAGING.md state | Code behavior | Match? |
|
||||
|---|---|---|
|
||||
| `stopped` — "stopped via multi-agent-mux-stop (default)" | `stop_session.sh:257` `target['status'] = 'stopped'` (non-purge path) | ✅ |
|
||||
| `terminated` — "stopped with --purge-conversation" | `stop_session.sh:296-297` purge path removes entry, status becomes terminated | ✅ |
|
||||
| `archived` — "legacy value, no producer" | `atomic_yaml.py:18` whitelist retains `archived`; no code path produces it | ✅ |
|
||||
|
||||
**V7: `archived` whitelist retention (Option A)**
|
||||
- `atomic_yaml.py:18`: `valid = {'running', 'terminated', 'archived', 'stopped'}` — `archived` retained ✅
|
||||
- `reconcile.sh:474`: `if s.get('status') in ('terminated', 'archived', 'stopped'):` — `archived` retained ✅
|
||||
- MESSAGING.md documents this as intentional for backward compatibility with older rows ✅
|
||||
|
||||
### 3.3 Loss (유실) — PASS
|
||||
|
||||
**V8: Regression guard effectiveness**
|
||||
The new test `test_comp_stop_usage_matches_parser` verifies 4 dimensions of help-parser consistency:
|
||||
1. `--help` succeeds (rc=0) and does NOT advertise deprecated flags ✅
|
||||
2. All 4 supported agents appear in help text ✅
|
||||
3. All advertised flags (`--reason`, `--purge-conversation`, `--yes`, `--agent`) are accepted by parser (rc≠2, no "unknown arg"/"deprecated" in stderr) ✅
|
||||
4. Deprecated flags (`--mode`, `--capture-id`, `--graceful`) are rejected with rc=2 and "deprecated" message ✅
|
||||
5. Header comments (first 35 lines) do not contain `--mode soft|hard` ✅
|
||||
|
||||
The test uses `subprocess.run(["bash", ...])` only — no ambient `PYTHONPATH` dependency (N1 guard satisfied).
|
||||
|
||||
**V9: Clean-environment test**
|
||||
```
|
||||
$ env -u PYTHONPATH pytest tests/test_tier2_component.py::test_comp_stop_usage_matches_parser -v
|
||||
1 passed in 0.79s
|
||||
```
|
||||
Environment-independent ✅
|
||||
|
||||
**V10: IMPROVEMENTS.md count consistency**
|
||||
- Line 5: "총 추적 미해결 과제: 5건 (아키텍처 1건, 엣지케이스 4건, 오케스트레이션 0건, 레거시 잔재 0건)" → 1+4+0+0 = 5 ✅
|
||||
- Line 107: "Legacy Remnants — 0건 — 전원 완료" → matches header "레거시 잔재 0건" ✅
|
||||
- Line 6: "완료된 과제: 20건" → listed items count: 20 ✅
|
||||
- Line 111: "Completed Tasks — 20건" → matches header ✅
|
||||
- C-6 present in completed list (line 6) ✅
|
||||
|
||||
**V11: LOG.md section numbering fix**
|
||||
The old LOG.md had duplicate "### 2)" numbering (3 sections all numbered "2)"). The new LOG.md correctly numbers sections 1–5 sequentially. This is a welcome cleanup beyond the brief scope. ✅
|
||||
|
||||
**V12: VERSIONS.md (new file)**
|
||||
The new `VERSIONS.md` (135 lines) provides a structured version history covering:
|
||||
- Current release overview (v2.0.0)
|
||||
- Skills version matrix (8 skills, all v2.0.0)
|
||||
- Changelog for v1.0.0–v2.0.0
|
||||
- Verification standards (4-step QA process)
|
||||
|
||||
Content is consistent with the existing IMPROVEMENTS.md and LOG.md records. The file is currently untracked (`??`).
|
||||
|
||||
---
|
||||
|
||||
## 4. Full Test Suite Execution
|
||||
|
||||
**V13: Complete regression test**
|
||||
```
|
||||
$ pytest tests/ -q --tb=short
|
||||
........................................................................ [ 27%]
|
||||
........................................................................ [ 54%]
|
||||
........................................................................ [ 82%]
|
||||
........................................................................ [100%]
|
||||
263 passed in 384.59s (0:06:24)
|
||||
```
|
||||
|
||||
**Result: 263/263 PASS (100%)** — matches the IMPROVEMENTS.md and LOG.md claims exactly. ✅
|
||||
|
||||
Previous review (Job e7b9812b) had 259/259; this changeset adds 1 new test (262→263, with +3 from commit `5ed39f8` between reviews).
|
||||
|
||||
---
|
||||
|
||||
## 5. Minor Observations (Non-blocking)
|
||||
|
||||
### 5.1 MESSAGING.md "lib.sh valid-status set" reference (pre-existing)
|
||||
Line 341 says "Valid values (see `lib.sh` valid-status set)" but the actual validation is in `atomic_yaml.py:18`, not `lib.sh`. This is a pre-existing inaccuracy **not introduced by C-6** — the C-6 diff only changed the table rows, not this reference line. Mentioning for awareness; no action required for this job.
|
||||
|
||||
### 5.2 `CAPTURE_ID`/`GRACEFUL`/`STOP_MODE` variables remain hardcoded
|
||||
Lines 62–65 still hardcode `CAPTURE_ID=1`, `GRACEFUL=1`, `STOP_MODE=1`. The comment cleanup removed references to these as user-facing flags, but the variables themselves remain in the code (always-on). This is correct for C-6 scope — the task was documentation cleanup, not code refactoring. The variables are harmless (always-true conditions) and removing them would expand scope beyond "극소" difficulty.
|
||||
|
||||
### 5.3 VERSIONS.md untracked
|
||||
`VERSIONS.md` is currently an untracked file (`??` in git status). It should be committed alongside the other changes. The Planner's recommended commit split (§9 of Job 73b18819) does not explicitly mention VERSIONS.md — it may need to be added to the commit plan.
|
||||
|
||||
---
|
||||
|
||||
## 6. Scope Assessment
|
||||
|
||||
The brief described C-6 as "도움말 3줄 정정" (3-line help text fix). The actual implementation correctly identified that the defect spans:
|
||||
- Header comments: 29 lines (not 3)
|
||||
- `usage()` function: +10 lines expansion
|
||||
- Internal comments: 3 locations
|
||||
- Warning string: 1 location
|
||||
- `MESSAGING.md`: 3 rows (scope expansion, justified — same defect type)
|
||||
- Regression guard: 1 new test (justified — C-6 is a documentation task that no existing test covered)
|
||||
|
||||
The scope expansion is well-justified and documented in the Planner's report (Job 73b18819 §0). The Challenger (Job 8b6b574f) agreed to include `MESSAGING.md` and to adopt Option A for `archived`. All changes trace directly to the C-6 defect (help text advertising deprecated flags).
|
||||
|
||||
---
|
||||
|
||||
## 7. Risk Assessment
|
||||
|
||||
| Risk | Assessment |
|
||||
|---|---|
|
||||
| Behavior regression | **None.** No execution paths changed. Only comments, help text, and documentation modified. Warning string at `:175` changed but no test asserts on it. |
|
||||
| Guard false-positive | **Resolved.** Test uses valid session name (`test-project-creator-claude`) to avoid rc=2 from agent inference failure; uses stderr message assertions instead of brittle rc=2 overloading. |
|
||||
| Guard powerlessness | **Resolved.** Mutation testing M1–M3 (per Planner report) confirmed all 3 mutations cause FAIL. |
|
||||
| Count inconsistency | **Resolved.** IMPROVEMENTS.md header counts match section headers (V10). |
|
||||
| Environment dependency | **Resolved.** Clean-environment test passes (V9, N1 guard). |
|
||||
|
||||
---
|
||||
|
||||
## 8. Verification Summary
|
||||
|
||||
| # | Verification | Expected | Result |
|
||||
|---|---|---|---|
|
||||
| V1 | `bash -n stop_session.sh` | OK | ✅ OK |
|
||||
| V2 | Header ↔ parser consistency | All 5 flags + 3 deprecated match | ✅ Match |
|
||||
| V3 | Orphaned deprecated refs in production | 0 | ✅ 0 |
|
||||
| V4 | `--help` output | rc=0, no deprecated flags, 4 agents | ✅ Pass |
|
||||
| V5 | `--mode hard` rejection | rc=2 + deprecated | ✅ Pass |
|
||||
| V6 | MESSAGING.md ↔ code alignment | 3 states match | ✅ Pass |
|
||||
| V7 | `archived` whitelist retention | Retained + documented | ✅ Pass |
|
||||
| V8 | Regression guard (4 dimensions) | All pass | ✅ Pass |
|
||||
| V9 | Clean-environment test (N1) | Pass without PYTHONPATH | ✅ Pass |
|
||||
| V10 | IMPROVEMENTS.md count consistency | 5 open, 20 completed, 0 remnants | ✅ Pass |
|
||||
| V11 | LOG.md section numbering | Sequential 1–5 | ✅ Pass |
|
||||
| V12 | VERSIONS.md content | Consistent with records | ✅ Pass |
|
||||
| V13 | Full test suite | 263/263 PASS | ✅ 263 passed in 384.59s |
|
||||
|
||||
---
|
||||
|
||||
## 9. Verdict
|
||||
|
||||
The C-6 implementation is a thorough and well-executed documentation cleanup that:
|
||||
- Correctly identifies the full scope of the defect (29-line header, not 3 lines)
|
||||
- Aligns all documentation surfaces (header, `usage()`, internal comments, `MESSAGING.md`) with the actual parser behavior
|
||||
- Adds a meaningful regression guard that prevents future help-parser drift
|
||||
- Retains `archived` in the validation whitelist with proper documentation (Option A)
|
||||
- Passes the complete test suite (263/263, 100%)
|
||||
|
||||
No behavior regression, no orphaned references, no count inconsistencies, and no environment dependencies. The three minor observations (§5) are pre-existing or out-of-scope and do not block the verdict.
|
||||
|
||||
[VERDICT: PASS]
|
||||
@@ -1,28 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
# stop_session.sh — multi-agent-mux-stop 의 부속 스크립트
|
||||
# Usage:
|
||||
# bash stop_session.sh --session <name> [--agent claude|agy] \
|
||||
# [--mode soft|hard] [--purge-conversation] [--yes]
|
||||
# bash stop_session.sh --session <name> [--agent claude|agy|hermes|cline] \
|
||||
# [--reason <reason>] [--purge-conversation] [--yes]
|
||||
#
|
||||
# mode:
|
||||
# soft — YAML 을 status=archived 로 마크, herdr 세션은 그대로 둠 (P1-A:
|
||||
# terminated 는 herdr 가 실제로 죽은 상태에만 사용)
|
||||
# hard — herdr kill-session + YAML status=terminated
|
||||
# --purge-conversation: --mode hard 일 때만. 삭제 대상 세션의 *워크스페이스에
|
||||
# 격리된* conversation artifact 만 삭제 (P0-C). 전역
|
||||
# agent_identities 를 참조하지 않음. resume 불가.
|
||||
# 동작: 항상 graceful stop 입니다. send-keys 로 정상 종료를 유도하고
|
||||
# (미종료 시 SIGTERM → SIGKILL 폴백), kill 직전에 이 워크스페이스의
|
||||
# conversation id 를 row 에 확정 기록해 다음 resume 이 tier-1(race-free)
|
||||
# 으로 복원되게 합니다. status 는 running -> stopped 로 전이합니다.
|
||||
# 멱등: 이미 stopped 면 no-op + exit 0.
|
||||
#
|
||||
# Stop extension (Option A — stop 확장, 새 6번째 스킬 없이 stop 의미론 흡수):
|
||||
# --capture-id — kill 직전에 이 워크스페이스의 conversation id 를 row 에 확정
|
||||
# 기록 (claude_session_id_own / agy_conversation_id_own) →
|
||||
# 다음 resume 이 tier-1(race-free) 로 복원. find_workspace_uuid
|
||||
# 재사용 (per-row -> workspace-scoped disk scan -> cache).
|
||||
# --reason R — 상태 전이 사유 (stop_reason). 기본값 manual_stop.
|
||||
# --graceful — kill-session 즉시 종료 대신 send-keys 로 정상 종료 유도 →
|
||||
# 3초 대기 → 미종료 시 kill-session(SIGTERM) → 5초 → SIGKILL.
|
||||
# 위 세 옵션 중 하나라도 주면 STOP 모드: status 가 terminated 가 아니라 stopped
|
||||
# 로 전이 (running -> stopped). 멱등: 이미 stopped 면 no-op + exit 0.
|
||||
# 옵션 미지정 시 기존 hard/soft 동작 그대로 (backward compatible).
|
||||
# 옵션:
|
||||
# --session <name> — 대상 세션 (필수)
|
||||
# --agent <type> — claude | agy | hermes | cline
|
||||
# (미지정 시 세션명 접미사로 추론; 추론 실패 시 exit 2)
|
||||
# --reason <reason> — 상태 전이 사유 (stop_reason). 기본값 manual_stop
|
||||
# --purge-conversation — 디스크의 conversation artifact 까지 삭제.
|
||||
# status=terminated, resumable=false 로 전이하며
|
||||
# resume 불가. --yes 없이는 확인 프롬프트(exit 3)
|
||||
# --yes — --purge-conversation 의 확인 프롬프트 생략
|
||||
#
|
||||
# 폐지된 옵션: --mode / --capture-id / --graceful 는 각각 exit 2 로 거부됩니다.
|
||||
# graceful 종료와 id 캡처는 이제 무조건 수행되며, soft/hard 모드
|
||||
# 구분은 --purge-conversation 유무로 대체되었습니다.
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 = success (or already-stopped no-op) | 1 = YAML not found / not registered
|
||||
@@ -38,11 +38,20 @@ source "$_lib_sh"
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 --session <name> [--agent claude|agy] [--purge-conversation] [--yes] [--reason <reason>]
|
||||
Usage: $0 --session <name> [--agent claude|agy|hermes|cline] [--reason <reason>]
|
||||
[--purge-conversation] [--yes]
|
||||
|
||||
Stop arguments:
|
||||
--reason <reason> — stop_reason field (default: manual_stop)
|
||||
(idempotent: stopping an already-stopped session is a no-op with exit 0)
|
||||
Arguments:
|
||||
--session <name> — target session name (required)
|
||||
--agent <type> — claude | agy | hermes | cline
|
||||
(inferred from the session-name suffix when omitted)
|
||||
--reason <reason> — stop_reason field (default: manual_stop)
|
||||
--purge-conversation — also delete on-disk conversation artifacts;
|
||||
status becomes terminated and resume is impossible
|
||||
--yes — skip the --purge-conversation confirmation prompt
|
||||
|
||||
Stop is always graceful and always captures the conversation id.
|
||||
(idempotent: stopping an already-stopped session is a no-op with exit 0)
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -154,7 +163,7 @@ if herdr has-session -t "$SESSION_NAME" 2>/dev/null; then
|
||||
LAST_STATUS=$(herdr capture-pane -t "$SESSION_NAME" -p -S -10 2>/dev/null | tr '\n' ' ' | head -c 500 || true)
|
||||
fi
|
||||
|
||||
# --capture-id: kill 직전에 conversation id 를 해결 (process/jsonl 이 아직 살아있을 때).
|
||||
# 캡처: kill 직전에 conversation id 를 해결 (process/jsonl 이 아직 살아있을 때).
|
||||
# find_workspace_uuid 가 tier-1(row) -> tier-2(workspace-scoped disk scan) -> tier-3(cache)
|
||||
# 를 알아서 시도하므로 herdr 생사와 무관하게 동작.
|
||||
CAPTURED_UUID=""
|
||||
@@ -163,13 +172,13 @@ if [ "$CAPTURE_ID" = "1" ] && [ -n "$TARGET_CWD" ]; then
|
||||
if [ -n "$CAPTURED_UUID" ]; then
|
||||
echo "captured conversation id: $CAPTURED_UUID"
|
||||
else
|
||||
echo "WARN: --capture-id requested but no conversation id resolved (nothing on disk yet)"
|
||||
echo "WARN: no conversation id resolved before stop (nothing on disk yet)"
|
||||
fi
|
||||
fi
|
||||
|
||||
delegate_publish_event "$DELEGATE_JOB_ID" progress "terminating"
|
||||
|
||||
# --graceful: send-keys 로 정상 종료 유도 → 폴백 체인 (SIGTERM → SIGKILL).
|
||||
# graceful 종료: send-keys 로 정상 종료 유도 → 폴백 체인 (SIGTERM → SIGKILL).
|
||||
graceful_stop() {
|
||||
local pane_pid exitkey
|
||||
pane_pid=$(herdr list-panes -t "$SESSION_NAME" -F '#{pane_pid}' 2>/dev/null | head -1 || true)
|
||||
@@ -254,7 +263,7 @@ if not purge:
|
||||
if last_status:
|
||||
target['last_visible_status_at_termination'] = last_status
|
||||
|
||||
# --capture-id: 항상 captured UUID 기록 (purge가 아닐 때만)
|
||||
# 항상 captured UUID 기록 (purge 가 아닐 때만)
|
||||
if captured and not purge:
|
||||
if agent == 'claude':
|
||||
target['claude_session_id_own'] = captured
|
||||
|
||||
+11
-9
@@ -1,9 +1,9 @@
|
||||
# 🛠️ Multi-Agent Mux 종합 개선 및 미해결 과제 백로그 (`IMPROVEMENTS.md`)
|
||||
|
||||
- **최종 갱신일**: 2026-08-16 (P3-1/A-4 Phase 2 M2~M7 에이전트 지식 계층 및 Option B / C-3b 완료, Reviewer 피드백 반영, 전체 259/259 회귀 통과 반영)
|
||||
- **최종 갱신일**: 2026-08-17 (C-6/P2-3 stop_session.sh 레거시 주석 및 구버전 사용법 정리 완료, 회귀 가드 신설, 전체 263/263 회귀 통과 반영)
|
||||
- **통합 관리 대상**: 기존 `CODEBASE_REVIEW_REPORT.md` + `OPTIMIZATION.md`
|
||||
- **총 추적 미해결 과제**: **6건** (아키텍처 1건, 엣지케이스 4건, 오케스트레이션 0건, 레거시 잔재 1건)
|
||||
- **완료된 과제**: **19건** (A-1, A-3, A-4, A-5, B-1, B-3, B-4, B-7, B-8, C-1, C-2, C-3b, O-1, O-2, O-3, O-4-OrcOnboard, Herdr-0.8.0-Compat-SanitizeHash, P2-1-DelegateJobSafe-TrapFix, P2-2-C3a-C4-LegacyCleanup)
|
||||
- **총 추적 미해결 과제**: **5건** (아키텍처 1건, 엣지케이스 4건, 오케스트레이션 0건, 레거시 잔재 0건)
|
||||
- **완료된 과제**: **20건** (A-1, A-3, A-4, A-5, B-1, B-3, B-4, B-7, B-8, C-1, C-2, C-3b, C-6, O-1, O-2, O-3, O-4-OrcOnboard, Herdr-0.8.0-Compat-SanitizeHash, P2-1-DelegateJobSafe-TrapFix, P2-2-C3a-C4-LegacyCleanup)
|
||||
|
||||
---
|
||||
|
||||
@@ -104,14 +104,16 @@
|
||||
|
||||
---
|
||||
|
||||
## 4. ⚪ 레거시 잔재 및 죽은 코드 (Legacy Remnants — 1건)
|
||||
|
||||
### **C-6: `stop_session.sh` 도움말 문서 구버전 표기**
|
||||
- 스크립트 도움말에는 `--mode soft|hard` 등이 서술되어 있으나 실제 옵션 파서는 `exit 2`로 거부합니다.
|
||||
## 4. ⚪ 레거시 잔재 및 죽은 코드 (Legacy Remnants — 0건 — 전원 완료)
|
||||
|
||||
---
|
||||
|
||||
## 5. 🎉 완료된 과제 (Completed Tasks — 19건)
|
||||
## 5. 🎉 완료된 과제 (Completed Tasks — 20건)
|
||||
|
||||
### **C-6 (P2-3): `stop_session.sh` 레거시 주석 및 구버전 사용법 정리** — ✅ 완료
|
||||
- 헤더 주석이 광고하던 `--mode soft|hard` / `--capture-id` / `--graceful` 3종은 파서가 `exit 2` 로 거부하는 폐지 플래그였습니다. 헤더 29줄을 현재 CLI 에 맞게 교체하고, `usage()` 에 누락돼 있던 옵션 설명과 `--agent` 접미사 추론 동작을 보강했으며, Option B 이후 무의미해진 "워크스페이스에 격리된" 표현과 내부 주석 3곳의 플래그 표기를 정리했습니다.
|
||||
- `MESSAGING.md` 상태 표가 제거된 플래그로 `stopped`/`terminated` 를 정의하던 것을 교정하고, 생산자가 사라진 `archived` 를 레거시 값으로 명기했습니다.
|
||||
- 도움말과 파서의 일치를 강제하는 회귀 가드 `test_comp_stop_usage_matches_parser` 를 신설하고 뮤테이션 3종(M1~M3)으로 방어력을 검증했습니다 — C-6 은 문서 과제라 기존 테스트가 전혀 잡지 못하던 영역입니다.
|
||||
|
||||
### **P3-1 (A-4 Phase 2 / Option B / C-3b / M2~M7): 에이전트 지식 계층 어댑터 일원화 및 isolation.root 완전 폐기** — ✅ 완료
|
||||
- 에이전트별 아티팩트 경로, 검증 로직, 재개/시작 스펙, 토큰, 종료 키, 인증(`auth_ok`), 자동 발견(`discover`)을 `BaseAgentAdapter` 및 4개 구체 어댑터(`claude`, `agy`, `hermes`, `cline`)로 이관하고, CLI facts bridge(`shlex.quote`) 및 서브커맨드(`spawn-spec`, `resume-spec`, `exit-key`)를 구축했습니다.
|
||||
@@ -250,7 +252,7 @@
|
||||
| **P1-2** | **B-8** | agy 주입 시 `return 0` 우회 제거 및 제출 검증 루프 이관 **(✅ 완료 — tests/test_b8_send_keys_verification.py 1/1 PASS)** | 소 | A-4 M0 |
|
||||
| **P2-1** | **B-6 / B-12** | 스킬 트리 내 임시 사본 및 서브셸 EXIT 트랩으로 인한 루프 락 조기 해제 차단 **(✅ 완료 — tests/test_o3_scoped_guard.py 27/27 PASS, commit b490713)** | 소 | — |
|
||||
| **P2-2** | **C-3a + C-4** | 빈 스텁 4종 + 공허한 테스트 4건 + 죽은 심볼 3종 제거 및 `--isolate` no-op 회귀 가드 신설 **(✅ 완료 — tests/test_tier1_unit.py + test_tier2_component.py 256/256 PASS)** | 소 | — |
|
||||
| **P2-3** | **C-6** | 도움말 3줄 정정 | 극소 | — |
|
||||
| **P2-3** | **C-6** | `stop_session.sh` 헤더/도움말/주석/MESSAGING.md 정리 및 회귀 가드 신설 **(✅ 완료 — tests/test_tier2_component.py 가드 신설, 전체 263/263 PASS)** | 극소 | — |
|
||||
| **P3-1** | **A-4 M2~M7** | 어댑터 본이관 및 CLI facts 브리지/서브커맨드 구축 **(✅ 완료 — tests/test_a4_adapter_contract.py 9/9 PASS, 전체 259/259 PASS)** | 대 | P1-1 |
|
||||
| **P3-2** | **B-10** | tier-3 신원 캐시 존치/제거 결정 + PyYAML 의존 완화 | 중 | A-4 M2 |
|
||||
| **P3-3** | **C-3b** | `isolation.root` 4개 소비자 완전 폐기 (Option B 채택) **(✅ 완료 — 전체 259/259 PASS)** | 소 | A-4 M2 |
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
# 📝 Multi-Agent Mux 작업 세션 기록 (`LOG.md`)
|
||||
|
||||
- **최종 기록일시**: 2026-08-16 10:00 (KST)
|
||||
- **작업 저장소**: `tmpl/multi-agent-mux` (Branch: `main`)
|
||||
- **작업 상태**: 모든 작업 완료, 세션 안전 종료(stopped), 저장소 상태 Clean!
|
||||
|
||||
---
|
||||
|
||||
## 📌 1. 금일 작업 내용 요약
|
||||
|
||||
### 1) **P3-1 (A-4 Phase 2 / Option B / C-3b / M2~M7): 에이전트 지식 계층 마이그레이션 및 isolation.root 완전 폐기** — **완료**
|
||||
- **배경**: 에이전트별 아티팩트 경로, 검증 로직, 재개/시작 스펙, 토큰, 종료 키, 인증(`auth_ok`), 자동 발견(`discover`)이 스크립트 전반에 하드코딩 산재되어 있던 문제(A-4)와, Universal Global Config 전환 후에도 4개 지점에 남아있던 `isolation.root` 소비자(C-3b)를 완전 폐기하고 어댑터 단일 소스로 일원화.
|
||||
- **주요 구현**:
|
||||
- [`.agents/skills/lib_py/agents/base.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/agents/base.py): `DiscoveryContext` 확장 (`ws_key`, `cwd`, `home_dir`, `claude_dir`, `epoch`, `row`, `mode`), `BaseAgentAdapter` 추상 인터페이스 정의 (`ready_tokens`, `exit_key`, `delegate_agent_key`, `identity_cache_fields`, `artifact_path`, `verify_artifact`, `purge_artifacts`, `spawn_spec`, `resume_spec`, `auth_ok`, `discover`).
|
||||
- [`.agents/skills/lib_py/agents/adapters/`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/agents/adapters/): `claude.py`, `agy.py`, `hermes.py`, `cline.py` 4개 어댑터 구체 클래스 구현 (Cline `resume_spec` `-i --id` 수정 반영, `auth_ok`, `discover` 구현).
|
||||
- [`.agents/skills/lib_py/agents/__main__.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/agents/__main__.py): 8개 `MAM_*` 변수 `shlex.quote` 셸 브리지 완성.
|
||||
- [`.agents/skills/lib_py/verify_session.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/verify_session.py): `adapter.verify_artifact(uuid, ctx)` 위임 및 `iso_root` 분기 제거.
|
||||
- [`.agents/skills/lib_py/workspace_uuid.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/workspace_uuid.py): `iso_root_of` 제거 및 디스크 스캔을 `adapter.discover(ctx)`로 단일화.
|
||||
- [`.agents/skills/lib_py/atomic_yaml.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/atomic_yaml.py): 레거시 `isolation` 유효성 검사 절 제거.
|
||||
- [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh): `mam_session_iso_root` 제거, `wait_for_tui_ready` 셀프 컨테인드 토큰 폴백 및 claude `projects` 토큰 제거.
|
||||
- [`.agents/skills/multi-agent-mux-create/scripts/create_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-create/scripts/create_session.sh): `CMD_FULL` (어댑터 `spawn_spec`) 및 `delegate_agent` (`delegate_agent_key`) 이관.
|
||||
- [`.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh): `_iso_root` 분기 완전 제거 및 `CMD_FULL` 을 `adapter.resume_spec`으로 이관.
|
||||
- [`.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh): `row_agent` / `_pin_and_verify_resume` / `OWN_KEY_BY_AGENT` / auto-register `cmd_full` 을 어댑터 레이어로 이관.
|
||||
- [`.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh): `exitkey` (`adapter.exit_key`), `adapter.purge_artifacts`, `adapter.identity_cache_fields` 위임 및 레거시 격리 삭제 블록 제거.
|
||||
- [`tests/test_a4_adapter_contract.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_a4_adapter_contract.py): facts eval 계약, 어댑터 속성 계약, 복합 아티팩트 삭제(purge_artifacts), spawn/resume_spec 계약, auth_ok 계약, discover 계약 테스트 9종 추가.
|
||||
- [`IMPROVEMENTS.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/IMPROVEMENTS.md): A-4 및 C-3b 완료 처리 및 19개 과제 완결 상태 동기화.
|
||||
- **검증**: `pytest` 실행 결과 **259 passed in 493s (100%)**.
|
||||
|
||||
### 2) **P2-2 (C-3a / C-4): 레거시 격리 스텁 및 미사용 심볼 제거** — **완료**
|
||||
- **배경**: 격리 구조가 Universal Global Config(Job `536a6625`)로 전환되며 남은 빈 스텁 4종과, 그 빈 출력만 재확인하던 공허한 테스트 4건, 그리고 참조 0회 심볼 3종 정리.
|
||||
- **주요 구현**:
|
||||
- [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh): 빈 스텁 4종(`provision_isolation`, `isolation_lever`, `isolation_env_prefix`, `isolation_cmd_args`) 및 `_REAL_HERDR_PATH` 대입·export 제거, 주석에 C-3b 경계 명시.
|
||||
- [`.agents/skills/multi-agent-mux-delegate-job/scripts/registry.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-delegate-job/scripts/registry.py): `TERMINAL_STATUSES` 제거.
|
||||
- [`.agents/skills/multi-agent-mux-create/scripts/create_session.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-create/scripts/create_session.sh): `ISOLATE` 제거.
|
||||
- [`tests/test_tier1_unit.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_tier1_unit.py) / [`tests/test_tier2_component.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_tier2_component.py): 공허한 테스트 4건 제거 및 `--isolate`/`--no-isolate` no-op 회귀 가드 1건 신설(변이 4종 검출 입증), 섹션 헤더 동기화.
|
||||
- [`IMPROVEMENTS.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/IMPROVEMENTS.md): C-4 완결 및 C-3a 완료 반영, C-3b 존속.
|
||||
- **검증**: `pytest tests/ -q` **256 passed (100%)**.
|
||||
|
||||
### 2) **P2-1 (B-6 / B-12): `delegate_job_safe` 임시 사본 제거 및 서브셸 루프 락 조기 해제 차단 조치** — **완료**
|
||||
- **배경**: `run_loop.sh::delegate_job_safe` 가 `.agents/skills/...` 내부에 `.tmp` 사본을 생성하여 트리 오염 및 배포 시 유출(B-6)되던 문제와, 명령 치환 서브셸 내의 `trap _mam_release_guard EXIT` 로 인해 첫 번째 잡 위임 시 루프 락 마커(`.mam/loop-guard-active`)가 조기 삭제되어 O-3 가드레일이 무력화되던 결함(**B-12 / D1**) 조치.
|
||||
- **주요 구현**:
|
||||
- [`.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh): `delegate_job_safe` 를 임시 사본 및 서브셸 트랩 없이 인플레이스로 직접 실행(`bash "$orig_script" "$@"`)하도록 개선하고 실패 시 진단 로깅 추가. 루프 기동 시 기존 잔여 `.tmp` 스윕 구문 추가.
|
||||
- [`IMPROVEMENTS.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/IMPROVEMENTS.md): B-6 완료 상태 갱신, B-12 (D1) 결함 명세 및 B-13 (턴 간 스킬 오염) Stage 2 과제 등록.
|
||||
- [`tests/test_o3_scoped_guard.py`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_o3_scoped_guard.py): 취약한 문자열 검사 Z-9를 4개 행위 기반 테스트(`test_z9_loop_lock_survives_delegation`, `test_z9_probe_detects_the_defect`, `test_z9_no_tmp_copy_left_in_skill_tree`, `test_z9_exit_code_and_diagnostics_propagation`)로 교체.
|
||||
- **검증**: `pytest tests/ -q` 실행 결과 **259 passed (100%)** 달성.
|
||||
|
||||
### 2) **multi-agent-mux-orc-onboard: 오케스트레이터 온보딩 스킬 및 `orchestrator_uuids` 배제 게이트 구축** — **완료**
|
||||
- **배경**: 오케스트레이터(`agy`)가 서브 에이전트 생성/정지/복원 시 자기 대화 UUID가 `agent-sessions.yaml` 서브 세션으로 오염 캡처되어 SQLite DB 락(`database is locked`) 및 대화 충돌이 발생하던 결함 조치.
|
||||
- **주요 구현**:
|
||||
- [`.agents/skills/multi-agent-mux-orc-onboard/SKILL.md`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-orc-onboard/SKILL.md) 및 [`.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-orc-onboard/scripts/orc_onboard.sh): 오케스트레이터의 신원 UUID를 포착하여 `.mam/agent-sessions.yaml` 및 SQLite DB 내 `orchestrator_uuids` 리스트로 원자적 등록하는 스킬 구축.
|
||||
- [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh): `find_workspace_uuid` 및 `verify_session_uuid`에 `orchestrator_uuids` 배제 게이트를 내장하여 오케스트레이터 대화 ID 스킵(Skip) 확립.
|
||||
- `tests/test_orc_onboard.py`: 전용 회귀 테스트 40개 작성 및 **40/40 PASS (100%)** 달성.
|
||||
- **멀티에이전트 자율 오케스트레이션**: `/multi-agent-mux-loop --plan --all-reviewer` 가동 결과 Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3자에 의해 **`[VERDICT: PASS]` (만장일치 통과)**.
|
||||
|
||||
### 2) **P0-2 (O-2): 동일 워크스페이스 내 중복 루프 기동 방지 원자적 락 및 마커 소유권 대조 삭제 조치** — **완료**
|
||||
- **배경**: 루프 중복 기동 시 마커 무단 덮어쓰기로 인한 데이터 오염 및 먼저 종료된 루프 인스턴스의 무차별 마커 삭제로 O-3 위임 가드레일이 조용히 무력화되던 결함 조치.
|
||||
- **주요 구현**:
|
||||
- [`.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` 기반 원자적 락 획득, `pid` + `lstart` 신원 대조 검증 및 중복 루프 기동 차단 모듈 구현.
|
||||
- [`.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh): `_mam_release_guard` 종료 트랩 시 `pid` + `lstart` 소유권 대조 검증 삭제 구현.
|
||||
- `tests/test_o2_race_free_lock.py`: 전용 회귀 테스트 22개 작성 및 **22/22 PASS (100%)** 달성. 전체 회귀 테스트 **46/46 PASS (100%)**.
|
||||
|
||||
### 2) **P0-1 (B-7): `run_loop.sh` 루프 기동 외곽 diff 누락 및 신규 미추적 파일 캡처 결함 조치** — **완료**
|
||||
- **배경**: CWD 의존성으로 인해 저장소 외곽에서 `run_loop.sh` 구동 시 `git diff` 실패 및 미추적 신규 파일(Untracked Files) 누락으로 리뷰어가 빈 diff 보고 무조건 `PASS`를 남기던 무음 검증 결함 조치.
|
||||
- **주요 구현**:
|
||||
- [`.agents/skills/multi-agent-mux-loop/scripts/diff_collect.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/diff_collect.sh): CWD 독립 `$REPO_ROOT` 이동 및 Git 인덱스 비침습 신규 파일 병합(`git ls-files -o --exclude-standard -z` + `git diff --no-index`) 구현.
|
||||
- [`.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh): `CHANGES_DIFF` 모듈화 및 500줄/30KB 상한 Truncation 경고 노출 내장.
|
||||
- `tests/test_b7_diff_untracked.py`: 전용 회귀 테스트 스위트 20개 작성 및 **20/20 PASS (100%)** 달성.
|
||||
- **멀티에이전트 자율 오케스트레이션**: `/multi-agent-mux-loop --plan --all-reviewer` 가동 결과 Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3자에 의해 **`[VERDICT: PASS]` (만장일치 통과)**.
|
||||
|
||||
### 2) **B-4: 시프트 `ls` 세션 생성 시각(session_created) 동적 포시스 타임스탬프 복원** — **완료**
|
||||
- **배경**: `.agents/skills/lib.sh` 554번 라인에서 `herdr ls` 시 생성시각이 `999999`로 하드코딩되어 `reconcile.sh` drift-B 등록 시 epoch 0이 되어 `find_workspace_uuid` 재개 가드가 붕괴되던 결함 조치.
|
||||
- **주요 구현**:
|
||||
- [`.agents/skills/lib.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh): real herdr 및 YAML 상의 `created`/`created_at`/`created_epoch` 속성을 읽고, 미정의 시 `int(time.time())` 동적 포시스 타임스탬프를 리턴하도록 정제.
|
||||
- [`reconcile.sh`](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh): `created` fallback 포맷팅 보완.
|
||||
- `tests/test_b4_session_created.py`: 전용 회귀 테스트 21개 항목 작성 및 **21/21 PASS (100%)** 달성.
|
||||
- **멀티에이전트 자율 오케스트레이션**: `/multi-agent-mux-loop --plan --all-reviewer` 가동 결과 Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3자에 의해 **`[VERDICT: PASS]` (만장일치 통과)**.
|
||||
|
||||
### 2) **deploy/ 배포 스크립트 최신화 및 레지스트리 3-way 병합 구현** — **완료**
|
||||
- **배경**: `deploy/install.sh` 및 `install_mam.sh`가 `.agents/skills/` 밖 자산(`hooks.json`, `MULTI_AGENT_RULES.md`, `INSTALL.md`)을 갱신하지 못하거나 로컬 훅 수정을 덮어쓰는 맹점(Job `1567c88e` / Plan Rev.2) 해결.
|
||||
- **주요 구현**:
|
||||
- `deploy/lib_ownership.sh` 신설: 자산 소유권 및 레지스트리 파일 관리 단일 창구화.
|
||||
- `deploy/install.sh`: `hooks.json` 키 단위 3-way 병합(`MERGE_REGISTRY`) 및 `.mam/base/` 스냅숏 도입.
|
||||
- `deploy/install_mam.sh` & `deploy/remove.sh`: `asset_hashes.txt` 및 `.mam/base/` 자동 생성과 fallback 자산 목록 동기화.
|
||||
- `deploy/gitea-ci.yml` & `deploy/README.md`: CI pytest 자동화 게이트 및 문서 구조 갱신.
|
||||
- 커밋 완료 (`399242d`, `cc11a02`).
|
||||
|
||||
### 2) **테스트 슈트 경량화 및 다이어트** — **완료**
|
||||
- 중복되고 오래된 레거시 테스트 7개 파일(1,559줄) 완전히 삭제 (`cf51b2c`).
|
||||
- 핵심 계층별 테스트 슈트(Tier 1~4, Deploy, Guard)만 정비하여 향후 기능 변경 시 실행 속도 및 자원 소모 대폭 개선.
|
||||
|
||||
### 3) **O-3: 조건부 오케스트레이션 위임 가드 (Invocation-Aware Scoped Guard)** — **완료**
|
||||
- **배경**: 오케스트레이터 에이전트가 `/multi-agent-mux-loop` 실행 시 직접 코드를 수정하지 않고 스크립트로 위임하도록 통제하며, 루프 내부에서 무한 재귀 기동되는 현상을 원천 방지함.
|
||||
- **주요 수정 파일**:
|
||||
- `.agents/skills/multi-agent-mux-loop/scripts/run_loop.sh`: PID + 시작시각 기반 `.mam/loop-guard-active` 식별자 작성 및 `trap` 자동 삭제 적용.
|
||||
- `AGENTS.md`: Section 5 (Orchestrator Scope Guard O-3) 명시.
|
||||
- `.agents/MULTI_AGENT_RULES.md` & `.ko.md`: 오케스트레이터 세션 및 루프 활성화 모드 수칙 동기화.
|
||||
- `tests/test_o3_scoped_guard.py`: 24개 검증 케이스 작성 (24/24 PASS).
|
||||
- **멀티에이전트 자율 피어 리뷰**: Planner(`claude`), Creator(`agy`), Reviewer(`cline`) 3자에 의해 루프 구동 후 **`[VERDICT: PASS]` (100% 합의)** 통과 및 커밋 완료 (`1f8622e`).
|
||||
|
||||
### 2) **A-3 & C-2 과제 완수 및 안정화 버그 수정** — **완료**
|
||||
- **A-3**: `send_keys_safe` 시프트 버퍼 동시성 레이스 조건 해결 (호출 고유 토큰 생성 + 원자적 쓰기/이동 + 60분 자동 GC).
|
||||
- **C-2**: 미사용 `.cache/multi-agent-mux-monitor` 디렉터리 생성 로직 축소 및 `reconcile.sh` 상태 dead code 정리.
|
||||
- **환경 변수 전파 보완**: `.agents/skills/lib.sh` 내 `HOME_DIR`, `CLAUDE_PROJECT_DIR`, `LOCAL_BIN` 하위 프로세스 `export` 누락 해결 (`2fc0f58`).
|
||||
- **테스트 슈트 Mock 지원**: `tests/conftest.py` 내 `mock_herdr`에 `list-panes` 핸들러 추가 (`778b22b`).
|
||||
- **상태 복구 안전성**: `reconcile.sh` 내 세션 생성 시각 안전 키 접근(`t.get('created', 0)`) 반영 (`36d0178`).
|
||||
|
||||
---
|
||||
|
||||
## Git 커밋 내역 (Total 8 Commits on `refactor`)
|
||||
|
||||
1. `2fc0f58`: `fix(lib): export HOME_DIR, CLAUDE_PROJECT_DIR, and LOCAL_BIN in lib.sh for proper child environment inheritance`
|
||||
2. `55fc739`: `fix(lib): use symlink-safe realpath comparison for workspace cwd matching in find_workspace_uuid`
|
||||
3. `778b22b`: `fix(test): add list-panes support to mock_herdr and fix environment overrides in tier3 integration tests`
|
||||
4. `9f266e6`: `test(integration): update test_tier3_integration to align with global config-home convention`
|
||||
5. `7e16d65`: `test(integration): refine test_integration_create_options_combination to test herdr spawn without wrapper`
|
||||
6. `1658af4`: `test(sanity): update test_sanity assertions to align with removed config-home isolation`
|
||||
7. `1f8622e`: `feat(o3): implement Invocation-Aware Scoped Guard for orchestrator role scoping (100% PASS)`
|
||||
8. `5ab7687`: `fix(c2): remove unused .cache directory creation and clean up state dead code (100% PASS)`
|
||||
9. `3530e8b`: `fix(a3): resolve shift buffer race condition with call-unique tokens, atomic write, and automatic GC (100% PASS)`
|
||||
|
||||
---
|
||||
|
||||
## 🤖 3. 라이브 에이전트 세션 현황 (`herdr: multi-agent-mux`)
|
||||
|
||||
| 에이전트 이름 | 역할 | herdr 세션 상태 | 비고 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `canary-projects-multi-agent-mux-creator-claude` | Planner | `stopped` | 대화 UUID `01eae7cf...` 캡처 보존 완료 |
|
||||
| `canary-projects-multi-agent-mux-creator-agy` | Creator | `stopped` | 대화 UUID `72d2d251...` 캡처 보존 완료 |
|
||||
| `canary-projects-multi-agent-mux-creator-cline` | Reviewer | `stopped` | 대화 UUID `17856352...` 캡처 보존 완료 |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 4. 추후 작업 재개 가이드 (Next Steps)
|
||||
|
||||
1. **세션 상태 확인**:
|
||||
```bash
|
||||
bash .agents/skills/multi-agent-mux-status/scripts/status_session.sh
|
||||
```
|
||||
2. **백로그 확인 (`IMPROVEMENTS.md`)**:
|
||||
- 다음 우선순위 추천 과제:
|
||||
- **O-2**: 동일 워크스페이스 내 중복 루프 기동 방지 락 (Race-Free Lock)
|
||||
- **B-4**: 시프트 `ls`의 `created=0` 하드코딩 해결
|
||||
3. **루프 구동으로 작업 재개**:
|
||||
```bash
|
||||
/multi-agent-mux-loop --plan --all-reviewer "IMPROVEMENTS.md 백로그의 O-2 (또는 선택 과제) 문제를 해결해줘."
|
||||
```
|
||||
+3
-3
@@ -343,9 +343,9 @@ Valid values (see `lib.sh` valid-status set):
|
||||
| State | Meaning | Set by |
|
||||
|---|---|---|
|
||||
| `running` | herdr session active, agent running | `create`, `resume` |
|
||||
| `stopped` | deliberately stopped via `--capture-id`/`--reason`/`--graceful`; conversation preserved for resume | `stop` (STOP mode) |
|
||||
| `terminated` | hard-killed via `--mode hard`; herdr session destroyed | `stop` (hard mode), `monitor` reconcile |
|
||||
| `archived` | soft-stopped via `--mode soft`; herdr left alive, YAML-only update | `stop` (soft mode) |
|
||||
| `stopped` | stopped via `multi-agent-mux-stop` (default); conversation preserved for resume | `stop` |
|
||||
| `terminated` | stopped with `--purge-conversation`, or herdr-dead detected; conversation deleted / session gone | `stop --purge-conversation`, `monitor` reconcile |
|
||||
| `archived` | legacy value — no producer since `--mode soft` was removed; kept in the validation whitelist for rows written by older versions | (none) |
|
||||
|
||||
### Job States (Registry — `.mam/jobs/<id>.json`)
|
||||
Managed by `.agents/skills/multi-agent-mux-delegate-job/scripts/registry.py`.
|
||||
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
# 📜 Multi-Agent Mux 버전 이력 (`VERSIONS.md`)
|
||||
|
||||
이 문서는 `multi-agent-mux` 프레임워크의 버전별 주요 기능 추가, 아키텍처 개선, 버그 수정 및 품질 검증 이력을 기록합니다.
|
||||
|
||||
---
|
||||
|
||||
## 📌 현재 버전 개요 (Current Release)
|
||||
|
||||
- **프레임워크 버전**: `v2.0.0`
|
||||
- **최신 릴리스 일시**: 2026-08-17 (KST)
|
||||
- **기준 브랜치**: `main`
|
||||
- **핵심 아키텍처**:
|
||||
- **A-4 Agent Adapter Layer**: 4대 에이전트(`claude`, `agy`, `hermes`, `cline`) 지식 계층 단일 소스 인터페이스
|
||||
- **Universal Herdr Session Isolation**: 단일 Herdr 서버 컨텍스트 기반 세션 격리
|
||||
- **O-3 Orchestrator Scope Guard**: 오케스트레이터의 직접 코드 변조 방지 및 스크립트 위임 통제
|
||||
- **Tier-1 Fast-Path Lifecycle**: 0ms 지연의 대화 UUID 캡처 및 초고속 재개(Resume)
|
||||
|
||||
---
|
||||
|
||||
## 🧭 스킬 패키지 버전 매트릭스 (Skills Version Matrix)
|
||||
|
||||
모든 8개 스킬은 YAML frontmatter 메타데이터(`author`, `version`, `platforms`, `environments`) 표준화를 통해 `v2.0.0`으로 동기화되어 배포됩니다.
|
||||
|
||||
| 스킬명 | 버전 | 역할 및 주요 책임 | 상태 |
|
||||
| :--- | :---: | :--- | :---: |
|
||||
| **`multi-agent-mux-create`** | `2.0.0` | 에이전트 세션 신규 생성 및 Herdr 컨테이너 격리 스폰 | ✅ 배포 |
|
||||
| **`multi-agent-mux-stop`** | `2.0.0` | 대화 UUID 원자적 캡처 및 세션 안전 종료 (Graceful Stop) | ✅ 배포 |
|
||||
| **`multi-agent-mux-resume`** | `2.0.0` | 온디스크 대화 컨텍스트 기반 Tier-1 초고속 세션 복원 | ✅ 배포 |
|
||||
| **`multi-agent-mux-status`** | `2.0.0` | 실시간 Herdr 세션 및 레지스트리 드리프트 스냅샷 조회 | ✅ 배포 |
|
||||
| **`multi-agent-mux-monitor`** | `2.0.0` | YAML ↔ 런타임 상태 간 자율 조정자 (Reconciler Loop) | ✅ 배포 |
|
||||
| **`multi-agent-mux-delegate-job`** | `2.0.0` | MQTT 이벤트 채널 기반 비동기 단위 작업 위임 | ✅ 배포 |
|
||||
| **`multi-agent-mux-loop`** | `2.0.0` | Planner-Creator-Reviewer 3자 자율 계획·실행·피어리뷰 루프 | ✅ 배포 |
|
||||
| **`multi-agent-mux-orc-onboard`** | `2.0.0` | 오케스트레이터 UUID 격리 등록 및 서브 세션 오염 방지 | ✅ 배포 |
|
||||
|
||||
---
|
||||
|
||||
## 📋 버전별 상세 변경 내역 (Changelog)
|
||||
|
||||
### 🚀 `v2.0.0` — Unified Agent Adapter Architecture & Herdr Standardization (2026-08-17)
|
||||
|
||||
> **주요 마일스톤**: 에이전트 지식 계층 단일 소스화(A-4), 레거시 격리 완전 폐기(Option B), 셸 브리지 하드닝 및 스킬 메타데이터 규격화 완료.
|
||||
|
||||
#### 1. 에이전트 지식 계층 마이그레이션 (A-4 Phase 2 / P3-1)
|
||||
- **`BaseAgentAdapter` 추상 클래스 및 4대 어댑터 구축**:
|
||||
- [`.agents/skills/lib_py/agents/base.py`](.agents/skills/lib_py/agents/base.py): `DiscoveryContext` 및 추상 인터페이스 정의 (`ready_tokens`, `exit_key`, `delegate_agent_key`, `identity_cache_fields`, `artifact_path`, `verify_artifact`, `purge_artifacts`, `spawn_spec`, `resume_spec`, `auth_ok`, `discover`).
|
||||
- [`.agents/skills/lib_py/agents/adapters/`](.agents/skills/lib_py/agents/adapters/): `ClaudeAgentAdapter`, `AgyAgentAdapter`, `HermesAgentAdapter`, `ClineAgentAdapter` 4개 구체 클래스 구현.
|
||||
- **`facts` 브리지 셸 인터페이스 하드닝**:
|
||||
- `lib_py.agents` CLI 모듈을 통해 8개 `MAM_*` 변수를 `shlex.quote` 안전 인용 처리하여 방출.
|
||||
- `wait_for_tui_ready` 빈 토큰 시 전량 매칭 오탐 방지 및 미지 에이전트 fail-closed 가드 내장.
|
||||
- **셸 스크립트 전반 어댑터 이관**:
|
||||
- `create_session.sh`, `resume_session.sh`, `stop_session.sh`, `reconcile.sh`에 산재되어 있던 40여 개 하드코딩 분기를 어댑터 호출로 일원화.
|
||||
|
||||
#### 2. 레거시 `isolation.root` 및 C-3b 소비자 완전 폐기 (Option B)
|
||||
- Universal Global Config 전환 이후 남아있던 4개 레거시 격리 소비자 코드(`lib.sh::mam_session_iso_root`, `workspace_uuid.py::iso_root_of`, `verify_session.py`, `stop_session.sh`) 및 `atomic_yaml.py`의 레거시 유효성 검사 절 100% 삭제.
|
||||
- 저장소 내 격리 잔재 참조 0건 달성.
|
||||
|
||||
#### 3. 셸 브리지 보안 및 예외 처리 강화 (R1, R2, N1 교정)
|
||||
- **R1 (위임 에이전트 키 폴백 보강)**: 브리지 미작동 시 `delegate_agent`가 `antigravity-cli`로 일괄 퇴화하지 않고 `claude-code`, `hermes-agent`, `cline-agent`로 명시적 `case` 폴백하도록 개선.
|
||||
- **R2 (`argv` 서브커맨드 전환)**: `python -c` 셸 변수 문자열 보간을 `spawn-spec`, `resume-spec`, `exit-key` 서브커맨드로 전면 전환하여 공백/작은따옴표 경로 에러 및 코드 주입 위협 원천 차단.
|
||||
- **N1 (클린 환경 격리 가드)**: `test_a4_adapter_contract.py` 내 CLI 테스트가 앰비언트 `PYTHONPATH` 없이도 독립 통과하도록 환경 격리 보강.
|
||||
|
||||
#### 4. 스킬 메타데이터 규격화 및 피어 리뷰 100% PASS
|
||||
- 8개 `SKILL.md` frontmatter `version: 2.0.0` 통일 및 배포 무결성 검증.
|
||||
- Reviewer `cline` (Job `e7b9812b`) 및 Planner/Senior Reviewer `claude` (Job `31730364`) 전원 `[VERDICT: PASS]` 획득.
|
||||
|
||||
#### 5. 레거시 주석 및 사용법 정합성 최신화 (C-6)
|
||||
- `stop_session.sh` 상단 주석 및 `usage()` 내 폐기된 플래그(`--mode soft|hard`, `--capture-id`, `--graceful`) 안내 문구를 완전 제거하고 현행 4대 에이전트(`claude`, `agy`, `hermes`, `cline`) 및 플래그 체계로 동기화.
|
||||
- 회귀 방지 컴포넌트 테스트(`test_comp_stop_usage_matches_parser`) 신설.
|
||||
- 회귀 및 계약 테스트: **263/263 PASS (100%)** 달성.
|
||||
|
||||
---
|
||||
|
||||
### 🛠️ `v1.4.0` — Stability, Cleanup & Safe Job Delegation (2026-08-16)
|
||||
|
||||
> **주요 마일스톤**: 격리 잔재 정리, 서브셸 루프 락 조기 해제 버그 픽스, 신규 파일 캡처 및 경량화.
|
||||
|
||||
- **P2-2 (C-3a / C-4 레거시 격리 스텁 및 미사용 심볼 제거)**:
|
||||
- `lib.sh` 내 빈 스텁 4종(`provision_isolation`, `isolation_lever`, `isolation_env_prefix`, `isolation_cmd_args`) 및 `_REAL_HERDR_PATH` 완전 삭제.
|
||||
- `registry.py::TERMINAL_STATUSES` 및 `create_session.sh::ISOLATE` 제거.
|
||||
- **P2-1 (B-6 / B-12 `delegate_job_safe` 안정화)**:
|
||||
- `.agents/skills/...` 내 불필요한 `.tmp` 복사본 생성 제거 및 인플레이스 직접 실행(`bash "$orig_script"`) 전환.
|
||||
- 서브셸 내 `trap`으로 인한 루프 락 마커(`.mam/loop-guard-active`) 조기 삭제 결함(D1) 원천 차단.
|
||||
- **P0-2 (O-2 중복 루프 기동 방지 원자적 락)**:
|
||||
- `loop_lock.sh` 신설: `set -C` 기반 원자적 락 획득 및 PID + lstart 소유권 검증으로 동시 실행 방지.
|
||||
- **P0-1 (B-7 외곽 diff 수집 및 미추적 파일 캡처)**:
|
||||
- `diff_collect.sh` 도입: CWD 독립 `$REPO_ROOT` 기준 diff 수집 및 `git ls-files -o` 미추적 파일 병합.
|
||||
- **B-4 (시프트 `ls` 동적 포시스 타임스탬프 복원)**:
|
||||
- `lib.sh` 554행의 `created=999999` 하드코딩을 실시간 타임스탬프(`int(time.time())`)로 복원.
|
||||
- **테스트 슈트 경량화**:
|
||||
- 노후화된 중복 레거시 테스트 7개 파일(1,559줄) 삭제 (`cf51b2c`).
|
||||
|
||||
---
|
||||
|
||||
### 🛡️ `v1.3.0` — Orchestrator Onboarding & Scoped Guarding (2026-08-15)
|
||||
|
||||
> **주요 마일스톤**: 오케스트레이터 신원 격리 및 다중 에이전트 협업 가드레일 확립.
|
||||
|
||||
- **`multi-agent-mux-orc-onboard` 스킬 신설**:
|
||||
- 오케스트레이터(`agy`)의 대화 UUID를 `.mam/agent-sessions.yaml` 내 `orchestrator_uuids` 리스트로 등록.
|
||||
- `find_workspace_uuid` 및 `verify_session_uuid`에서 오케스트레이터 UUID를 스킵하여 서브에이전트 세션 오염 방지.
|
||||
- **O-3 (조건부 오케스트레이션 위임 가드 — Scoped Guard)**:
|
||||
- 오케스트레이터가 `/multi-agent-mux-loop` 활성화 상태에서 직접 코드를 수정하지 않고 스크립트로 위임하도록 통제.
|
||||
- `AGENTS.md` §5 및 `MULTI_AGENT_RULES.md` 내 가드레일 명시.
|
||||
- **배포 및 패키징 파이프라인 현대화**:
|
||||
- `deploy/lib_ownership.sh` 신설 및 `hooks.json` 3-way 병합(`MERGE_REGISTRY`) 지원.
|
||||
- Gitea CI/CD 파이프라인 (`deploy/gitea-ci.yml`) 연동.
|
||||
|
||||
---
|
||||
|
||||
### 🔌 `v1.2.0` — Universal Herdr Server Isolation & Cline Integration (2026-08-14)
|
||||
|
||||
> **주요 마일스톤**: Herdr 단일 서버 격리 및 다중 AI 에이전트 확장.
|
||||
|
||||
- **Universal Herdr Session Isolation**:
|
||||
- `HERDR_SESSION_NAME` 기반으로 격리 서버를 통일하여 프로세스 충돌 방지.
|
||||
- **Cline 에이전트 통합**:
|
||||
- `cline` CLI 기반 대화 세션 생성, 정지, 복원 및 TUI 레디 토큰 핸들링 지원.
|
||||
- **SQLite WAL 트랜잭션 동시성**:
|
||||
- 세션 레지스트리 동시 쓰기 시 발생하는 락 충돌을 방지하기 위해 SQLite WAL 모드 전면 적용.
|
||||
|
||||
---
|
||||
|
||||
### 🧱 `v1.0.0` ~ `v1.1.0` — Initial Multi-Agent Mux Framework (2026-08-10 ~ 2026-08-13)
|
||||
|
||||
> **주요 마일스톤**: 터미널 다중 에이전트 오케스트레이션 기초 설계 및 비동기 루프 완성.
|
||||
|
||||
- **핵심 수명주기 스킬군 구축**: `create`, `stop`, `resume`, `status`, `monitor` 스킬 기본 구현.
|
||||
- **MQTT 기반 비동기 잡 위임**: `multi-agent-mux-delegate-job`을 통한 에이전트 간 이벤트 통신 및 결과 구독.
|
||||
- **자율 협업 루프**: `multi-agent-mux-loop` 컨트롤러를 통한 Planner-Creator-Reviewer 역할 분담 체계 정립.
|
||||
|
||||
---
|
||||
|
||||
## 🧪 품질 보증 및 검증 기준 (Verification Standards)
|
||||
|
||||
모든 릴리스는 다음 4단계 엄격한 검증을 통과해야 배포됩니다:
|
||||
1. **정적 문법 검사**: `bash -n` (모든 셸 스크립트) 및 AST 미사용 코드 분석.
|
||||
2. **단위 및 컴포넌트 테스트 (Tier 1~2)**: 인플레이스 및 컴포넌트 간 상호작용 검증.
|
||||
3. **통합 및 계약 테스트 (Tier 3~4 / Contract)**: clean environment (`env -u PYTHONPATH`) 하에서의 어댑터 계약 및 CLI 브리지 검증.
|
||||
4. **멀티에이전트 교차 피어 리뷰**: Planner(`claude`) 및 Reviewer(`cline`) 간 교차 검증 및 `[VERDICT: PASS]` 100% 합의.
|
||||
@@ -691,3 +691,45 @@ d['herdr_sessions'] = [{
|
||||
row = conn.execute("SELECT status FROM sessions WHERE name='test-autorecovery-creator-claude'").fetchone()
|
||||
assert row[0] == "terminated"
|
||||
conn.close()
|
||||
|
||||
def test_comp_stop_usage_matches_parser(mam_sandbox):
|
||||
"""C-6: help text and parser must not drift apart."""
|
||||
script = mam_sandbox / ".agents" / "skills" / "multi-agent-mux-stop" / "scripts" / "stop_session.sh"
|
||||
|
||||
# 에이전트 접미사 추론(:91-100)이 성립하는 이름 — rc=2 의 다섯 원인 중
|
||||
# 'cannot infer agent'(:98)를 배제하기 위함 (Challenge 8b6b574f)
|
||||
VALID = "test-project-creator-claude"
|
||||
|
||||
# 1) --help 는 성공하고, 폐지된 플래그를 광고하지 않는다
|
||||
res = subprocess.run(["bash", str(script), "--help"], capture_output=True, text=True)
|
||||
assert res.returncode == 0
|
||||
for dead in ("--mode", "--capture-id", "--graceful"):
|
||||
assert dead not in res.stdout, f"usage() still advertises {dead}"
|
||||
|
||||
# 1b) 검증기가 받는 에이전트는 전부 도움말에 나온다 (Rev.2 M3)
|
||||
for agent in ("claude", "agy", "hermes", "cline"):
|
||||
assert agent in res.stdout, f"usage() omits supported agent {agent}"
|
||||
|
||||
# 2) 도움말이 광고하는 플래그는 전부 파서가 받는다
|
||||
# rc=2 는 5가지 원인을 공유하므로 stderr 메시지로 직접 지목한다
|
||||
for flag, args in (("--reason", ["--reason", "x"]),
|
||||
("--purge-conversation", ["--purge-conversation"]),
|
||||
("--yes", ["--yes"]),
|
||||
("--agent", ["--agent", "hermes"])):
|
||||
r = subprocess.run(["bash", str(script), "--session", VALID] + args,
|
||||
capture_output=True, text=True)
|
||||
assert "unknown arg" not in r.stderr, f"usage() advertises {flag} but parser rejects it: {r.stderr}"
|
||||
assert "deprecated" not in r.stderr, f"usage() advertises deprecated {flag}: {r.stderr}"
|
||||
assert r.returncode != 2, f"{flag} -> rc=2: {r.stderr}"
|
||||
|
||||
# 3) 폐지된 플래그는 전용 메시지와 함께 rc=2 로 거부된다 (특별 취급 유지)
|
||||
for dead in ("--mode", "--capture-id", "--graceful"):
|
||||
r = subprocess.run(["bash", str(script), "--session", VALID, dead, "hard"],
|
||||
capture_output=True, text=True)
|
||||
assert r.returncode == 2
|
||||
assert "deprecated" in r.stderr
|
||||
|
||||
# 4) 헤더 주석도 폐지 플래그를 사용법으로 광고하지 않는다
|
||||
head = "".join(script.read_text().splitlines(keepends=True)[:35])
|
||||
assert "--mode soft|hard" not in head
|
||||
|
||||
|
||||
Reference in New Issue
Block a user