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]
|
||||
Reference in new issue
Block a user