release(v4.7.2): bump framework and eight skills to 4.7.2 in lockstep; archive PR #35 merge-side reviews
Issues #23 and #24: cross-server herdr scope, agent-agnostic start-up dialogs, onboarding delivery judged by the agent's own started event, verified rollback. VERSIONS.md carries the entry; the merge-side reports (round 1: claude/agy/grok; round 2 on05b0ea4: all four, with identity sidecars, basef4ba205-> head05b0ea4, evidence review-tree) are archived under .agents/reports/<session>/. The round-1 codex report was lost to the host sleeping mid-review; its two probes are recorded in the changelog. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
1 parent
05b0ea4762
commit
9fb037c084
27 files changed
+727
-26
No files matched your search
@@ -0,0 +1,176 @@
|
|||||||
|
# 🔍 Review Report — PR #35 병합 전 독립 리뷰 (job `adc0ff3c`)
|
||||||
|
|
||||||
|
- **Reviewer**: `planner-reviewer-claude-01` (role: planner,reviewer) · 2026-09-23
|
||||||
|
- **대상**: PR #35 `fix/issue-23-24` **@ `f4ba205`**, base `main 1e78dae` (v4.7.1). 13커밋, 22파일 `+2197/−118`, `git diff --check` 클린.
|
||||||
|
- **검증 경로**: `/var/folders/.../T/mam-review/loop-20260923T142448Z-609954/1`. **identity 확인**: `HEAD = f4ba205c…fd2f`, `HEAD^{tree} = 88cb4f34…f181` — 브리프의 `head`·`tree` 와 일치.
|
||||||
|
- **안전 규칙 준수**: 검증 경로·소스 워크트리(`multi-agent-mux-wt/pr-35`)·본 체크아웃(`main 1e78dae`) 모두 수정·커밋·checkout 없음. 실험은 scratchpad 임시 디렉터리(uuid4 이름)에서만, pytest 는 `AGENT_PYTHON_BIN=<제어 루트 .venv>` + `--basetemp=<검증 경로 밖>` 으로 실행. 실제 herdr 서버·에이전트 세션·`.mam`·데몬 조작 없음(이 pane 의 herdr 환경변수를 **읽기만** 했다), push·merge·PR 상태 변경 없음, purge·scrub 실행 없음.
|
||||||
|
|
||||||
|
## 결론 요약
|
||||||
|
|
||||||
|
**병합을 막을 결함은 없다.** 세 핵심 규칙 — 교차 서버 판정, "이번 dispatch 의 started 만 증거", kill 결과 확인 롤백 — 을 각각 독립 실험으로 재현·확인했고, 새 테스트는 실제 `registry.py`/`publish_event.py` 를 쓰며 홈·브로커·실제 herdr 에 닿지 않는다. 비차단 지적 6건(F1–F6)을 남긴다. 그중 F1 은 **브리프의 codex 수락 키 서술과 코드가 다르다**는 점이라 오케스트레이터가 확인할 필요가 있다.
|
||||||
|
|
||||||
|
## 1. #24 시작 다이얼로그 (항목 1)
|
||||||
|
|
||||||
|
### 1-1. 어댑터 시그니처·수락 키
|
||||||
|
|
||||||
|
`python -m lib_py.agents facts <agent>` 가 실제로 내놓는 값(검증 경로에서 실행):
|
||||||
|
|
||||||
|
| 에이전트 | `MAM_STARTUP_DIALOGS` | 강한 준비 토큰 |
|
||||||
|
|---|---|---|
|
||||||
|
| claude | 기존 사다리 5개(trust Enter / `Yes, try it` Escape / `Yes, proceed` Down+Enter / `Resuming…` Enter / `Press Enter…` Enter)가 그대로 옮겨짐 | `Anthropic\|Assistant\|…\|Haiku` |
|
||||||
|
| agy | `Do you trust the contents of this project\|Yes, I trust this folder` → `Enter`, trust | `Antigravity` |
|
||||||
|
| grok | `Do you trust the contents of this directory` → `y`, trust | `Grok\|xAI\|Assistant\|❯\|>>>` |
|
||||||
|
| codex | `Do you trust…\|1\. Yes, continue` → **`Enter`**, trust · `1\. Update now\|Skip until next version` → **`2`**, notice | `Codex\|Ask Codex to do anything` |
|
||||||
|
| opencode·hermes | `[]` (다이얼로그 없음) | 있음 → 핸들러가 배너에서 즉시 반환 |
|
||||||
|
|
||||||
|
**F1 (확인 요망, 비차단)**: 브리프는 codex 수락 키를 "`1`+Enter, 업데이트 안내 `3`+Enter" 로 적었으나 코드는 **Enter 단독**(1번 항목이 미리 선택돼 있다는 주석)과 **`2`**("2 = Skip" 이라는 관찰 기록, 2026-09-22) 다. 어느 쪽이 실제 화면인지는 이 리뷰에서 재현할 수 없다(실제 codex 를 띄우는 것은 금지). PR 본문은 codex 를 포함한 4개 에이전트의 실제 herdr 시험이 사람 개입 없이 `started`(토큰 포함)→`completed` 까지 갔다고 기록하므로 **코드 쪽이 실측**으로 보이지만, 브리프 작성자의 관찰과 다르므로 병합 전에 한 번 맞춰 볼 것을 권한다. `_MAM_READY_TOKENS_CLAUDE` 상수는 제거되고 어댑터의 `strong_ready_tokens` 로 대체됐다(값 동일).
|
||||||
|
|
||||||
|
### 1-2. 준비 토큰으로 수락을 판정하는 이유
|
||||||
|
|
||||||
|
`handle_startup_dialogs`(`lib.sh:2979-`)는 시그니처가 화면에 남아 있어도 같은 인덱스에 대해 `MAM_DIALOG_RESEND_S`(기본 5 s) 안에는 재전송하지 않고(`_mam_dialog_pick` 의 cooldown), 반환 조건은 **오직 준비 토큰**이다. `--source visible` 스냅샷이 수락된 다이얼로그를 한동안 계속 보여 준다는 #24 의 관찰과 맞물려 타당하다 — 옛 코드는 매 폴링마다 Enter 를 다시 보내 이미 넘어간 TUI 에 입력을 흘렸다. `test_c1_tui_readiness.py::test_c1b` 의 단언이 `==30` 에서 `1 ≤ n ≤ 30` 으로 바뀐 것도 같은 이유이며, "한 프레임에 두 번 보내지 않는다"는 원래 가드는 그대로다.
|
||||||
|
|
||||||
|
### 1-3. `--no-auto-trust` / `MAM_AUTO_TRUST=0`
|
||||||
|
|
||||||
|
`_mam_dialog_pick` 은 `kind == "trust"` 이고 auto_trust 가 꺼져 있으면 `skip|idx|` 를 내고, 핸들러는 경고만 남긴다(cooldown 마다 1회). `notice` 는 항상 답한다. create(`create_session.sh:86-94`)와 resume(`resume_session.sh:43-57`)이 **같은 스위치·같은 env 변수(`MAM_AUTO_TRUST`)·같은 호출(`handle_startup_dialogs "$SESSION" N "$AGENT"`)** 을 쓴다. S6/R3 가 고정.
|
||||||
|
|
||||||
|
### 1-4. 자동 수락의 적용 범위(보안)
|
||||||
|
|
||||||
|
pane 은 `new-session -c "$WORKSPACE"` 로 뜨고 신뢰 창은 그 cwd 에 대한 것이므로 실질적으로 `--workspace` 에만 적용된다. 다만 시그니처 정규식은 **디렉터리 이름을 검사하지 않는다** — 화면에 어떤 경로가 적혀 있든 매치되면 수락한다(F5). 시작 직후의 신뢰 창이 다른 디렉터리를 가리킬 경로는 없어 실무 위험은 낮다.
|
||||||
|
|
||||||
|
## 2. #23 교차 서버 스코프 (항목 2)
|
||||||
|
|
||||||
|
`_herdr_caller_server` / `_herdr_call_is_cross_server`(`lib.sh:1403-1447`)를 lib.sh 에서 함수만 추출해 `env -i` 로 9가지 조합을 돌렸다(전부 기대와 일치):
|
||||||
|
|
||||||
|
| `HERDR_SOCKET_PATH` | `HERDR_SESSION` | 대상 | 판정 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `~/.config/herdr/herdr.sock` | – | `mam` | caller=`default`, **CROSS** (보고된 #23 시나리오) |
|
||||||
|
| 〃 | – | (없음) / `default` | same (앰비언트 sentinel) |
|
||||||
|
| `~/.config/herdr/sessions/mam/herdr.sock` | – | `mam` | caller=`mam`, same → **pane 배치·workspace 패킹 유지** |
|
||||||
|
| 〃 | – | `other` | CROSS |
|
||||||
|
| 〃 | `orch` | `mam` | caller=`orch`(HERDR_SESSION 우선), CROSS |
|
||||||
|
| `/other/layout/herdr.sock` / 비어 있음 | – | `mam` | caller="" → same (pane 밖: 명시 스코프 존중) |
|
||||||
|
| `…/sessions/a b/herdr.sock` | – | `mam` | caller=`a b`, CROSS (공백 안전) |
|
||||||
|
|
||||||
|
- 제거는 `mam_herdr` 안에서 **교차일 때만** `env -u HERDR_WORKSPACE_ID -u HERDR_PANE_ID -u HERDR_TAB_ID` 로 이루어지고(`lib.sh:1449-1461`), argv 배열 + `if` 로 판정하므로 `set -e` 호출자를 중단시키지 않는다(S12).
|
||||||
|
- `lib_py/loop/watcher.py::caller_server/scoped_env` 는 같은 규칙의 파이썬 쌍둥이다. 같은 5가지 입력으로 돌려 bash 와 **동일 결과**를 확인했다(같은 서버·pane 밖·`default`·`None` 대상은 ids 유지, 교차만 제거).
|
||||||
|
- **실제 레이아웃 근거**: 이 pane(herdr **0.9.1**)의 환경은 `HERDR_SOCKET_PATH=~/.config/herdr/sessions/multi-agent-mux/herdr.sock`, `HERDR_SESSION=multi-agent-mux` 였다 — 규칙이 전제하는 `sessions/<name>/herdr.sock` 형태와 일치하고, `HERDR_SESSION` 도 export 된다. 0.8.2 의 "기본 서버 pane 에는 `HERDR_SESSION` 이 없다"는 전제는 PR 의 실측 기록(코드 주석)에 의존하며 여기서 재현할 수 없다. 두 경우 모두 소켓 경로 규칙이 뒷받침하므로 어느 버전이든 판정이 성립한다.
|
||||||
|
- 인식되지 않는 레이아웃은 ""(= pane 밖) 으로 떨어져 **오늘의 동작을 유지**한다. 잘못된 제거보다 안전한 쪽이다.
|
||||||
|
|
||||||
|
## 3. #23 온보딩 전달 판정 (항목 3)
|
||||||
|
|
||||||
|
### 3-1. 공유
|
||||||
|
|
||||||
|
`delegate_publish_cmd`·`delegate_job_status`·`delegate_started_recorded`·`delegate_wait_started` 가 `lib.sh:2189-2313` 에 하나씩 있고, create 온보딩(`create_session.sh:622-680`)과 래퍼 `_wait_started`(`multi-agent-mux-delegate-job:647-668`)가 **같은 `delegate_started_recorded`** 를 부른다. 래퍼는 `MAM_JOBS_DIR="$REGISTRY_DIR"` 와 `LOGS_DIR_ABS` 를 넘겨 자기 레지스트리·감사 루트를 그대로 쓴다(`:191`,`:659`). 옛 `_disk_status != pending → 성공` 우회와 구독자 콘솔 grep 은 **삭제**됐다(diff 로 확인).
|
||||||
|
|
||||||
|
### 3-2. 증거 규칙 실측
|
||||||
|
|
||||||
|
`delegate_started_recorded` 만 추출해 가짜 `events.log`/`events.ndjson` 으로 10가지를 돌렸다(전부 기대와 일치):
|
||||||
|
|
||||||
|
| # | 상태 | 토큰 요구 | 결과 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 파일 없음 | 있음 | NOT |
|
||||||
|
| 2 | 이전 dispatch 토큰의 `started` | 있음 | **NOT** (R1: 이전 시도의 증거 거부) |
|
||||||
|
| 3 | 〃 | 없음 | recorded (토큰 없으면 종전대로) |
|
||||||
|
| 4 | 이번 토큰의 `started` | 있음 | recorded |
|
||||||
|
| 5 | 감사 기록 `dispatch_verified:true`, **fingerprint 없음** | 있음 | **NOT** (신원 없는 과거 기록 fail closed) |
|
||||||
|
| 6 | 〃 | 없음 | recorded |
|
||||||
|
| 7 | 이전 시도의 fingerprint | 있음 | NOT |
|
||||||
|
| 8 | 이번 토큰의 fingerprint | 있음 | recorded |
|
||||||
|
| 9 | fingerprint 맞지만 `dispatch_verified:false` | 있음 | NOT |
|
||||||
|
| 10 | 깨진 줄 + `progress` 만 | 있음 | NOT (JSON 파싱, 패턴 매칭 아님) |
|
||||||
|
|
||||||
|
fingerprint 는 `sha256(token)` 으로 구독자(`job_subscriber.py:303-306`)와 **같은 해시**임을 확인했다. 레지스트리 `status` 는 어느 경로에서도 증거로 쓰이지 않는다.
|
||||||
|
|
||||||
|
### 3-3. 종료된 잡·#18 정합
|
||||||
|
|
||||||
|
- create 는 더 이상 에이전트 대신 `started` 를 발행하지 않는다(`:649-657` 주석과 코드; S7). 미확인 시 `delegate_job_status` 가 `completed|error|cancelled` 면 **덮어쓰지 않고** 경고만 한다(`:674-679`; S7m).
|
||||||
|
- 대기 시간은 `MAM_ONBOARD_ACK_S` → `MAM_INJECT_ACK_GRACE_S` → 잡의 `ack_timeout_sec`(기본 180) 순이다 — #18 의 T=180 과 같은 값이고, heartbeat 계약은 `started --heartbeat 30` 명령을 `delegate_publish_cmd` 가 래퍼와 **인자 단위로 동일**하게 만든다(S7l).
|
||||||
|
- `inject_instructions`(= `send_keys_safe`) 의 rc 4 는 세 자리 모두 "전달 미상"(`lib.sh:2746` busy 초과, `:2810` delivery unknown, `:2883` Enter 미수락)이라 `started` 대기로 판정을 넘기는 것이 맞고, rc 1(quiesce 실패)·2·3(다이얼로그 차단)은 즉시 실패로 남는다(S8/S8b).
|
||||||
|
|
||||||
|
## 4. #23 실패 처리 (항목 4)
|
||||||
|
|
||||||
|
- `cleanup_herdr_on_error`(`create_session.sh:318-346`): `kill-session` 의 rc 를 버리지 않고 받은 뒤 `has-session` 으로 재확인, 살아 있으면 행을 `running` + `last_visible_status: rollback-failed` + `delegate_job_id: null` 로 표시하고 **exit 43**. bash 3.2 에서 EXIT trap 안의 `exit 43` 이 원래 종료 코드(1)를 덮어씀을 직접 확인했다(`rc=43`). 상태값은 `atomic_yaml.py:18` 의 어휘(`running/terminated/archived/stopped`) 안이고 `last_visible_status` 는 reconcile 이 이미 쓰는 필드다.
|
||||||
|
- 온보딩 미확인: 세션 보존 + 잡 `error`(이미 종료된 잡은 제외) + 경고 2줄, `ROW_APPENDED` 뒤라 YAML 행은 유효한 `running` 이다. 실패한 잡은 `JOB_TERMINALIZED=1` 로 표시돼 트랩이 `cancelled` 를 겹쳐 발행하지 않는다.
|
||||||
|
- create SKILL.md(`:101-131`)가 이 규칙(started 기반 판정, rc 4 경고, 세션 보존, `MAM_ONBOARD_ACK_S`, exit 42/43 과 행 상태)을 정확히 서술한다.
|
||||||
|
|
||||||
|
## 5. 기존 테스트 조정 6파일 (항목 5)
|
||||||
|
|
||||||
|
| 파일 | 변경 | 판정 |
|
||||||
|
|---|---|---|
|
||||||
|
| `conftest.py` | `mam_sandbox` 에 `MAM_ONBOARD_ACK_S=3` 추가 | 타당. 샌드박스에는 `started` 를 발행할 실제 에이전트가 없어 이것이 없으면 create 테스트마다 180 s 를 소모한다. create 전용 변수라 래퍼의 `MAM_INJECT_ACK_GRACE_S` 를 단언하는 테스트와 간섭하지 않는다 |
|
||||||
|
| `test_b19_*` | `grep -q 'Yes, try it'` 가 lib.sh 에 있는지 → claude 어댑터의 `('Yes, try it', ['Escape'], 'notice')` 로 위치 이동 | 토큰 목록 두 단언은 그대로. 검증 대상이 이사한 것뿐 |
|
||||||
|
| `test_c1_tui_readiness.py` | `KEYS_COUNT==30` → `1 ≤ n ≤ 30`, `custom` 에이전트 → `claude` | §1-2 참조. cooldown 도입으로 "매 반복 1회" 가 "프레임당 최대 1회" 로 바뀌었고 원래 가드(2회 금지)는 유지·강화. `custom` 은 어댑터가 없어 다이얼로그 목록이 비므로 이 시험에는 `claude` 가 맞다 |
|
||||||
|
| `test_issue14_delivery_ack.py` | 레지스트리 상태만 `running` 으로 flip 하던 "ack" 를 **실제 `publish_event.py` + dispatch 토큰의 `started`** 로 교체 | **강화**. 옛 시험은 PR 이 없앤 "상태만 보고 성공" 우회를 통과 조건으로 쓰고 있었다. 새 시험은 로컬 `events.log` 에 토큰이 실린 줄까지 단언한다 |
|
||||||
|
| `test_issue18_liveness_contract.py` | acceptance5 의 배달 단언을 `recorded 'started'` 하나로 좁힘 | 계약상 옳다(레지스트리 상태는 증거가 아님). 다만 "브로커가 retained `completed` 만 배달" 한 경우가 이제 **실패**한다 — `_skip_if_broker_did_not_deliver` 는 그 잡의 어떤 이벤트도 못 받았을 때만 skip 하므로. 공개 브로커에서 flake 가 늘 수 있는 자리(F4) |
|
||||||
|
| `test_issue5_phase2a_loop.py` | G9 가드가 코드만 읽도록(`ast` 로 docstring **노드**만 제거, 주석은 unparse 에서 사라짐) + `g9b` 자체 검증 | 약화 아님. 호출 형태(`subprocess` argv 의 `lib.sh` 경로·`source`, 식별자)는 여전히 코드 텍스트에 있어 잡히고, `g9b` 가 "같은 줄의 코드"(R2) 네 가지까지 고정한다. `ast.unparse` 는 3.9+ — venv 3.9.6 이라 통과 |
|
||||||
|
|
||||||
|
## 7. 문서 (항목 7)
|
||||||
|
|
||||||
|
- create SKILL.md `:101-131`: started 기반 판정·rc 4 경고·세션 보존·`MAM_ONBOARD_ACK_S`·`--no-auto-trust`(codex 의 로컬 설정 로드 위험 명시)·`MAM_DIALOG_RESEND_S`·exit 42/43 과 행 상태가 코드와 일치한다. resume SKILL.md 는 에이전트 분기 `case` 를 없애고 같은 호출로 바꿨다.
|
||||||
|
- **F2 (비차단, 문서 누락)**: 감사 기록의 새 필드 `dispatch_verified`·`dispatch_fingerprint`·`attempt_id` 는 `MESSAGING.md`·delegate-job `SKILL.md` **어디에도 없다**(전수 grep 0건). 두 문서는 `events.ndjson` 을 단계 수준으로만 서술해 필드 목록 자체가 없으므로 모순은 없지만, "래퍼와 create 가 무엇을 증거로 읽는가"가 이번 PR 의 핵심이라 한 문단은 있어야 한다.
|
||||||
|
- **F3 (비차단, 문구 정밀도)**: SKILL.md 는 `MAM_ONBOARD_ACK_S` 가 래퍼의 `MAM_INJECT_ACK_GRACE_S` 와 "별개" 라고만 적었지만 코드의 우선순위는 `MAM_ONBOARD_ACK_S` → `MAM_INJECT_ACK_GRACE_S` → 잡의 `ack_timeout_sec` 이다(`create_session.sh:658`). 즉 래퍼 변수도 create 의 대기에 **2순위로 영향**을 준다.
|
||||||
|
- `.claude/skills`: 본 체크아웃의 것은 git 에 추적되지 않는 로컬 심링크(`../../.agents/skills/*`, 10개)라 자동 동기화된다. 검증 경로(워크트리)에는 존재하지 않는다 — 배포 사본 정합 문제 없음.
|
||||||
|
|
||||||
|
## 6. 테스트 (항목 6)
|
||||||
|
|
||||||
|
### 6-1. 검증 경로에서의 실행
|
||||||
|
|
||||||
|
```
|
||||||
|
cd <검증 경로> && AGENT_PYTHON_BIN=<제어 루트 .venv/bin/python> PYTHONDONTWRITEBYTECODE=1 <같은 인터프리터> -m pytest \
|
||||||
|
-p no:cacheprovider -q -rfEs --basetemp=<검증 경로 밖> \
|
||||||
|
tests/test_issue23_24_startup_path.py tests/test_issue24_resume_dialogs.py tests/test_b19_headless_reconcile_fixes.py \
|
||||||
|
tests/test_c1_tui_readiness.py tests/test_issue14_delivery_ack.py tests/test_issue18_liveness_contract.py \
|
||||||
|
tests/test_issue5_phase2a_loop.py tests/test_herdr_shim_contract.py tests/test_loop_cli.py
|
||||||
|
→ 273 passed in 700.58s (0:11:40) failed 0 · errors 0 · skipped 0
|
||||||
|
```
|
||||||
|
|
||||||
|
새 파일 2개(73건)와 조정된 6파일, 그리고 셸 shim 계약·loop CLI 까지 모두 통과. 브로커 의존 시험(issue14·issue18)도 이번 실행에서는 flake 없이 통과했다.
|
||||||
|
|
||||||
|
### 6-2. 수정 없이는 실패하는가 — 확인함
|
||||||
|
|
||||||
|
검증 경로 사본에서 PR 이 바꾼 소스 12파일(lib.sh·어댑터 5·`__main__.py`·`job_subscriber.py`·`watcher.py`·create/resume 스크립트·래퍼)만 base `1e78dae` 판으로 되돌리고 새 테스트 2파일을 돌렸다:
|
||||||
|
|
||||||
|
```
|
||||||
|
60 failed, 12 passed, 1 skipped in 275.50s
|
||||||
|
```
|
||||||
|
|
||||||
|
실패 60건은 S1(교차 서버)·S4~S6(다이얼로그)·S7/W(started 증거)·S8(rc 4)·S9/S10(롤백)·R1~R4(resume) 전 영역에 걸친다. 통과한 12건은 "같은 서버는 스코프 유지"(S2/S2b)·"shim 은 바뀌지 않음"(S11)·"호출자가 준 토큰은 덮어쓰지 않음"(S5e) 같은 **불변 조건**들이라 수정과 무관한 것이 맞다. 즉 새 테스트는 이 변경을 정확히 겨냥한다.
|
||||||
|
|
||||||
|
### 6-3. 격리·픽스처·시간
|
||||||
|
|
||||||
|
| 항목 | 결과 |
|
||||||
|
|---|---|
|
||||||
|
| 실제 `.mam/jobs` / `.mam/delegate_job_logs` 전후 | **차이 0 / 차이 0** |
|
||||||
|
| 실제 herdr 서버·홈 | `mam_sandbox` 가 `HOME`/`HOME_DIR` 를 `tmp_path` 로 바꾸고(`conftest.py:210-211`) herdr 는 mock. 새 파일에서 `hivemq`·실제 소켓 참조 0건. 이 pane 의 herdr 환경변수는 S1d 가 **읽기만** 한다 |
|
||||||
|
| 실제 생산자 사용 | S7i~S7n·W 계열은 `REGISTRY_PY`/`PUBLISH_PY`(실제 `registry.py`·`publish_event.py`)로 잡을 등록하고 `started` 를 발행한다(`test_issue23_24_startup_path.py:620-660`). "손으로 만든 픽스처가 결함을 가렸다"는 PR 의 교훈이 테스트에 반영돼 있다 |
|
||||||
|
| 검증 경로 | tracked 파일 변화 없음(HEAD `f4ba205` 유지). 내 실행이 무시되는 `.mam/` 을 만들었다(#32 리뷰 때와 같은 현상, 그대로 둠) |
|
||||||
|
| 실행 시간 | 새 파일 2개는 대체로 빠르지만 **`test_issue24_resume_dialogs.py` 4건이 각 39~43 s** 다(resume 의 `handle_startup_dialogs … 20` 타임아웃과 mock 준비 대기가 겹친다). 스위트 전체 시간에 +2.7 분을 더한다(F6) |
|
||||||
|
|
||||||
|
## 8. 병합 차단 여부 (항목 8)
|
||||||
|
|
||||||
|
버전 락스텝 bump 부재(`lib.sh:32` `4.7.1`, 오케스트레이터가 4.7.2 로 처리 예정) 외에 **병합을 막을 결함은 없다**.
|
||||||
|
|
||||||
|
| # | 비차단 지적 | 근거 / 권고 |
|
||||||
|
|---|---|---|
|
||||||
|
| F1 | **codex 수락 키가 브리프 서술과 다르다.** 코드: 신뢰 창 `Enter`(1번 미리 선택), 업데이트 안내 **`2`**(Skip, 이번만). 브리프: `1`+Enter, `3`+Enter(Skip until next version). S4 의 codex 화면 픽스처(`Update available / 1. Update now / 2. Skip / 3. Skip until next version`)를 보면 3개 항목이 실제로 있고, 코드는 그중 **2** 를 고른다 — "아무것도 바꾸지 않는" 선택이라는 주석과 일치하나 다음 시작 때 다시 뜬다. 실제 시험은 PR 본문대로 통과했으므로 동작은 성립 | 병합 전 브리프 작성자와 한 번 맞출 것; `3` 이 의도라면 어댑터 한 줄 |
|
||||||
|
| F2 | 감사 기록의 새 필드(`dispatch_verified`·`dispatch_fingerprint`·`attempt_id`)가 MESSAGING.md·delegate-job SKILL.md 에 없다 | 한 문단 추가 권고 |
|
||||||
|
| F3 | `MAM_INJECT_ACK_GRACE_S` 가 create 의 대기에도 2순위로 영향을 준다는 점이 SKILL.md 에 없다(`create_session.sh:658`) | 문구 보강 |
|
||||||
|
| F4 | acceptance5 가 "retained `completed` 만 배달" 된 경우를 이제 실패로 본다(계약상 옳음). 공개 브로커에서 flake 가 늘 수 있는 자리 | 관찰되면 skip 조건 재검토 |
|
||||||
|
| F5 | 다이얼로그 시그니처는 화면의 디렉터리 경로를 검사하지 않는다 — pane 이 `-c $WORKSPACE` 로 뜨므로 실무 위험은 낮다 | 정보 |
|
||||||
|
| F6 | `test_issue24_resume_dialogs.py` 4건이 각 ~40 s | 타임아웃을 env 로 줄일 수 있으면 개선 |
|
||||||
|
|
||||||
|
## 9. 교차검증 가이드
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RP=/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260923T142448Z-609954/1
|
||||||
|
PY=/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python
|
||||||
|
git -C "$RP" rev-parse HEAD 'HEAD^{tree}' # f4ba205… / 88cb4f3…
|
||||||
|
# 교차 서버 규칙 (함수만 추출, env -i)
|
||||||
|
eval "$(sed -n '/^_herdr_caller_server() {/,/^}/p; /^_herdr_call_is_cross_server() {/,/^}/p' "$RP/.agents/skills/lib.sh")"
|
||||||
|
env -i HERDR_SOCKET_PATH=/x/.config/herdr/herdr.sock HERDR_SESSION_NAME=mam bash -c "$(declare -f _herdr_caller_server _herdr_call_is_cross_server); _herdr_call_is_cross_server && echo CROSS"
|
||||||
|
env -i HERDR_SOCKET_PATH=/x/.config/herdr/sessions/mam/herdr.sock HERDR_SESSION_NAME=mam bash -c "$(declare -f _herdr_caller_server _herdr_call_is_cross_server); _herdr_call_is_cross_server || echo same"
|
||||||
|
# 증거 규칙: 이전 토큰의 started / fingerprint 없는 감사 기록은 토큰 요구 시 거부 (§3-2 의 10 케이스)
|
||||||
|
# 수정 없이는 실패하는지 (사본에서만): 소스 12파일을 1e78dae 판으로 교체 후 새 테스트 2파일 → 60 failed / 12 passed
|
||||||
|
```
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"loop_id": "loop-20260923T220355Z-76dd1d",
|
||||||
|
"base_sha": "f4ba205c9f755d817e2206c7a9cb390a3e61fd2f",
|
||||||
|
"head_sha": "05b0ea4762de3fad013e8986d45db21c4e6aa465",
|
||||||
|
"tree_sha": "8f5e8b0402017d2cc809364e60400c4c25b922f3",
|
||||||
|
"review_commit": "05b0ea4762de3fad013e8986d45db21c4e6aa465",
|
||||||
|
"reviewer": "planner-reviewer-claude-01",
|
||||||
|
"job_id": "df626811",
|
||||||
|
"verdict": "PASS",
|
||||||
|
"transport": "herdr",
|
||||||
|
"evidence": "review-tree",
|
||||||
|
"isolation": "worktree",
|
||||||
|
"verified_at": "2026-09-23T23:35:19Z"
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# 🔍 Review Report — PR #35 델타 리뷰 2회차 (job `df626811`)
|
||||||
|
|
||||||
|
- **Reviewer**: `planner-reviewer-claude-01` (role: planner,reviewer) · 2026-09-24
|
||||||
|
- **대상 델타**: `f4ba205..05b0ea4` (1커밋 `05b0ea4`, 6파일 `+76/−5`, `git diff --check` 클린), base `main 1e78dae` (v4.7.1).
|
||||||
|
- **검증 경로**: `/var/folders/.../T/mam-review/loop-20260923T220355Z-76dd1d/1`. **identity 확인**: `HEAD = 05b0ea47…a465`, `HEAD^{tree} = 8f5e8b04…22f3` — 브리프와 일치.
|
||||||
|
- **1회차 내 판정**: PASS (job `adc0ff3c`). 이번에는 codex 탐침 2건의 정정이 실제로 닫혔는지와 부작용을 본다.
|
||||||
|
- **안전 규칙 준수**: 검증 경로·소스 워크트리·본 체크아웃(`main 1e78dae`) 모두 수정·커밋·checkout 없음. 함수 추출 실험과 되돌린 사본 실행은 scratchpad 에서만, pytest 는 `AGENT_PYTHON_BIN` + `--basetemp=<검증 경로 밖>`. 실제 herdr·세션·`.mam`·데몬 조작 없음, push·merge·PR 상태 변경 없음.
|
||||||
|
|
||||||
|
## 결론 요약
|
||||||
|
|
||||||
|
**두 정정은 탐침을 닫고, 1회차 판정을 뒤집을 요소는 없다.** P2 의 `continue` 는 S5/S5b 의 쿨다운 계약을 그대로 유지하면서 같은 화면의 다음 다이얼로그를 보게 하고, P1 의 `AUTO_TRUST="${MAM_AUTO_TRUST:-1}"` 는 "플래그 > 환경 > 기본 1" 의 우선순위를 문서대로 만든다. 비차단 관찰 2건(G1·G2).
|
||||||
|
|
||||||
|
## 1. P2 — `_mam_dialog_pick` 의 `continue` (항목 1)
|
||||||
|
|
||||||
|
`lib.sh:2954-2958`. 함수만 추출해 codex 어댑터의 다이얼로그 2개(신뢰 창 idx0 → `Enter`, 업데이트 안내 idx1 → `2`)와 **두 창이 함께 있는 화면**으로 7가지 상태를 돌렸다(cooldown 5 s):
|
||||||
|
|
||||||
|
| # | 상태 | 결과 | 의미 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | 기록 없음, 자동 신뢰 on | `send\|0\|Enter` | 신뢰 창이 먼저(어댑터 순서) |
|
||||||
|
| 2 | 신뢰 창을 1 s 전에 보냄(쿨다운 중), on | **`send\|1\|2`** | **P2 정정**: 쿨다운 중인 창을 건너뛰고 안내에 답한다. 옛 코드는 여기서 `exit 1` 로 아무것도 안 했다 |
|
||||||
|
| 3 | 기록 없음, 자동 신뢰 off | `skip\|0\|` | 신뢰 창은 사람 몫, skip 기록 |
|
||||||
|
| 4 | skip 1 s 뒤, off | **`send\|1\|2`** | **P2 정정**: skip 의 쿨다운이 안내를 가리지 않는다 |
|
||||||
|
| 5 | 두 창 모두 쿨다운 중 | 없음(rc 1) | **S5 유지**: 쿨다운 안에서는 재전송 없음 |
|
||||||
|
| 6 | 두 창 모두 쿨다운 만료(+5 s) | `send\|0\|Enter` | **S5b 유지**: 만료 후 1회 재시도, 다시 신뢰 창부터 |
|
||||||
|
| 7 | off, 만료 | `skip\|0\|` | 경고가 쿨다운마다 1회 |
|
||||||
|
|
||||||
|
**키 순서·횟수**: 핸들러는 한 폴링에 하나만 고르므로(`_mam_dialog_pick` 은 첫 actionable 항목에서 종료), 두 창이 한 화면에 있으면 **1회차 폴링에 `Enter`, 다음 폴링(1 s 뒤)에 `2`** 순으로 각 1회 간다. S5f 가 `["Enter", "2"]` 를, S6c 가 `["2"]` + 경고를 그대로 고정한다. 쿨다운은 **인덱스별**(`state[idx]`)이라 서로 간섭하지 않는다.
|
||||||
|
|
||||||
|
## 2. P1 — `AUTO_TRUST="${MAM_AUTO_TRUST:-1}"` (항목 2)
|
||||||
|
|
||||||
|
`create_session.sh:72,87-88,96` 과 `resume_session.sh:33,42-43,57` 이 같은 3단 구조(초기값 ← 환경, 플래그 arm 이 덮어씀, 마지막에 `export`)다. 세 줄을 그대로 옮긴 하네스로 8가지를 돌렸다:
|
||||||
|
|
||||||
|
| 환경 `MAM_AUTO_TRUST` | 플래그 | 핸들러가 받는 값 | 판정 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 없음 | – | `1` (on) | 기본 |
|
||||||
|
| `0` | – | `0` (**off**) | **P1 정정**: 문서의 환경변수 형식이 이제 닿는다(옛 코드는 `1` 로 덮어썼다) |
|
||||||
|
| `0` | `--auto-trust` | `1` (on) | 플래그 > 환경 |
|
||||||
|
| `1` | `--no-auto-trust` | `0` (off) | 플래그 > 환경 |
|
||||||
|
| 없음 | `--no-auto-trust` | `0` (off) | |
|
||||||
|
| `yes` / `false` | – | 그대로 전달 → 핸들러 `!= "0"` 규칙으로 **on** | `_mam_dialog_pick` 도 같은 규칙(`MAM_DLG_TRUST != "0"`)이라 두 층이 일치한다 |
|
||||||
|
| `''`(빈 문자열) | – | `:-1` 이 빈 값을 미설정으로 봐 `1` (on) | 핸들러의 `${MAM_AUTO_TRUST:-1}` 와 같은 해석 |
|
||||||
|
|
||||||
|
즉 "0 만 off, 나머지는 전부 on" 이 스크립트·핸들러·picker 세 층에서 동일하다(`lib.sh:2986`, picker 의 `!= "0"`). create SKILL.md `:119-120` 이 환경변수 형식과 "플래그 우선"을 명시한다. **G1 (비차단)**: `false`/`no` 가 on 으로 해석되는 것은 일관되지만 직관에 반한다 — 문서에 "`0` 만 끈다" 를 한 마디 적어 두면 좋다. resume SKILL.md 는 `:107` 에서 `MAM_AUTO_TRUST=0` 형식은 적지만 "플래그가 환경보다 우선" 은 create 쪽에만 있다(G2, 사소).
|
||||||
|
|
||||||
|
## 3. 테스트 (항목 1·3)
|
||||||
|
|
||||||
|
### 3-1. 수정 없이는 실패하는가 — 확인함
|
||||||
|
|
||||||
|
검증 경로 사본에서 `lib.sh`·`create_session.sh`·`resume_session.sh` 세 파일만 `f4ba205` 판으로 되돌리고 새 회귀와 이웃 시험을 `-k "s6c or s5f or r3b or c3 or test_s5_ or s5b or test_s6_"` 로 돌렸다:
|
||||||
|
|
||||||
|
```
|
||||||
|
4 failed, 7 passed, 70 deselected in 153.65s
|
||||||
|
FAILED test_s6c_a_skipped_trust_dialog_does_not_hide_the_notice_below_it ← P2
|
||||||
|
FAILED test_s5f_a_dialog_inside_its_cooldown_does_not_block_the_next_one ← P2
|
||||||
|
FAILED test_r3b_…_on_resume[0-flag0-0] (환경변수만, 플래그 없음) ← P1
|
||||||
|
FAILED test_c3_…_on_create[0-flag0-0] (환경변수만, 플래그 없음) ← P1
|
||||||
|
```
|
||||||
|
|
||||||
|
실패 4건이 정확히 두 탐침의 재현 사례다. 통과한 7건 — R3b/C3 의 "플래그가 환경을 이긴다" 4사례(플래그는 옛 코드에서도 동작했다), S5·S5b(쿨다운 계약), S6(신뢰 창 skip + 안내 응답, 한 화면에 하나씩) — 은 정정 전후로 **변하지 않아야 하는** 계약이고, 실제로 변하지 않았다. 즉 `continue` 가 S5/S5b 를 깨지 않았다는 것이 되돌린 사본과 PR 트리 양쪽에서 성립한다(PR 트리 쪽은 §3-2).
|
||||||
|
|
||||||
|
### 3-2. PR 트리(검증 경로)에서의 실행
|
||||||
|
|
||||||
|
```
|
||||||
|
tests/test_issue23_24_startup_path.py tests/test_issue24_resume_dialogs.py tests/test_c1_tui_readiness.py tests/test_b19_headless_reconcile_fixes.py
|
||||||
|
→ 120 passed in 535.40s (0:08:55) failed 0 · skipped 0
|
||||||
|
같은 -k 부분집합(새 회귀 4 + 이웃 7) 단독 → 11 passed in 148.21s
|
||||||
|
```
|
||||||
|
|
||||||
|
- 다이얼로그 핸들러를 건드리는 4파일 전부 통과. `c1`·`b19` 의 "프레임당 1회"·`Yes, try it` 가드도 유지된다.
|
||||||
|
- 실제 `.mam/jobs` 전후 **차이 0**. 검증 경로 tracked 파일 변화 없음(HEAD `05b0ea4`), 본 체크아웃 `main 1e78dae`.
|
||||||
|
- 시간: 이 호스트에서 다른 스위트 2개가 동시에 돌고 있어 resume 시험 6건이 각 37~41 s 였다(1회차 F6 그대로; R3b 3사례가 더해져 +2 분).
|
||||||
|
|
||||||
|
## 4. 병합 차단 여부 (항목 3)
|
||||||
|
|
||||||
|
1회차 PASS 를 뒤집을 요소는 없다. 델타는 세 줄의 소스 변경(`lib.sh:2958` `continue`, `create_session.sh:72`·`resume_session.sh:33` 의 환경 기본값)과 문서 한 줄, 회귀 4건이며, 두 탐침의 재현 사례만 정확히 실패→통과로 바뀌었다. 버전 락스텝 bump 부재(`4.7.1`, 오케스트레이터가 4.7.2 로 처리 예정) 외에 **병합을 막을 결함은 없다**.
|
||||||
|
|
||||||
|
| # | 비차단 관찰 | 근거 |
|
||||||
|
|---|---|---|
|
||||||
|
| G1 | `MAM_AUTO_TRUST` 는 `0` 만 끈다(`false`/`no` 는 on). 세 층(스크립트·핸들러·picker)이 일치하므로 결함은 아니지만 문서에 한 마디 있으면 좋다 | `create_session.sh:72`, `lib.sh:2986`, `_mam_dialog_pick` 의 `!= "0"` |
|
||||||
|
| G2 | "플래그가 환경보다 우선" 은 create SKILL.md(`:119-120`)에만 있고 resume SKILL.md(`:107`)에는 환경변수 형식만 있다 | 사소 |
|
||||||
|
|
||||||
|
1회차 F1(codex 수락 키와 브리프 서술의 차이)은 이 델타의 범위 밖이며 그대로 열려 있다.
|
||||||
|
|
||||||
|
## 5. 교차검증 가이드
|
||||||
|
|
||||||
|
```bash
|
||||||
|
RP=/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260923T220355Z-76dd1d/1
|
||||||
|
PY=/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python
|
||||||
|
git -C "$RP" rev-parse HEAD 'HEAD^{tree}' # 05b0ea4… / 8f5e8b0…
|
||||||
|
# picker 단독: 신뢰 창 쿨다운 중에도 안내에 답하는지
|
||||||
|
eval "$(sed -n '/^_mam_dialog_pick() {/,/^}/p' "$RP/.agents/skills/lib.sh")"
|
||||||
|
D='[["Do you trust the contents of this directory|1\\. Yes, continue",["Enter"],"trust"],["1\\. Update now|Skip until next version",["2"],"notice"]]'
|
||||||
|
S=$'Do you trust the contents of this directory?\n > 1. Yes, continue\nUpdate available\n 1. Update now\n 2. Skip\n 3. Skip until next version'
|
||||||
|
_mam_dialog_pick "$S" "$D" 1 "0:1000" 1001 5 # send|1|2 (정정 전: 출력 없음)
|
||||||
|
_mam_dialog_pick "$S" "$D" 1 "0:1000 1:1000" 1002 5 || echo nothing # S5 유지
|
||||||
|
# 되돌린 사본에서 회귀가 실패하는지: lib.sh/create/resume 를 f4ba205 판으로 교체 → -k "s6c or s5f or r3b or c3 ..." → 4 failed / 7 passed
|
||||||
|
```
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"loop_id": "loop-20260923T220355Z-76dd1d",
|
||||||
|
"base_sha": "f4ba205c9f755d817e2206c7a9cb390a3e61fd2f",
|
||||||
|
"head_sha": "05b0ea4762de3fad013e8986d45db21c4e6aa465",
|
||||||
|
"tree_sha": "8f5e8b0402017d2cc809364e60400c4c25b922f3",
|
||||||
|
"review_commit": "05b0ea4762de3fad013e8986d45db21c4e6aa465",
|
||||||
|
"reviewer": "planner-reviewer-codex-01",
|
||||||
|
"job_id": "81cd4006",
|
||||||
|
"verdict": "PASS",
|
||||||
|
"transport": "herdr",
|
||||||
|
"evidence": "review-tree",
|
||||||
|
"isolation": "worktree",
|
||||||
|
"verified_at": "2026-09-23T23:35:19Z"
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# PR #35 델타 리뷰 — 두 탐침 지적 해소
|
||||||
|
|
||||||
|
- Job: `81cd4006`; reviewer: `planner-reviewer-codex-01`
|
||||||
|
- Loop: `loop-20260923T220355Z-76dd1d`
|
||||||
|
- Base: `f4ba205c9f755d817e2206c7a9cb390a3e61fd2f`
|
||||||
|
- Head: `05b0ea4762de3fad013e8986d45db21c4e6aa465`
|
||||||
|
- Tree: `8f5e8b0402017d2cc809364e60400c4c25b922f3`
|
||||||
|
- 검증 경로: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260923T220355Z-76dd1d/1`
|
||||||
|
|
||||||
|
두 기존 지적이 해결되었다. 이번 델타에서 추가 병합 차단 결함을 발견하지 않았다. 브리프에 명시된 4.7.2 버전 락스텝 변경은 오케스트레이터의 후속 작업으로 남는다.
|
||||||
|
|
||||||
|
## P1: 환경변수 자동 신뢰 거부가 create/resume에서 보존됨
|
||||||
|
|
||||||
|
근거: `.agents/skills/multi-agent-mux-create/scripts/create_session.sh:72`, `:87`, `:88`, `:96`; `.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh:33`, `:42`, `:43`, `:57`.
|
||||||
|
|
||||||
|
초기값이 `AUTO_TRUST="${MAM_AUTO_TRUST:-1}"`로 바뀌어 환경의 `0`을 보존한다. 이후 명시적 플래그가 값을 덮어쓰므로 문서에 추가된 우선순위와 일치한다. 실제 create/resume 스크립트를 샌드박스의 mock herdr와 실행하는 C3/R3b 회귀가 다음 여섯 사례를 검증했다.
|
||||||
|
|
||||||
|
| 환경값 | 명시 플래그 | create/resume 핸들러에 전달되는 값 |
|
||||||
|
|---|---|---|
|
||||||
|
| `0` | 없음 | `0` |
|
||||||
|
| `0` | `--auto-trust` | `1` |
|
||||||
|
| `1` | `--no-auto-trust` | `0` |
|
||||||
|
|
||||||
|
추가로 두 스크립트에서 추출한 초기화·인자 처리 코드와 실제 `_mam_dialog_pick` 함수를 연결하여, 미설정·빈 문자열·`0`·`1`·`false`·`2`를 각각 검사했다(총 12사례). 미설정/빈 문자열은 `1`로 기본화되며, 정확히 `0`일 때만 신뢰 창을 건너뛴다. `false`와 `2`는 그대로 전달되고 자동 신뢰가 켜진다. 이는 핸들러의 기존 `!= "0"` 규칙과 일치하며 일반적인 boolean 문자열 파서로 바뀐 것은 아니다.
|
||||||
|
|
||||||
|
역검증: 별도 임시 샌드박스에서 해당 스크립트의 초기화 한 줄만 `AUTO_TRUST=1`로 되돌린 뒤, C3/R3b의 환경값 `0`, 플래그 없음 사례를 호출했다. create와 resume 모두 새 회귀의 assertion이 실패했다. 수정된 HEAD에서는 같은 사례가 통과했다. 기존 P1 지적을 해소한다.
|
||||||
|
|
||||||
|
## P2: 쿨다운 중인 신뢰 창이 뒤의 안내를 가리지 않음
|
||||||
|
|
||||||
|
근거: `.agents/skills/lib.sh:2953` 및 `:2958`. 쿨다운에 걸린 항목에서 검색 전체를 끝내던 `sys.exit(1)`이 다음 항목을 검사하는 `continue`로 바뀌었다. 항목별 쿨다운 판정과 전송 기록은 유지된다.
|
||||||
|
|
||||||
|
재현 화면은 신뢰 문구와 업데이트 안내를 함께 포함한다.
|
||||||
|
|
||||||
|
```text
|
||||||
|
Do you trust the contents of this directory?
|
||||||
|
> 1. Yes, continue
|
||||||
|
Update available
|
||||||
|
1. Update now
|
||||||
|
2. Skip
|
||||||
|
3. Skip until next version
|
||||||
|
```
|
||||||
|
|
||||||
|
S6c는 `MAM_AUTO_TRUST=0`, 쿨다운 30초, 핸들러 실행 3회 조건에서 신뢰 키 없이 `2`만 한 번 전송됨을 검증했다. S5f는 자동 신뢰가 켜진 상태와 쿨다운 60초에서 `Enter`, `2`가 이 순서로 각각 한 번 전송됨을 검증했다. 둘 다 통과했다. 기존 S5/S5b를 포함한 선택 테스트도 통과하여, 쿨다운 중 재전송 억제와 만료 후 재시도 동작이 보존됨을 확인했다.
|
||||||
|
|
||||||
|
역검증: 임시 사본에서 이 `continue`만 이전 `sys.exit(1)`로 되돌렸다. S6c는 실제 전송 키가 `[]`여서 실패했고, S5f는 실제 전송 키가 `[Enter]`뿐이어서 실패했다. 즉 새 테스트는 안내 전송 누락을 실제로 검출한다. 기존 P2 지적을 해소한다.
|
||||||
|
|
||||||
|
## 검증 결과와 범위
|
||||||
|
|
||||||
|
검증 트리의 HEAD/tree가 브리프와 일치하고 작업 트리가 깨끗함을 확인했다. `git diff f4ba205...HEAD`의 6개 파일을 검토했다. 제품 코드·소스 워크트리·실제 에이전트 세션은 수정하지 않았으며, 역검증 변경은 `/tmp/mam-81cd-revert-*`의 테스트 사본에만 적용했다.
|
||||||
|
|
||||||
|
실행한 선택 테스트:
|
||||||
|
|
||||||
|
```text
|
||||||
|
tests/test_issue23_24_startup_path.py
|
||||||
|
tests/test_issue24_resume_dialogs.py
|
||||||
|
-k 's5 or s6 or environment_form or no_auto_trust_reaches'
|
||||||
|
```
|
||||||
|
|
||||||
|
- 결과: **20 passed, 61 deselected in 191.05s**.
|
||||||
|
- 브리프의 Python 인터프리터를 `AGENT_PYTHON_BIN`과 실행 경로에 함께 지정했다. `PYTHONDONTWRITEBYTECODE=1`, `-p no:cacheprovider`, 검증 경로 밖의 고유 `--basetemp=/tmp/mam-review-81cd4006.*`를 사용했다.
|
||||||
|
- 수정 역검증 4건 모두 새 회귀 assertion이 예상대로 실패했다: 신뢰 거부+안내, 신뢰 수락+안내, create 환경값, resume 환경값.
|
||||||
|
- 환경값 경계 검사 12건 통과.
|
||||||
|
- `git diff --check f4ba205 HEAD`, 변경된 셸 파일 3개의 개별 `bash -n`, 변경된 Python 테스트 파일 2개의 AST 구문 검사 통과.
|
||||||
|
|
||||||
|
직전 `f4ba205` 리뷰에서 기록한 247건 통과는 이전 트리의 결과다. 이번 트리에서 247건 전체를 재실행했다고 주장하지 않으며, 이번 검증은 두 정정과 관련 회귀에 집중했다. 델타는 교차 서버 스코프, dispatch 증거, 롤백 구현을 변경하지 않는다. 새 회귀는 샌드박스의 mock herdr/화면 문자열을 사용하므로 실제 CLI 화면 수용 시험을 새로 수행했다는 의미도 아니다.
|
||||||
|
|
||||||
|
단순 수정으로 두 지적이 닫혔으므로 재설계 에스컬레이션은 필요하지 않다.
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"loop_id": "loop-20260923T220355Z-76dd1d",
|
||||||
|
"base_sha": "f4ba205c9f755d817e2206c7a9cb390a3e61fd2f",
|
||||||
|
"head_sha": "05b0ea4762de3fad013e8986d45db21c4e6aa465",
|
||||||
|
"tree_sha": "8f5e8b0402017d2cc809364e60400c4c25b922f3",
|
||||||
|
"review_commit": "05b0ea4762de3fad013e8986d45db21c4e6aa465",
|
||||||
|
"reviewer": "reviewer-agy-01",
|
||||||
|
"job_id": "471806f8",
|
||||||
|
"verdict": "PASS",
|
||||||
|
"transport": "herdr",
|
||||||
|
"evidence": "review-tree",
|
||||||
|
"isolation": "worktree",
|
||||||
|
"verified_at": "2026-09-23T23:35:19Z"
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# Pre-Merge Independent Delta Review Report: PR #35 (`fix/issue-23-24` Round 2)
|
||||||
|
|
||||||
|
- **Job ID**: `471806f8`
|
||||||
|
- **Target Agent**: `agy` (Session: `herdr:reviewer-agy-01`)
|
||||||
|
- **Role**: Reviewer
|
||||||
|
- **Target Worktree Context**:
|
||||||
|
- **Loop ID**: `loop-20260923T220355Z-76dd1d`
|
||||||
|
- **Base Commit**: `f4ba205c9f755d817e2206c7a9cb390a3e61fd2f` (Round 1 target)
|
||||||
|
- **Head Commit**: `05b0ea4762de3fad013e8986d45db21c4e6aa465` (1 delta commit: +76 / −5)
|
||||||
|
- **Tree SHA**: `8f5e8b0402017d2cc809364e60400c4c25b922f3`
|
||||||
|
- **Verification Path**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260923T220355Z-76dd1d/1`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Executive Summary
|
||||||
|
|
||||||
|
This second review round examines delta commit `05b0ea4` ("fix(issue-23-24): merge review - the environment form of the auto-trust switch reaches the handler; a rate-limited dialog does not hide the next one"). The commit addresses two specific edge-case probes identified during the merge review of PR #35:
|
||||||
|
1. **Probe P1**: In `create_session.sh` and `resume_session.sh`, hardcoded `AUTO_TRUST=1` unconditionally overwrote the documented environment switch `MAM_AUTO_TRUST=0`.
|
||||||
|
2. **Probe P2**: In `lib.sh::_mam_dialog_pick`, hitting a dialog within its resend cooldown triggered `sys.exit(1)`, preventing subsequent modal notices (e.g. codex update skip) on the same screen from being answered.
|
||||||
|
|
||||||
|
Both fixes, their regression test coverage (`test_issue23_24_startup_path.py` and `test_issue24_resume_dialogs.py`), and documentation updates in `multi-agent-mux-create/SKILL.md` were evaluated. All 18 targeted tests and git diff validation passed with zero regressions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Detailed Verification Against Checklist Items
|
||||||
|
|
||||||
|
### (1) Resolution of Codex Probes P1 & P2 and Side-Effect Analysis
|
||||||
|
- **P1: Environment Variable Inheritance (`AUTO_TRUST="${MAM_AUTO_TRUST:-1}"`)**:
|
||||||
|
- Previously, `create_session.sh` and `resume_session.sh` set `AUTO_TRUST=1` and subsequently exported `MAM_AUTO_TRUST="$AUTO_TRUST"`, clobbering caller-provided `MAM_AUTO_TRUST=0` when no CLI flag was supplied.
|
||||||
|
- Initializing `AUTO_TRUST="${MAM_AUTO_TRUST:-1}"` allows `MAM_AUTO_TRUST=0` in the environment to take effect naturally.
|
||||||
|
- An explicit CLI flag (`--auto-trust` or `--no-auto-trust`) re-assigns `AUTO_TRUST` to `1` or `0`, correctly asserting command-line precedence over environment variables.
|
||||||
|
- Regression verified by `test_r3b` (resume) and `test_c3` (create) across all combinations (env=0 alone, env=0 with `--auto-trust`, and env=1 with `--no-auto-trust`).
|
||||||
|
- **P2: Dialog Inspection Fallthrough via `continue`**:
|
||||||
|
- In `lib.sh::_mam_dialog_pick`, when a dialog matched on screen is within its cooldown window (`0 <= now - last < cooldown`), changing the behavior from `sys.exit(1)` to `continue` permits evaluation of subsequent dialog signatures in the adapter's list.
|
||||||
|
- If a trust dialog was skipped via `--no-auto-trust` (recorded in `_MAM_DIALOG_SENT`), or if it was answered on the preceding frame and is now cooling, a co-located notice dialog (such as the codex update prompt) is properly evaluated and answered on subsequent iterations.
|
||||||
|
- Verified by new test `test_s6c` (skipped trust dialog does not hide notice below it) and `test_s5f` (dialog inside cooldown does not block answering the next dialog).
|
||||||
|
- **Preservation of Cooldown Protection**:
|
||||||
|
- `test_s5` and `test_s5b` continue to verify that an individual dialog cannot be resent while its cooldown is active, and can only be retried once the cooldown window expires.
|
||||||
|
- Multi-dialog ordering and execution count remain deterministic: trust dialog answered first (`Enter`), followed by notice dialog (`2`), each sent exactly once (`test_s5f`).
|
||||||
|
|
||||||
|
### (2) Environment Precedence & Value Semantics
|
||||||
|
- In shell scripts (`create_session.sh` / `resume_session.sh`):
|
||||||
|
- `AUTO_TRUST="${MAM_AUTO_TRUST:-1}"` defaults to `1` when unset or empty.
|
||||||
|
- Any user-specified value (e.g. `0`) is preserved and exported.
|
||||||
|
- Command-line flags `--auto-trust` and `--no-auto-trust` overwrite `AUTO_TRUST` to `1` and `0` respectively, ensuring CLI options win over environment variables.
|
||||||
|
- In Python (`_mam_dialog_pick`):
|
||||||
|
- `auto_trust = os.environ.get("MAM_DLG_TRUST", "1") != "0"` cleanly maps string `"0"` to `False`, while any other non-"0" value defaults to `True`.
|
||||||
|
- Behavior between shell scripts and Python dialog picker is fully aligned.
|
||||||
|
- Documentation in `multi-agent-mux-create/SKILL.md` explicitly specifies `MAM_AUTO_TRUST=0` and documents that explicit flags take precedence over the environment.
|
||||||
|
|
||||||
|
### (3) Overall Merge Readiness
|
||||||
|
- Commit `05b0ea4` reinforces the robustness and reliability of PR #35 without altering any public interfaces or state machine rules verified in Round 1.
|
||||||
|
- Formatting and git diff checks (`git diff f4ba205...HEAD --check`) reported 0 whitespace or formatting issues.
|
||||||
|
- Version bump to `v4.7.2` remains scheduled for the orchestrator release commit.
|
||||||
|
- No blockers or regressions detected.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Test Execution Summary
|
||||||
|
|
||||||
|
| Test Suite / Target | Result | Duration | Notes |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| `test_issue23_24_startup_path.py` (`s6c`, `s5f`, `s5`, `s5b`) | **11 / 11 PASS** | 182s | Probe P2 cooldown fallthrough & multi-dialog handling |
|
||||||
|
| `test_issue24_resume_dialogs.py` (`r3b`, `c3`, `r3`) | **7 / 7 PASS** | 8s | Probe P1 environment variable inheritance & CLI flag precedence |
|
||||||
|
| `git diff f4ba205...HEAD --check` | **0 errors** | 0.05s | Clean formatting and no whitespace errors |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
# Pre-Merge Independent Review Report: PR #35 (`fix/issue-23-24`)
|
||||||
|
|
||||||
|
- **Job ID**: `c786c83f`
|
||||||
|
- **Target Agent**: `agy` (Session: `herdr:reviewer-agy-01`)
|
||||||
|
- **Role**: Reviewer
|
||||||
|
- **Target Worktree Context**:
|
||||||
|
- **Loop ID**: `loop-20260923T142448Z-609954`
|
||||||
|
- **Base Commit**: `1e78dae6ebcb01773df7c4715c98b1786965a24a` (v4.7.1)
|
||||||
|
- **Head Commit**: `f4ba205c9f755d817e2206c7a9cb390a3e61fd2f`
|
||||||
|
- **Tree SHA**: `88cb4f34f1e9f8220a373350cfc600a53735f181`
|
||||||
|
- **Verification Path**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260923T142448Z-609954/1`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Executive Summary
|
||||||
|
|
||||||
|
PR #35 addresses Issue #23 and Issue #24 ("교차 서버 herdr 스코프와 에이전트 무관 시작 다이얼로그, 실제 에이전트가 충족하는 온보딩 전달 판정") across 13 commits and 22 files (+2197 / −118).
|
||||||
|
|
||||||
|
The branch eliminates cross-server scope leaks (`HERDR_WORKSPACE_ID` / `HERDR_PANE_ID` / `HERDR_TAB_ID`), externalizes agent start-up modal handling into declarative adapter facts, standardizes protocol-level `started` acknowledgement for agent onboarding, and implements robust fail-closed rollback handling (exit code 43 on unkillable sessions).
|
||||||
|
|
||||||
|
All verification tasks were performed in the isolated verification path. All 73 tests in the new test suites (`test_issue23_24_startup_path.py`, `test_issue24_resume_dialogs.py`) and all 177 regression tests in the adjusted suites passed without error.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Detailed Verification Against Checklist Items
|
||||||
|
|
||||||
|
### (1) Issue #24 Startup Dialogs
|
||||||
|
- **Adapter-Driven Declarative Modals**:
|
||||||
|
- Signatures, response keystrokes, and dialog classifications (`trust` vs. `notice`) are defined per agent in `lib_py/agents/adapters/*.py` (`startup_dialogs` property) and exposed via `lib_py.agents facts` (`MAM_STARTUP_DIALOGS`).
|
||||||
|
- Supported keys match target agent TUI specifications:
|
||||||
|
* `agy`: `'Do you trust the contents of this project|Yes, I trust this folder'` -> `['Enter']` (`trust`).
|
||||||
|
* `grok`: `'Do you trust the contents of this directory'` -> `['y']` (`trust`).
|
||||||
|
* `codex`: `'Do you trust the contents of this directory|1\\. Yes, continue'` -> `['Enter']` (`trust`); `'1\\. Update now|Skip until next version'` -> `['2']` (`notice`, selects "2. Skip").
|
||||||
|
* `claude`: Full legacy ladder (`Enter` for trust/proceed, `Escape` for fullscreen upsell modal to preserve execution flags, `Down`+`Enter` for proceed).
|
||||||
|
- **Cooldown & Ready Token Gating**:
|
||||||
|
- Because herdr `--source visible` capture retains modal text on-screen temporarily after acceptance, re-sending keystrokes is rate-limited by `MAM_DIALOG_RESEND_S` (default 5s cooldown).
|
||||||
|
- TUI readiness is strictly judged by adapter ready tokens (`MAM_STRONG_READY_TOKENS` / `MAM_READY_TOKENS`), never by modal disappearance (`test_s5c`, `test_s5d`).
|
||||||
|
- **`--no-auto-trust` Flag & Workspace Scope**:
|
||||||
|
- Setting `--no-auto-trust` (`MAM_AUTO_TRUST=0`) leaves dialogs of kind `trust` unanswered (warning printed to stderr for operator confirmation) while continuing to auto-handle `notice` dialogs (`test_s6`).
|
||||||
|
- Crucial for `codex` security, where directory trust activates project-local configuration, hooks, and execution policies.
|
||||||
|
- Automatic trust is only sent to sessions launched inside the designated `--workspace`.
|
||||||
|
- **Contract Parity across Create and Resume**:
|
||||||
|
- `create_session.sh` and `resume_session.sh` both invoke `handle_startup_dialogs "$SESSION_NAME" <timeout> "$AGENT"`, parse `--no-auto-trust`, and share `_mam_load_dialog_facts` (`test_r1`, `test_r2`, `test_r3`, `test_r4`).
|
||||||
|
|
||||||
|
### (2) Issue #23 Cross-Server Herdr Scoping
|
||||||
|
- **Targeted Scope Variable Stripping**:
|
||||||
|
- In `lib.sh` (`mam_herdr`), `_herdr_call_is_cross_server` strips `HERDR_WORKSPACE_ID`, `HERDR_PANE_ID`, and `HERDR_TAB_ID` via `env -u ...` **only** when targeting a different server (`caller != target`).
|
||||||
|
- Same-server calls retain workspace/pane scoping, protecting workspace packing and pane isolation (`test_s2`, `test_s1e`). Calls outside panes retain explicit scopes (`test_s2b`).
|
||||||
|
- **Caller Server Identification**:
|
||||||
|
- `_herdr_caller_server` checks `HERDR_SESSION` first. If unset (e.g. herdr 0.8.2 on the default server), it parses `HERDR_SOCKET_PATH`:
|
||||||
|
* `*/.config/herdr/herdr.sock` -> `default`
|
||||||
|
* `*/.config/herdr/sessions/<name>/herdr.sock` -> `<name>`
|
||||||
|
* Unknown formats -> `""` (treated safely as non-pane).
|
||||||
|
- Verified across both default and named session socket layouts on herdr 0.8.2 and 0.9.0 (`test_s1c`, `test_s1d`, `test_s1f`, `test_s1g`, `test_s1h`).
|
||||||
|
- **Python Watcher Parity**:
|
||||||
|
- `lib_py/loop/watcher.py` implements identical logic (`caller_server()` and `scoped_env()`) for direct subprocess executions of herdr (`test_s13`).
|
||||||
|
|
||||||
|
### (3) Issue #23 Onboarding Delivery Verification
|
||||||
|
- **Unified Command Builder & Predicate**:
|
||||||
|
- `delegate_publish_cmd` in `lib.sh` generates the canonical publish command with `--expect-dispatch-token <token> --attempt-id <attempt>`.
|
||||||
|
- `test_s7l` confirms `delegate_publish_cmd` produces identical arguments to the delegate-job wrapper's `_pub_cmd`.
|
||||||
|
- Both `create_session.sh` and the wrapper (`_wait_started`) share `delegate_started_recorded` from `lib.sh`.
|
||||||
|
- **Dispatch Attribution & Single-Injection Contract**:
|
||||||
|
- Local events: `<registry>/<job_id>.events.log` requires `event == "started"` and `data.dispatch_token == <token>`.
|
||||||
|
- Remote events: `<logs_dir>/<job_id>/events.ndjson` requires `source_event == "started"`, `dispatch_verified is True`, and `dispatch_fingerprint == sha256(<token>)`.
|
||||||
|
- Prevents a prior attempt's started record from acknowledging a subsequent re-dispatch (`test_w2`, `test_w7`).
|
||||||
|
- Legacy records lacking a fingerprint fail closed when a token is demanded (`test_w8`).
|
||||||
|
- **Elimination of Status Bypass**:
|
||||||
|
- The previous wrapper fallback (`disk_status != pending -> success`) was completely removed. Both create and wrapper now strictly verify `started` event attribution (`test_w1`, `test_w4`).
|
||||||
|
- **Terminal State Protection**:
|
||||||
|
- If a job has already transitioned to a terminal status (`completed`, `error`, `cancelled`), `create_session.sh` leaves the job untouched rather than issuing a conflicting state change (`test_s7f`, `test_s7m`).
|
||||||
|
- **Liveness Parity**:
|
||||||
|
- Respects Issue #18 liveness contract (T=180s timeout, configurable via `MAM_ONBOARD_ACK_S`).
|
||||||
|
|
||||||
|
### (4) Issue #23 Rollback & Error Handling
|
||||||
|
- **Kill Confirmation & Exit Code 43**:
|
||||||
|
- `cleanup_herdr_on_error` checks the returncode of `kill-session` and affirmatively verifies session termination via `has-session`.
|
||||||
|
- If the session remains alive, the script updates `agent-sessions.yaml` to `status: running` with `last_visible_status: rollback-failed`, clears `delegate_job_id`, prints manual cleanup instructions, and exits with code **43** (`test_s9`).
|
||||||
|
- If cleanly killed, it marks `status: terminated`, `last_visible_status: rolled-back`, publishes `cancelled` for the onboarding job, and exits (`test_s10`).
|
||||||
|
- **Session Preservation on Handshake Timeout**:
|
||||||
|
- If an onboarding `started` event is not observed within `ONBOARD_ACK_S`, the onboarding job is marked `error`, but the session and its pane are **preserved** (`test_s7d`). Operators can re-submit onboarding via `multi-agent-mux-delegate-job submit` once the agent finishes initializing.
|
||||||
|
|
||||||
|
### (5) Impact on Existing Test Suites (6 Files)
|
||||||
|
- `tests/conftest.py`: Injects `MAM_ONBOARD_ACK_S=3` into the `mam_sandbox` fixture to prevent sandbox runs without real agents from waiting 180s.
|
||||||
|
- `tests/test_b19_headless_reconcile_fixes.py`: Relocated modal assertion to inspect `claude.py` adapter facts.
|
||||||
|
- `tests/test_c1_tui_readiness.py`: Updated `test_c1b_hint_press_enter_sends_enter` to reflect time-based cooldown semantics (`MAM_DIALOG_RESEND_S`), verifying `1 <= count <= 30`.
|
||||||
|
- `tests/test_issue14_delivery_ack.py`: Updated out-of-band agent acknowledgement to publish a genuine `started` event with token via `publish_event.py`.
|
||||||
|
- `tests/test_issue18_liveness_contract.py`: Assertions match the protocol requirement (`recorded 'started'`).
|
||||||
|
- `tests/test_issue5_phase2a_loop.py`: Refined G9 guard using Python AST parsing (`_code_only`) to strip only docstring expression nodes while preserving same-line code statements. Rigorously tested by `test_g9b_the_guard_still_catches_an_invocation_and_ignores_prose`.
|
||||||
|
|
||||||
|
### (6) Test Isolation & Reliability
|
||||||
|
- New suites (`test_issue23_24_startup_path.py` [1268 lines] and `test_issue24_resume_dialogs.py` [127 lines]) operate completely within isolated sandboxes.
|
||||||
|
- Real `registry.py` and `publish_event.py` utilities are exercised against isolated directories.
|
||||||
|
- Zero mutation of control plane `.mam`, live agent sessions, or daemon processes.
|
||||||
|
|
||||||
|
### (7) Documentation Integrity
|
||||||
|
- `multi-agent-mux-create/SKILL.md` and `multi-agent-mux-resume/SKILL.md` accurately document `--no-auto-trust`, exit codes 42/43, and `MAM_ONBOARD_ACK_S`.
|
||||||
|
- Event and audit log schemas (`dispatch_fingerprint`, `dispatch_verified`) align with `MESSAGING.md`.
|
||||||
|
|
||||||
|
### (8) Merge Readiness
|
||||||
|
- Version bump to `v4.7.2` is scheduled for the orchestrator release commit.
|
||||||
|
- Code style, formatting, and diff integrity checks (`git diff 1e78dae...HEAD --check`) reported 0 issues.
|
||||||
|
- Zero architectural, functional, or regression defects found.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Test Execution Summary
|
||||||
|
|
||||||
|
| Test Suite | Result | Duration | Notes |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| `tests/test_issue23_24_startup_path.py` | **68 / 68 PASS** | 358s | S1–S13, S4–S6, S7–S10, W1–W8 test matrix |
|
||||||
|
| `tests/test_issue24_resume_dialogs.py` | **5 / 5 PASS** | 8s | R1–R4 resume dialog parity |
|
||||||
|
| `tests/test_issue5_phase2a_loop.py` | **91 / 91 PASS** | 3.1s | Loop orchestration & updated G9 AST guard |
|
||||||
|
| `tests/test_issue18_liveness_contract.py` | **31 / 31 PASS** | 112s | Protocol liveness, subscriber audit & broker fallback |
|
||||||
|
| `tests/test_c1_tui_readiness.py` | **23 / 23 PASS** | 45s | TUI readiness & rate-limited dialog responses |
|
||||||
|
| `tests/test_b19_headless_reconcile_fixes.py` | **16 / 16 PASS** | 1.8s | Reconcile fixes & dialog exclusion assertions |
|
||||||
|
| `tests/test_issue14_delivery_ack.py` | **12 / 12 PASS** | 98s | Delivery acknowledgement contracts |
|
||||||
|
| `tests/test_version_consistency.py` | **3 / 3 PASS** | 0.2s | Version consistency checks |
|
||||||
|
| `git diff 1e78dae...HEAD --check` | **0 errors** | 0.05s | Clean whitespace and formatting |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# 🔍 Review Report — Job 59e62ce6 (PR #35 @ `f4ba205`)
|
||||||
|
|
||||||
|
- **Reviewer**: `reviewer-grok-01` · 2026-09-22
|
||||||
|
- **검증 경로**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260923T142448Z-609954/1`
|
||||||
|
- **identity**: base `1e78dae` head `f4ba205` tree `88cb4f3` (일치)
|
||||||
|
- **본 체크아웃**: `main` `1e78dae` 유지. 소스 워크트리·herdr 미조작.
|
||||||
|
|
||||||
|
`git diff --check 1e78dae...HEAD` 클린. 13커밋.
|
||||||
|
|
||||||
|
## (1) #24 다이얼로그
|
||||||
|
|
||||||
|
어댑터 `startup_dialogs` (`facts` 로 `MAM_STARTUP_DIALOGS`):
|
||||||
|
|
||||||
|
| 에이전트 | 키 | kind |
|
||||||
|
|---|---|---|
|
||||||
|
| agy | Enter | trust |
|
||||||
|
| grok | `y` | trust |
|
||||||
|
| codex trust | Enter (`1. Yes, continue` 선선택) | trust |
|
||||||
|
| codex 업데이트 | **`2`** (Skip) | notice |
|
||||||
|
| claude | Enter / Escape / Down+Enter | 기존 사다리 |
|
||||||
|
|
||||||
|
브리프의 “`3`+Enter” 와 다름. 코드·테스트(`test_s4`, `test_s6`)는 **`2`** 를 잠근다. 주석: 0.155.1 화면에서 2 가 Skip. `--source visible` 잔상 때문에 재전송은 `MAM_DIALOG_RESEND_S`(기본 5s) 이고 수락은 ready 토큰만 (`lib.sh` `handle_startup_dialogs`). `--no-auto-trust` / `MAM_AUTO_TRUST=0` 은 trust 만 건너뛰고 notice 는 답함. 신뢰는 `--workspace` 로 연 그 세션의 창. create·resume 둘 다 `handle_startup_dialogs "$SESSION" … "$AGENT"` 와 `MAM_AUTO_TRUST`.
|
||||||
|
|
||||||
|
## (2) #23 교차 서버
|
||||||
|
|
||||||
|
`_herdr_call_is_cross_server` (`lib.sh:1437-1446`): 대상이 비거나 `default` 이면 스트립 안 함(같은 서버·#7 패킹의 `HERDR_WORKSPACE_ID` 유지). 호출자 서버 없음(pane 밖)도 스트립 안 함. `HERDR_SESSION` 이 있으면 소켓보다 우선. 없으면 `HERDR_SOCKET_PATH` 모양: `…/.config/herdr/herdr.sock` → `default`, `…/.config/herdr/sessions/<name>/herdr.sock` → `<name>`. 0.8.2 기본 서버 pane 은 `HERDR_SESSION` 이 없어도 소켓으로 판별. 0.9 는 소켓 규약이 같고, 주석의 0.9 차이는 agent status 미보고(`lib.sh:2792`)이지 소켓 형태가 아님. `watcher.scoped_env` 가 같은 규칙.
|
||||||
|
|
||||||
|
## (3) 온보딩 전달
|
||||||
|
|
||||||
|
`delegate_publish_cmd` / `delegate_started_recorded` 를 create 와 래퍼 `_wait_started` 가 공유. 증거는 **이번 `dispatch_token`** 의 `events.log` `started`, 또는 감사 `events.ndjson` 의 `dispatch_verified` **그리고** `dispatch_fingerprint == sha256(token)`. 지문 없는 옛 기록은 토큰이 있을 때 거부. 레지스트리 status 는 증거가 아님(래퍼 `:641-646`). 이미 터미널인 잡은 `JOB_TERMINALIZED` 로 두 번째 close 를 안 함. T 기본 180, heartbeat 계약 유지. create 는 더 이상 대리 `started` 를 안 찍음.
|
||||||
|
|
||||||
|
## (4) 실패 처리
|
||||||
|
|
||||||
|
롤백: `kill-session` rc 후 `has-session`. 살아 있으면 행 `status: running`, `last_visible_status: rollback-failed`, `delegate_job_id` 비움, **exit 43**. 죽었으면 `terminated` / `rolled-back`. 온보딩 미확인은 세션 유지, 잡 `error`, `MAM_ONBOARD_ACK_S` 가 대기. create SKILL.md 와 맞음.
|
||||||
|
|
||||||
|
## (5) 기존 테스트
|
||||||
|
|
||||||
|
G9 는 AST 에서 docstring 노드만 빼고 나머지 코드를 unparse (`test_issue5_phase2a_loop.py:710-729`). `test_g9b` 가 호출·경로 문자열은 여전히 잡고 주석/독스트링은 놓음을 잠금. 의도 약화 아님. issue14 는 started 증거 계약에 맞춰 조정.
|
||||||
|
|
||||||
|
## (6) 새 테스트
|
||||||
|
|
||||||
|
`test_issue23_24_startup_path.py`·`test_issue24_resume_dialogs.py` 는 mock herdr / tmp. 실제 herdr·홈 미접촉. 검증 경로에서 `AGENT_PYTHON_BIN` 으로 **177 passed in 461.74s** (위 두 파일 + issue5 phase2a + issue14).
|
||||||
|
|
||||||
|
## (7)–(8) 문서·락스텝
|
||||||
|
|
||||||
|
create SKILL: `--no-auto-trust`, exit 43, `MAM_ONBOARD_ACK_S`. resume SKILL: `--no-auto-trust` 와 같은 핸들러. **비차단**: `MESSAGING.md` 와 delegate-job SKILL.md 본문에 `dispatch_fingerprint` 단어가 없음. 필드는 `job_subscriber.py` 주석과 감사 레코드에 있다. 락스텝은 4.7.1; 4.7.2 는 오케스트레이터 예정. 병합 차단 아님.
|
||||||
|
|
||||||
|
## 종합
|
||||||
|
|
||||||
|
#23 교차 서버 스코프와 #24 에이전트 무관 다이얼로그, 실제 `started` 로만 온보딩을 판정하는 계약이 코드·테스트와 맞다. 설계 재작업 불필요.
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"loop_id": "loop-20260923T220355Z-76dd1d",
|
||||||
|
"base_sha": "f4ba205c9f755d817e2206c7a9cb390a3e61fd2f",
|
||||||
|
"head_sha": "05b0ea4762de3fad013e8986d45db21c4e6aa465",
|
||||||
|
"tree_sha": "8f5e8b0402017d2cc809364e60400c4c25b922f3",
|
||||||
|
"review_commit": "05b0ea4762de3fad013e8986d45db21c4e6aa465",
|
||||||
|
"reviewer": "reviewer-grok-01",
|
||||||
|
"job_id": "8352b00e",
|
||||||
|
"verdict": "PASS",
|
||||||
|
"transport": "herdr",
|
||||||
|
"evidence": "review-tree",
|
||||||
|
"isolation": "worktree",
|
||||||
|
"verified_at": "2026-09-23T23:35:19Z"
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# 🔍 Review Report — Job 8352b00e (PR #35 델타 `f4ba205...05b0ea4`)
|
||||||
|
|
||||||
|
- **Reviewer**: `reviewer-grok-01` · 2026-09-24
|
||||||
|
- **검증 경로**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260923T220355Z-76dd1d/1`
|
||||||
|
- **identity**: head `05b0ea4` tree `8f5e8b0` (일치). 1회차 grok PASS @ `f4ba205` 를 뒤집지 않음.
|
||||||
|
- **본 체크아웃**: `main` `1e78dae` 유지.
|
||||||
|
|
||||||
|
`git diff --check f4ba205...HEAD` 클린. 커밋 1개.
|
||||||
|
|
||||||
|
## (1) 탐침 두 건 — 닫힘
|
||||||
|
|
||||||
|
**P1.** `create_session.sh:72` 와 `resume_session.sh:33` 이 `AUTO_TRUST="${MAM_AUTO_TRUST:-1}"` 후 플래그 case 가 덮어쓰고, 그 다음 `export MAM_AUTO_TRUST`. 환경만 `0` 이면 핸들러에 `0`. `--auto-trust` / `--no-auto-trust` 가 이김. R3b·C3 각 3사례 통과.
|
||||||
|
|
||||||
|
**P2.** `_mam_dialog_pick` (`lib.sh:2954-2958`) 이 쿨다운 중이면 `sys.exit(1)` 대신 `continue`. 같은 화면의 다음 다이얼로그를 본다.
|
||||||
|
|
||||||
|
- S6c: `--no-auto-trust` + 신뢰 창과 업데이트 안내가 같이 있으면 키는 `2` 한 번, stderr 에 no-auto-trust.
|
||||||
|
- S5f: 자동 신뢰면 순서 `Enter` 다음 `2`, 각 1회.
|
||||||
|
|
||||||
|
임시 사본에서 `continue` 를 `sys.exit(1)` 로 되돌리면 S6c·S5f **2 failed** (안내는 안 나감). 정정 트리에서는 통과.
|
||||||
|
|
||||||
|
**부작용.** S5(수락된 창은 쿨다운 안 재전송)·S5b(만료 후 1회) 그대로 통과. 한 다이얼로그만 있으면 루프 끝이 여전히 `sys.exit(1)` 이라 “할 일 없음”.
|
||||||
|
|
||||||
|
## (2) `0`/`1` 외 값
|
||||||
|
|
||||||
|
핸들러는 `MAM_DLG_TRUST != "0"` (`lib.sh` pick 의 `auto_trust`). 리터럴 `"0"` 만 끔. `"false"`/`"no"`/`"00"` 은 켜짐. 빈 환경은 `${MAM_AUTO_TRUST:-1}` 이 `1`. 문서가 약속한 형식은 `MAM_AUTO_TRUST=0` 이라 일치. create SKILL.md 에 환경 형식과 “명시 플래그가 이김”이 있음.
|
||||||
|
|
||||||
|
## (3) 1회차·락스텝
|
||||||
|
|
||||||
|
교차 서버 스코프, started-only 온보딩, exit 43 은 이 커밋이 건드리지 않음. 4.7.2 bump 는 오케스트레이터 예정. 병합 차단 아님.
|
||||||
|
|
||||||
|
## 테스트 (검증 경로)
|
||||||
|
|
||||||
|
S5, S5b, S5f, S6, S6c, R3b×3, C3×3: **11 passed in 152.03s**.
|
||||||
|
|
||||||
|
## 종합
|
||||||
|
|
||||||
|
두 탐침이 코드·회귀와 맞다. 쿨다운은 같은 다이얼로그의 재전송만 막고, 다음 다이얼로그는 막지 않는다. 설계 재작업 불필요.
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -29,7 +29,7 @@ export WORKSPACE_ROOT
|
|||||||
# Framework semantic version. Single runtime source of truth; kept in lockstep
|
# 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.
|
# 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.
|
# NOTE: unlike other MAM_* variables this one is intentionally NOT env-overridable.
|
||||||
MAM_VERSION="4.7.1"
|
MAM_VERSION="4.7.2"
|
||||||
export MAM_VERSION
|
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}"
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import sys
|
|||||||
from typing import List, Sequence
|
from typing import List, Sequence
|
||||||
|
|
||||||
# Framework version locked with framework constants
|
# Framework version locked with framework constants
|
||||||
FRAMEWORK_VERSION = "4.7.1"
|
FRAMEWORK_VERSION = "4.7.2"
|
||||||
|
|
||||||
CORE_MODULES: Sequence[str] = (
|
CORE_MODULES: Sequence[str] = (
|
||||||
# Standard library modules
|
# Standard library modules
|
||||||
|
|||||||
@@ -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: 4.7.1
|
version: 4.7.2
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
@@ -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, 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, grok-build, codex, or a human) and observe it asynchronously over an MQTT event channel. Supported roles include orchestrator, worker, and reviewer."
|
||||||
version: 4.7.1
|
version: 4.7.2
|
||||||
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: 4.7.1
|
version: 4.7.2
|
||||||
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: 4.7.1
|
version: 4.7.2
|
||||||
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: 4.7.1
|
version: 4.7.2
|
||||||
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: 4.7.1
|
version: 4.7.2
|
||||||
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: 4.7.1
|
version: 4.7.2
|
||||||
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: 4.7.1
|
version: 4.7.2
|
||||||
author: godopu
|
author: godopu
|
||||||
license: MIT
|
license: MIT
|
||||||
platforms: [linux, macos]
|
platforms: [linux, macos]
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
본 문서는 `herdr_agent_orchestration` 오케스트레이션 및 메시징 백플레인 워크플로우를 새로운 프로젝트에 도입하여 이식하고, 새로운 개발자/에이전트가 초기 가동을 시작할 때 수행해야 하는 환경 설정 및 구축 절차를 안내합니다.
|
본 문서는 `herdr_agent_orchestration` 오케스트레이션 및 메시징 백플레인 워크플로우를 새로운 프로젝트에 도입하여 이식하고, 새로운 개발자/에이전트가 초기 가동을 시작할 때 수행해야 하는 환경 설정 및 구축 절차를 안내합니다.
|
||||||
|
|
||||||
[](VERSIONS.md)
|
[](VERSIONS.md)
|
||||||
|
|
||||||
새로운 에이전트는 이 안내서에 기술된 절차를 순차적으로 실행하여 초기 환경을 안정적으로 설정할 수 있습니다.
|
새로운 에이전트는 이 안내서에 기술된 절차를 순차적으로 실행하여 초기 환경을 안정적으로 설정할 수 있습니다.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
This document guides you through the setup and initialization procedures required to adopt the `herdr_agent_orchestration` orchestration and messaging backplane workflow in a new project, enabling a new developer or agent to get up and running quickly.
|
This document guides you through the setup and initialization procedures required to adopt the `herdr_agent_orchestration` orchestration and messaging backplane workflow in a new project, enabling a new developer or agent to get up and running quickly.
|
||||||
|
|
||||||
[](VERSIONS.md)
|
[](VERSIONS.md)
|
||||||
|
|
||||||
A new agent can follow the steps in this guide sequentially to establish a stable and reliable initial environment.
|
A new agent can follow the steps in this guide sequentially to establish a stable and reliable initial environment.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
# Messaging System Technical Analysis & Architecture Report
|
# Messaging System Technical Analysis & Architecture Report
|
||||||
|
|
||||||
Applies to: MAM v4.7.1
|
Applies to: MAM v4.7.2
|
||||||
|
|
||||||
This report provides a comprehensive, deep-dive analysis of the messaging system implemented in the `multi-agent-mux-delegate-job` skill. It covers the MQTT broker architecture, event protocols, job lifecycles, codebase internals, cross-system integration, and a list of known limitations along with production recommendations.
|
This report provides a comprehensive, deep-dive analysis of the messaging system implemented in the `multi-agent-mux-delegate-job` skill. It covers the MQTT broker architecture, event protocols, job lifecycles, codebase internals, cross-system integration, and a list of known limitations along with production recommendations.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Herdr와 MQTT 브로커를 기반으로 구축된 고신뢰성 **다중 에이전트 오케스트레이션 및 메시징 백플레인** 프레임워크입니다. `claude`, `agy`, `hermes`, `grok`, `opencode`, `codex` 등 다중 LLM 백엔드 에이전트 전반에 걸쳐 장시간 수행되는 작업(코드 생성, 리팩토링, 보안 검토 등)을 조정, 격리 및 감사할 수 있도록 설계되었습니다.
|
Herdr와 MQTT 브로커를 기반으로 구축된 고신뢰성 **다중 에이전트 오케스트레이션 및 메시징 백플레인** 프레임워크입니다. `claude`, `agy`, `hermes`, `grok`, `opencode`, `codex` 등 다중 LLM 백엔드 에이전트 전반에 걸쳐 장시간 수행되는 작업(코드 생성, 리팩토링, 보안 검토 등)을 조정, 격리 및 감사할 수 있도록 설계되었습니다.
|
||||||
|
|
||||||
[](VERSIONS.md)
|
[](VERSIONS.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
An advanced, high-reliability **Multi-Agent Orchestration & Messaging Backplane** framework built on Herdr and MQTT. It is designed to coordinate, isolate, and audit long-running agent tasks (such as code generation, refactoring, and security reviews) across multiple LLM backend clients (`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`).
|
An advanced, high-reliability **Multi-Agent Orchestration & Messaging Backplane** framework built on Herdr and MQTT. It is designed to coordinate, isolate, and audit long-running agent tasks (such as code generation, refactoring, and security reviews) across multiple LLM backend clients (`claude`, `agy`, `hermes`, `grok`, `opencode`, `codex`).
|
||||||
|
|
||||||
[](VERSIONS.md)
|
[](VERSIONS.md)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+29
-11
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
## 📌 현재 버전 개요 (Current Release)
|
## 📌 현재 버전 개요 (Current Release)
|
||||||
|
|
||||||
- **프레임워크 버전**: `v4.7.1`
|
- **프레임워크 버전**: `v4.7.2`
|
||||||
- **최신 릴리스 일시**: 2026-09-22 (KST)
|
- **최신 릴리스 일시**: 2026-09-23 (KST)
|
||||||
- **기준 브랜치**: `main`
|
- **기준 브랜치**: `main`
|
||||||
- **핵심 아키텍처**:
|
- **핵심 아키텍처**:
|
||||||
- **Terminal 상태 단방향 불변성 (`engine.py`, Issue #6 Phase 1)**: `completed`, `error`, `cancelled` 터미널 상태 진입 후 후속 이벤트나 업데이트에 의한 덮어쓰기를 엄격히 차단(Terminal Immutability). `registry.py close` 서브커맨드 및 fail-closed 조기 종료 도입.
|
- **Terminal 상태 단방향 불변성 (`engine.py`, Issue #6 Phase 1)**: `completed`, `error`, `cancelled` 터미널 상태 진입 후 후속 이벤트나 업데이트에 의한 덮어쓰기를 엄격히 차단(Terminal Immutability). `registry.py close` 서브커맨드 및 fail-closed 조기 종료 도입.
|
||||||
@@ -22,23 +22,41 @@
|
|||||||
|
|
||||||
## 🧭 스킬 패키지 버전 매트릭스 (Skills Version Matrix)
|
## 🧭 스킬 패키지 버전 매트릭스 (Skills Version Matrix)
|
||||||
|
|
||||||
모든 8개 스킬은 YAML frontmatter 메타데이터(`author`, `version`, `platforms`, `environments`) 표준화를 통해 `v4.7.1`로 동기화되어 배포됩니다.
|
모든 8개 스킬은 YAML frontmatter 메타데이터(`author`, `version`, `platforms`, `environments`) 표준화를 통해 `v4.7.2`로 동기화되어 배포됩니다.
|
||||||
|
|
||||||
| 스킬명 | 버전 | 역할 및 주요 책임 | 상태 |
|
| 스킬명 | 버전 | 역할 및 주요 책임 | 상태 |
|
||||||
| :--- | :---: | :--- | :---: |
|
| :--- | :---: | :--- | :---: |
|
||||||
| **`multi-agent-mux-create`** | `4.7.1` | 에이전트 세션 신규 생성 및 Herdr 컨테이너 격리 스폰 | ✅ 배포 |
|
| **`multi-agent-mux-create`** | `4.7.2` | 에이전트 세션 신규 생성 및 Herdr 컨테이너 격리 스폰 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-stop`** | `4.7.1` | 대화 UUID 원자적 캡처 및 세션 안전 종료 (Graceful Stop) | ✅ 배포 |
|
| **`multi-agent-mux-stop`** | `4.7.2` | 대화 UUID 원자적 캡처 및 세션 안전 종료 (Graceful Stop) | ✅ 배포 |
|
||||||
| **`multi-agent-mux-resume`** | `4.7.1` | 온디스크 대화 컨텍스트 기반 Tier-1 초고속 세션 복원 | ✅ 배포 |
|
| **`multi-agent-mux-resume`** | `4.7.2` | 온디스크 대화 컨텍스트 기반 Tier-1 초고속 세션 복원 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-status`** | `4.7.1` | 실시간 Herdr 세션 및 레지스트리 드리프트 스냅샷 조회 | ✅ 배포 |
|
| **`multi-agent-mux-status`** | `4.7.2` | 실시간 Herdr 세션 및 레지스트리 드리프트 스냅샷 조회 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-monitor`** | `4.7.1` | YAML ↔ 런타임 상태 간 자율 조정자 (Reconciler Loop) | ✅ 배포 |
|
| **`multi-agent-mux-monitor`** | `4.7.2` | YAML ↔ 런타임 상태 간 자율 조정자 (Reconciler Loop) | ✅ 배포 |
|
||||||
| **`multi-agent-mux-delegate-job`** | `4.7.1` | MQTT 이벤트 채널 기반 비동기 단위 작업 위임 | ✅ 배포 |
|
| **`multi-agent-mux-delegate-job`** | `4.7.2` | MQTT 이벤트 채널 기반 비동기 단위 작업 위임 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-loop`** | `4.7.1` | Planner-Creator-Reviewer 3자 자율 계획·실행·피어리뷰 루프 | ✅ 배포 |
|
| **`multi-agent-mux-loop`** | `4.7.2` | Planner-Creator-Reviewer 3자 자율 계획·실행·피어리뷰 루프 | ✅ 배포 |
|
||||||
| **`multi-agent-mux-orc-onboard`** | `4.7.1` | 오케스트레이터 UUID 격리 등록 및 서브 세션 오염 방지 | ✅ 배포 |
|
| **`multi-agent-mux-orc-onboard`** | `4.7.2` | 오케스트레이터 UUID 격리 등록 및 서브 세션 오염 방지 | ✅ 배포 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📋 버전별 상세 변경 내역 (Changelog)
|
## 📋 버전별 상세 변경 내역 (Changelog)
|
||||||
|
|
||||||
|
### 🚀 `v4.7.2` — Issue #23·#24 세션 생성 경로: 교차 서버 herdr 스코프, 에이전트 무관 시작 다이얼로그, 실제 에이전트가 충족하는 온보딩 전달 판정 (2026-09-23, PR #35)
|
||||||
|
|
||||||
|
> **패치 마일스톤 (PATCH Release)**: `create_session.sh` 로 새 세션을 만드는 첫 1분 안의 결함 둘을 고쳤다. 오케스트레이터 pane 이 물려주는 herdr 환경(`HERDR_WORKSPACE_ID`·`HERDR_PANE_ID`·`HERDR_TAB_ID`)이 격리 서버 조회를 오염시켜 온보딩 프롬프트가 전달되지 않고, 전달 판정이 화면 기준이라 살아 있는 에이전트를 실패로 판정한 뒤 롤백까지 실패하던 문제(#23)와, 시작 신뢰(trust) 다이얼로그를 claude 에게만 처리해 agy·grok·codex 가 준비 대기 초과로 온보딩을 건너뛰던 문제(#24)다. 옵션 하나(`--no-auto-trust`)와 종료 코드 둘(42·43)이 늘지만 잘못된 기본 동작을 고치는 수정이라 PATCH 로 올린다.
|
||||||
|
|
||||||
|
#### 🌟 주요 개선 사항
|
||||||
|
1. **시작 다이얼로그가 에이전트 무관 (#24, `lib_py/agents/base.py: startup_dialogs`, 어댑터 4종, `lib.sh: handle_startup_dialogs`)**: 모달의 시그니처·수락 키·종류(`trust`/`notice`)를 어댑터가 제공하고(`MAM_STARTUP_DIALOGS`), TUI 준비 대기 중 감지되면 수락한다. agy(Enter)·grok(`y`)·codex(`1. Yes, continue` Enter)의 신뢰 창과 codex 0.155.1 업데이트 안내(Skip)를 처리한다. 수락 판정은 다이얼로그 시그니처가 아니라 준비 토큰으로 한다(`--source visible` 이 수락된 창을 한동안 계속 보여준다). `--no-auto-trust` / `MAM_AUTO_TRUST=0` 은 신뢰 창만 사람에게 남기고 안내는 계속 처리한다(codex 의 trust 는 프로젝트 로컬 설정·훅·exec 정책을 로드한다). resume 도 create 와 같은 스위치·계약이다.
|
||||||
|
2. **교차 서버 호출의 스코프 제거 (#23, `lib.sh`)**: herdr pane 이 내보내는 세 id 는 발급한 서버에서만 뜻이 있으므로 **다른 서버를 겨냥한 호출에서만** `env -u` 로 제거한다. 호출자 서버는 `HERDR_SESSION` 이 있으면 그것, 없으면 `HERDR_SOCKET_PATH` 의 모양에서 구한다(herdr 0.8.2 는 기본 서버 pane 에 `HERDR_SESSION` 을 내보내지 않는다).
|
||||||
|
3. **온보딩 전달 판정 = 에이전트 자신의 `started` (#23, `lib.sh: delegate_publish_cmd / delegate_started_recorded / delegate_wait_started`, `create_session.sh`, delegate-job 래퍼)**: create 는 더 이상 에이전트 대신 `started` 를 발행하지 않는다. 발행 명령 빌더 하나가 create 온보딩과 래퍼에 같은 모양(dispatch_token·attempt 포함)을 주고, `started` 판정 하나를 두 대기 지점이 공유한다. 이번 dispatch 의 `started` 만 증거이며(로컬: events.log 의 dispatch_token, 원격: 구독자가 HMAC·토큰 검증 뒤 감사 기록에 남기는 `dispatch_fingerprint`(검증한 토큰의 SHA-256)+attempt), 신원 없는 과거 기록은 fail closed 다. 래퍼의 "레코드 상태만 보고 먼저 성공" 우회는 사라졌다. send_keys 의 rc 4(Enter 수락 미관측)는 경고로 낮추고 에이전트의 `started` 가 결정한다.
|
||||||
|
4. **실패 처리 (#23, `create_session.sh`)**: 롤백이 kill 결과를 확인하고 `has-session` 으로 재확인한다. 못 죽였으면 행에 `rollback-failed` 를 적고 exit 43. 온보딩이 `MAM_ONBOARD_ACK_S`(기본: 래퍼의 주입 ack 유예 → 잡의 ack timeout 180) 안에 확인되지 않아도 세션은 보존하고 잡만 error 로 표시한다(살아 있는 에이전트를 느린 온보딩 때문에 죽이지 않는다; 이미 종료된 잡은 덮어쓰지 않는다). 롤백 시 온보딩 잡은 `cancelled`, YAML 행은 `terminated`/`rollback-failed` 로 표시한다. TUI 가 준비되지 않고 프로세스도 없으면 exit 42.
|
||||||
|
5. **문서**: create/resume SKILL.md(`--no-auto-trust`, `started` 기반 판정, exit 42·43, `MAM_ONBOARD_ACK_S`, 미확인 온보딩 시 세션 보존 규칙).
|
||||||
|
|
||||||
|
#### ✅ 품질 검증
|
||||||
|
- **신규 테스트** (`tests/test_issue23_24_startup_path.py` 1,268줄, `tests/test_issue24_resume_dialogs.py`): 어댑터 다이얼로그 facts, 준비 토큰 기반 수락, `--no-auto-trust`, 교차 서버 스코프 제거(같은 서버는 유지), 공유 `started` 판정(이전 시도·신원 없는 기록 거부, 종료된 잡 보존), 롤백의 kill 확인·exit 43, 미확인 온보딩 시 세션 보존. 픽스처는 실제 `registry.py`·`publish_event.py` 를 쓴다(작성 워크스페이스 리뷰에서 손으로 만든 픽스처가 결함 3건을 가렸던 교훈). 기존 테스트 6파일 조정(G9 가드는 코드만 읽음).
|
||||||
|
- **실제 herdr 수용 시험 (작성 워크스페이스)**: 오케스트레이터 pane 의 상속 환경을 그대로 둔 채 격리 서버에 agy·grok·codex·opencode 를 순차 생성 — 4건 모두 사람 개입 없이 TUI 준비, 온보딩 전달, `started`(dispatch_token 포함) → `completed`.
|
||||||
|
- **리뷰**: 작성 워크스페이스 5인 5라운드(차단 지적 3건 — `HERDR_SESSION` 에만 의존한 교차 서버 판정, `data.dispatch_token` 을 요구했으나 실제 발행 명령엔 없던 온보딩 ack, 래퍼의 레코드 상태 우회와 신원 없는 원격 감사 기록 — 모두 해소) 전원 PASS. 병합 워크스페이스에서 PR head 를 detached 워크트리에 받아 재검토: @f4ba205 claude·agy·grok PASS; codex 는 리뷰 도중 호스트가 반복 절전(pmset 로그)에 들어가 API 스트림이 끊기는 바람에 리포트를 남기지 못했고, 대화 기록에서 복원한 탐침 2건(환경변수 `MAM_AUTO_TRUST=0` 이 스크립트의 기본값 export 에 덮여 핸들러에 1 로 도달, 쿨다운에 걸린 다이얼로그가 같은 화면의 다음 다이얼로그를 가림)을 05b0ea4 로 정정. 델타 리뷰 @05b0ea4 claude·agy·grok·codex 4인 전원 PASS(identity 4건 모두 base f4ba205 → head 05b0ea4, evidence review-tree; codex 는 두 정정을 되돌린 사본에서 새 회귀가 실패함을 역검증). 리포트와 identity 사이드카는 `.agents/reports/<session>/`.
|
||||||
|
- **전체 스위트 (병합 워크스페이스, 자체 venv 가 있는 워크트리 @f4ba205)**: 1111 통과 / 1 skip / 실패 0 (51분 21초, 리뷰 루프와 병행); 05b0ea4 에서 startup-path·resume-dialogs·TUI readiness·headless reconcile·version 스위트 123 통과.
|
||||||
|
- **별건**: 리뷰 루프가 diff 를 단일 argv 로 넘겨 Linux 의 단일 인자 상한(131,072 바이트)을 넘는 브랜치 diff 에서 `OSError: [Errno 7]` 로 죽고 rc 0 으로 끝난다(수집기 상한 `MAM_DIFF_MAX_BYTES` 기본 200000 이 더 높다). 작성 측이 별도 이슈로 등록. 비차단: 감사 기록의 새 필드(`dispatch_verified`·`dispatch_fingerprint`·`attempt_id`)가 MESSAGING.md·delegate-job SKILL.md 에 없음, `MAM_INJECT_ACK_GRACE_S` 가 create 의 대기에도 2순위로 작용한다는 점이 문서에 없음, `MAM_AUTO_TRUST` 는 `0` 만 끈다는 점과 플래그 우선 규칙이 resume SKILL.md 에 없음, codex 업데이트 안내에 `2`(이번만 건너뛰기)를 고르므로 다음 시작 때 다시 뜸(`3` 이면 다음 버전까지 조용함), 다이얼로그 시그니처는 화면의 디렉터리 경로를 검사하지 않음(pane 이 `-c $WORKSPACE` 로 뜨므로 실무 위험 낮음), `test_issue24_resume_dialogs.py` 4건이 각 ~40 s.
|
||||||
|
|
||||||
### 🚀 `v4.7.1` — Issue #25 승격된 계획서 재사용은 `--plan-file` 로만: 암묵적 자동 로드 제거, 빈 계획 리포트는 조용히 넘어가지 않음 (2026-09-22, PR #32)
|
### 🚀 `v4.7.1` — Issue #25 승격된 계획서 재사용은 `--plan-file` 로만: 암묵적 자동 로드 제거, 빈 계획 리포트는 조용히 넘어가지 않음 (2026-09-22, PR #32)
|
||||||
|
|
||||||
> **패치 마일스톤 (PATCH Release)**: `run_loop.sh` 를 `--plan` 없이 실행하면 러너가 planner 를 자동으로 고르고 `.agents/reports/<planner>/plan-*.md` 중 mtime 이 가장 최근인 파일을 "이미 수립된 계획서"로 creator 에게 넘기던 문제(Issue #25)를 고쳤다. 저장소에는 다른 이슈의 계획서가 수십 개 커밋돼 있고 체크아웃 직후의 mtime 은 의미가 없어, 무관한 계획이 구현 프롬프트에 실렸다(v4.7.0 병합 루프에서도 Issue #6 계획서가 실린 것을 관측). 옵션이 하나 늘지만 잘못된 기본 동작을 없애는 수정이라 PATCH 로 올린다.
|
> **패치 마일스톤 (PATCH Release)**: `run_loop.sh` 를 `--plan` 없이 실행하면 러너가 planner 를 자동으로 고르고 `.agents/reports/<planner>/plan-*.md` 중 mtime 이 가장 최근인 파일을 "이미 수립된 계획서"로 creator 에게 넘기던 문제(Issue #25)를 고쳤다. 저장소에는 다른 이슈의 계획서가 수십 개 커밋돼 있고 체크아웃 직후의 mtime 은 의미가 없어, 무관한 계획이 구현 프롬프트에 실렸다(v4.7.0 병합 루프에서도 Issue #6 계획서가 실린 것을 관측). 옵션이 하나 늘지만 잘못된 기본 동작을 없애는 수정이라 PATCH 로 올린다.
|
||||||
|
|||||||
Reference in new issue
Block a user