release(v4.13.0): worktree creator onboards by default; create --no-onboard warns for post-discovered-id agents (Issue #68) - archive the review reports, bump the lockstep version

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-29 16:56:48 +09:00
1 parent a7bf07bb1c
commit a582934f6a
25 files changed
+529 -28

No files matched your search

@@ -0,0 +1,14 @@
{
"loop_id": "loop-20261029T045625Z-74296d",
"base_sha": "b9c828f09214b4bed6651a223cbb941e7b432647",
"head_sha": "3b81f9973223d2a910369711c08adc772003639d",
"tree_sha": "ff705b61bf25fe40d0ff054c372a399eacc79730",
"review_commit": "3b81f9973223d2a910369711c08adc772003639d",
"reviewer": "planner-reviewer-claude-01",
"job_id": "2ab23f4e",
"verdict": "PASS",
"transport": "herdr",
"evidence": "review-tree",
"isolation": "worktree",
"verified_at": "2026-10-29T06:08:06Z"
}
@@ -0,0 +1,133 @@
# PR #79 (Issue #68) 리뷰 — head 3b81f99
리뷰어: planner-reviewer-claude-01 (claude) · job 2ab23f4e
## 0. 리뷰 경로 확인
- 검증 경로: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261029T045625Z-74296d/1`
- HEAD 는 `3b81f9973223d2a910369711c08adc772003639d`, tree 는 `ff705b61bf25fe40d0ff054c372a399eacc79730` 로 [리뷰 identity] 와 같다. 리뷰 전과 후 두 번 확인했다.
- `git status --porcelain --ignored` 결과는 비어 있고, `.mam` 도 없다.
- 리뷰 범위: base `b9c828f` 와 HEAD 사이의 커밋 5개, 9개 파일, +277/−22 줄.
- 기준 문서(읽기만 했다): `tea issues 68 --comments` 의 결정 1–4 와 완료 조건, `tea pulls 79` 설명, `INSTRUCTION.md`.
## 1. 결정·완료 조건 대조표
| 조건 | 구현(파일:줄) | 테스트 | 판정 |
|---|---|---|---|
| 결정 1: create 의 `--no-onboard` 유지, 기본은 온보딩 | `create_session.sh:67` `ONBOARD=1`, `:87-88` 그대로 | 기존 테스트 전체가 그대로 통과 | ✅ |
| 결정 2: worktree_prepare 기본을 온보딩으로 | `worktree_prepare.sh:30` `ONBOARD=1` | `test_prepare_onboards_by_default_end_to_end`(온보딩 잡 completed, "onboarding completed" 출력) | ✅ |
| 결정 2: `--no-onboard` 는 건너뛰고 create 에 그대로 넘김 | `:43`, `:232` `args+=(--no-onboard)` | `test_prepare_no_onboard_sends_none`, `test_prepare_forwards_onboarding_choice[opts2]` | ✅ |
| 결정 2: 기존 `--onboard` 도 같은 동작 | `:42` | `forwards[opts1]`, `[opts3]`(둘 다 주면 마지막 것이 이김) | ✅ |
| 결정 3: agy·codex·hermes·opencode 에만 경고, claude·grok 에는 없음 | `create_session.sh:208-211`, facts `lib_py/agents/__main__.py:75` | `test_facts_expose_post_discovered[6]`, `test_no_onboard_warning_dry_run[6]`, `..._keeps_exit_and_row[6]` | ✅ |
| 결정 3: 경고 내용 "첫 대화 전까지 ID 미기록, 같은 폴더 같은 종류는 기다림(#63)" | `:210` 의 문구가 이 두 가지와 `MAM_ID_ORDER_WAIT_S` 를 말한다 | 경고에 `Issue #63` 과 에이전트 이름이 들어 있는지 확인 | ✅ |
| 결정 3: 종료 코드·행이 바뀌지 않음 | 경고 출력만 하고 분기는 없다 | `keeps_exit_and_row`: rc 0, 행 필드(이름, status, role, server, workspace, cmd, cmd_full, cwd, id source·verified, 상태, control_plane)를 기대값과 비교 | ✅ |
| 결정 3: 뒤에서 거부돼도 경고가 먼저 보임 | spawn·#63 검사(`:287` 부근)보다 앞에서 출력 | `test_no_onboard_warning_precedes_a_later_refusal` | ✅ |
| 결정 4: 문서는 create SKILL.md 옵션 표와 worktree 절만 고침 | `SKILL.md:173`, `:205`, `:210`, `:213` 네 줄 | `test_issue42_skill_blocks`(블록 sha 와 근거 핀) | ✅ |
| 완료: "기본은 온보딩 안 함" 을 전제로 한 worktree 테스트를 고침 | `test_issue21_acceptance.py:47`, `:207`, `test_issue21_phase2_loop_a.py:422` | 모두 통과 | ✅ |
| 완료: macOS(bash 3.2, Python 3.9)에서 통과 | — | §3 | ✅ |
빠진 조건은 없다.
## 2. 꼼꼼히 본 것
### 2.1 경고 판정과 facts
- 이 Mac 에서 `lib_py.agents facts <agent>` 를 직접 실행했다.
- agy, codex, hermes, opencode 는 `MAM_ID_POST_DISCOVERED=1` 이다.
- claude, grok 은 `0` 이다.
- 값은 어댑터의 `id_lifecycle`(`base.py:174-175` 의 `PRE_ASSIGNED`/`POST_DISCOVERED`)에서 나온다. 셸 쪽에는 에이전트 목록을 두지 않았다.
- facts 를 쓰는 다른 곳에는 영향이 없다.
- `lib.sh:2596`(eval 뒤 필요한 키만 읽음), `:2957`(eval), `:3156`(`sed -n 's/^KEY=//p'` 로 키별 추출)은 모두 키 단위로 읽는다. 그래서 줄이 하나 늘어도 문제가 없다.
- facts 출력을 다루는 테스트(`test_a4_adapter_contract.py`, `test_issue23_24_startup_path.py`)도 이 Mac 에서 103 passed 였다.
- facts 를 얻지 못하는 경우(파이썬 실패 등) `eval "$(… || true)"` 는 아무 값도 정하지 않는다. 그러면 `${MAM_ID_POST_DISCOVERED:-0}` 가 0 이 되어 경고 없이 지나간다. 동작이 바뀌지 않는 쪽으로 실패하므로 안전하다.
- `MAM_DELEGATION_PY=0` 는 위임(delegation) 경로에만 쓰이는 스위치다. `lib_py.agents facts` 와는 관계가 없어 경고 판정에 영향이 없다.
- `test_issue26_ints.py:111` 은 이 값을 "문자열 비교" 로 분류해 정수 기본값 검사 대상에서 뺐다. 코드도 실제로 문자열로 비교하므로(`= 1`) 맞는 분류다.
### 2.2 `--creator-agent` 를 부르는 모든 곳 (`git grep -n creator-agent`)
- 테스트
- `test_issue21_acceptance.py:47`, `:207` 와 `test_issue21_phase2_loop_a.py:422` 에는 이제 `--no-onboard` 가 붙어 있다.
- `test_issue21_phase2_loop_a.py:339`, `test_issue50_onboard.py:192`, `test_issue57_logs_follow_registry.py:276`, `test_issue50_dispatch_herdr.py:868` 는 원래 `--onboard` 를 명시하므로 동작이 같다.
- `test_issue21_phase2_loop_a.py:355`(w6c)는 옵션이 없다. 하지만 서브모듈 초기화가 실패해 create 이전에 exit 1 로 끝나고, 행이 없음을 확인하는 테스트다. 그래서 온보딩까지 가지 않는다. 뒤에 다시 부르는 `_prepare(main, wt)` 에는 `--creator-agent` 가 없다.
- 새 테스트 파일의 세 호출은 의도한 대로다.
- 문서와 기록
- `docs/design/worktree-creator-model.md:48-51` 의 예시에는 옵션이 없다. 그래서 이제 온보딩하는데, 예시가 보여 주려는 creator 흐름에도 그게 맞다. 이 문서에는 "기본은 온보딩 안 함" 이라는 문장이 없어 고칠 내용도 없다. 결정 4 의 "최소 변경" 과도 맞는다.
- `VERSIONS.md:632` 는 과거 기록이고, `README*.md:51` 은 create 에 대한 설명이라 맞다.
- 그 밖의 스크립트에서는 `worktree_prepare.sh` 를 부르는 곳이 없다.
- 결론적으로 온보딩 대기(최대 `MAM_ONBOARD_WAIT_S`) 때문에 의도치 않게 느려지거나 44/45 로 끝날 호출은 남아 있지 않다.
### 2.3 SKILL.md 와 코드의 줄 단위 대조 (INSTRUCTION.md)
- `SKILL.md:173` 은 "`--no-onboard` 로 만든, ID 가 첫 턴 뒤에 생기는 에이전트(`id_lifecycle`)는 그때까지 ID 를 기록하지 않고, 같은 폴더의 같은 종류 create 를 막는다(#63). create 가 경고한다" 고 설명한다.
- 코드(`create_session.sh:209-210`)의 조건과 문구가 이와 같다.
- #63 쪽은 정확히는 "막는다" 가 아니라 "기다린 뒤 거부" 다. 하지만 표 한 줄 요약으로는 맞다.
- `SKILL.md:205` 의 시놉시스 `[--no-onboard]` 는 `worktree_prepare.sh:9`, `:43` 과 같다.
- `SKILL.md:210` 의 "onboards it … `--no-onboard` skips it, `--onboard` is the default and still accepted" 는 `:30`, `:42-43`, `:232` 와 같다.
- `SKILL.md:213` 의 종료 코드 "44/45 are create's (…onboarding is the default…)" 는 스크립트 머리말 `:17-19` 와 같고, create 의 44/45 정의(`create_session.sh:22-23`)와도 같다.
- 판단이 필요한 내용만 문서에 있고, 판정은 코드(adapter facts)에 있다. INSTRUCTION.md 를 따른 것이다.
### 2.4 `tests/data/skill_code_blocks.json`
- 근거 핀의 줄 번호 이동은 실제로 늘어난 줄 수와 맞는다.
- `create_session.sh` 는 경고 4줄을 `:208` 에 넣었으므로 그 뒤 근거가 모두 +4 줄 밀렸다(360→364, 518-545→522-549 등).
- `worktree_prepare.sh` 는 `--no-onboard` case 한 줄 때문에 +1 줄 밀렸다(250→251).
- 내용이 바뀐 블록은 하나다. `SKILL.md:202-206` 의 worktree 시놉시스가 `[--onboard]` 에서 `[--no-onboard]` 로 바뀌었고, 그 블록의 sha 만 `38836d31bf38` 에서 `8bfabafb0328` 로 바뀌었다.
- `test_issue42_skill_blocks.py` 가 sha 와 근거를 다시 계산해 통과했다(§3).
### 2.5 새 테스트가 결함을 잡는지
- base 대조 실행: `git archive HEAD` 를 TMPDIR 에 풀고, 코드 3개 파일(`__main__.py`, `create_session.sh`, `worktree_prepare.sh`)만 b9c828f 판으로 바꾼 뒤 `tests/test_issue68_onboard_default.py` 를 돌렸다.
- 결과는 **20 failed, 5 passed** 로, 작성자의 주장과 같다.
- 통과한 5건은 base 에서도 맞아야 하는 경우다. claude·grok 의 dry-run 과 행 시험 4건, 그리고 `--onboard` 전달 1건이다.
- 사본은 확인한 뒤 지웠다.
- Python 3.9 호환성: `str.removeprefix` 는 3.9 부터 있다. `list[str]` 주석은 `from __future__ import annotations` 덕분에 3.9 에서도 문제가 없다.
## 3. 실행한 테스트 (이 Mac: macOS, `/bin/bash` 3.2, `/usr/bin/python3` 3.9.6)
```
cd <검증 경로>
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME \
-u HERDR_SESSION -u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR -u DELEGATE_JOB_LOGS_DIR \
PYTHONDONTWRITEBYTECODE=1 /Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python \
-m pytest -p no:cacheprovider --basetemp="$TMPDIR/claude-j2ab-bt" -q -rfs \
tests/test_issue68_onboard_default.py tests/test_issue21_acceptance.py tests/test_issue21_phase2_loop_a.py \
tests/test_issue26_ints.py tests/test_issue42_skill_blocks.py tests/test_issue50_onboard.py \
tests/test_issue57_logs_follow_registry.py tests/test_issue63_same_cwd_ids.py
```
- 결과: **265 passed, 1 skipped, 0 failed** (724 s).
- skip 1건은 `test_issue42_skill_blocks.py:266` 이다. untracked `.claude/skills` 가 worktree 에 없어서 생기는 환경 문제다.
- facts 를 쓰는 다른 테스트 `tests/test_a4_adapter_contract.py`, `tests/test_issue23_24_startup_path.py` 는 **103 passed** (152 s).
- base 대조 실행(§2.5)은 `test_issue68_onboard_default.py` 기준 20 failed, 5 passed.
- `test_issue50_dispatch_herdr.py` 는 실제 herdr 서버를 띄우므로 브리프 제약에 따라 실행하지 않았다. 이 파일이 worktree_prepare 를 부르는 곳(`:868`)은 `--onboard` 를 명시하므로 이번 변경으로 동작이 바뀌지 않는다.
- 테스트가 끝난 뒤 남은 프로세스: 테스트가 띄운 `reconcile.sh`, mock herdr, 구독자는 없다. 남아 있는 것은 원래 있던 셋뿐이다.
- 본 체크아웃 모니터 3714
- 이번 루프 88445
- 이번 잡의 job_subscriber 88788 (13:56:28 시작)
## 4. 발견 사항
### 차단
- 없음.
### 비차단
- **N1.** `tests/test_issue68_onboard_default.py:17` 의 `import yaml` 은 쓰이지 않는다. PR 설명에서도 남긴 것으로 밝혔다.
- **N2.** `--no-onboard --submit-job "<프롬프트>"` 를 함께 주면, 제출한 잡이 첫 턴이 되는데도 경고가 나온다.
- 이 조합에서는 원래 온보딩 프롬프트를 만들지 않는다(`create_session.sh:440`). 그래서 `--no-onboard` 가 사실상 아무 일도 하지 않는다.
- 결정 3 의 조건("`--no-onboard` 를 주고 ID 후발견 에이전트이면")을 그대로 구현한 결과다. 그래서 결함은 아니고, 문구가 조금 지나치게 경고할 뿐이다.
- **N3.** facts 를 얻지 못했는데 호출자 환경에 `MAM_ID_POST_DISCOVERED=1` 이 export 돼 있으면, claude 에도 경고가 나올 수 있다. 현실적인 경로가 없어 참고로만 적는다.
## 5. 사용자 확인 필요
- N2: `--submit-job` 과 함께 준 `--no-onboard` 에도 경고를 낼지. 지금은 결정 3 의 문언대로 경고를 낸다.
## 6. 결론
- 결정 1–4 와 완료 조건이 모두 구현됐고 테스트로 덮였다.
- 새 테스트는 base 에서 20건이 실패하므로 결함을 실제로 잡는다.
- 바뀐 테스트 파일과 create/worktree 관련 테스트가 이 Mac 에서 모두 통과한다.
- SKILL.md 의 설명은 코드와 줄 단위로 맞는다.
[VERDICT: PASS]
@@ -0,0 +1,14 @@
{
"loop_id": "loop-20261029T045625Z-74296d",
"base_sha": "b9c828f09214b4bed6651a223cbb941e7b432647",
"head_sha": "3b81f9973223d2a910369711c08adc772003639d",
"tree_sha": "ff705b61bf25fe40d0ff054c372a399eacc79730",
"review_commit": "3b81f9973223d2a910369711c08adc772003639d",
"reviewer": "planner-reviewer-codex-01",
"job_id": "ee26d64c",
"verdict": "PASS",
"transport": "herdr",
"evidence": "review-tree",
"isolation": "worktree",
"verified_at": "2026-10-29T06:08:06Z"
}
@@ -0,0 +1,93 @@
# PR #79 / Issue #68 리뷰 — PASS
- Job: ee26d64c / Reviewer: planner-reviewer-codex-01
- 기준: `tea issues 68 --comments`의 “구현 전에 정한 것”(결정 1–4), `tea pulls 79`, `INSTRUCTION.md:5`.
- Loop: `loop-20261029T045625Z-74296d`
- Base: `b9c828f09214b4bed6651a223cbb941e7b432647`
- Head: `3b81f9973223d2a910369711c08adc772003639d`
- Tree: `ff705b61bf25fe40d0ff054c372a399eacc79730`
- 검증 루트: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261029T045625Z-74296d/1`
- 아래 파일:줄은 이 검증 루트 기준이다. 시작·종료 HEAD/tree 일치, `git status --short` 빈 출력, `git diff --check b9c828f..HEAD` 통과. creator 작업 트리에서 실행하거나 수정하지 않았다.
## 결정·완료 조건 대조
| 요구사항 | 코드·문서 근거 | 검증 | 빠진 조건 |
|---|---|---|---|
| 결정 1: create의 기본 온보딩 및 --no-onboard 유지 | `create_session.sh:67`, `:87`, `:88`, `:440` | 새 파일의 기본 dry-run 대조군·6종 실제 skip 행 검증, 기존 Issue #50 완료/44/45 테스트 | 없음 |
| 결정 2: worktree creator 기본 온보딩, skip 전달, 기존 --onboard 수용 | `worktree_prepare.sh:30`, `:42`, `:43`, `:230`, `:232` | 새 테스트 `:195`, `:215`, `:233`: 옵션 전달 4조합 및 실제 mock 온보딩 완료/잡 미생성; 외부 탐침에서 반대 순서 옵션도 확인 | 없음 |
| 결정 3: agy/codex/hermes/opencode에만 경고 1줄 | `lib_py/agents/__main__.py:75`, `create_session.sh:207`–`:211` | 새 테스트 `:50`, `:67`, `:95`: 6종 facts, dry-run/실제 create 및 기본 옵션 대조군 | 없음 |
| 경고가 종료 코드·행을 바꾸지 않음 | 변경은 facts 출력과 stderr 조건문뿐; 행 기록 분기는 그대로 | 새 테스트 `:95`에서 rc=0, 이름·역할·status·cmd·cwd·ID 출처·검증 상태·control_plane·delegate_job_id 검증. base 대조에서도 이 검증 후 경고 단언에서만 실패 | 없음 |
| 경고 이후의 거부도 기존 동작 유지 | `create_session.sh:209` 및 기존 #63 순서 게이트 | 새 테스트 `:157`: 미발견 agy 선행 세션, wait=0, rc=1 및 경고가 거부 설명보다 먼저 출력 | 없음 |
| 결정 4: 문서 변경 최소화 | create `SKILL.md:173`, `:205`, `:210`, `:213` | 옵션 표 1줄·worktree 절 3줄만 변경. 각 설명을 위 코드와 대조 | 없음 |
| 기존 implicit skip 호출 수정 및 Mac 통과 | `test_issue21_acceptance.py:47`, `:207`; `test_issue21_phase2_loop_a.py:422` | 변경 파일 5개와 관련 파일 3개 직접 실행. 아래 경로 이름 충돌 1건은 경로 보정 재실행으로 해소 | 없음 |
`create_session.sh`와 `worktree_prepare.sh`의 경로는 `.agents/skills/multi-agent-mux-create/scripts/` 아래다. 새 테스트 줄은 `tests/test_issue68_onboard_default.py` 기준이다.
## 추가 코드·호출부 확인
- 어댑터: `lib_py/agents/base.py:379`–`:382`의 기본값은 POST_DISCOVERED. claude의 `adapters/claude.py:188`–`:190`, grok의 `adapters/grok.py:18`–`:20`만 PRE_ASSIGNED로 재정의한다. 나머지 4종은 기본값을 사용한다. facts는 이 값을 0/1로 출력하므로 셸에 별도 에이전트 목록을 복제하지 않는다.
- facts 소비자는 `lib.sh:2596`(readiness eval), `:2957`(send_keys_safe eval), `:3156`(dialog facts의 이름별 sed 선택), `create_session.sh:207`이다. 새 항목은 숫자 할당문이므로 기존 eval 계약을 유지하고, 이름별 파싱에도 섞이지 않는다. 기존 facts 계약·CLI 인용 테스트 통과.
- `MAM_DELEGATION_PY=0`도 agents facts 호출을 건너뛰지 않는다. 외부 탐침에서 6종 경고 판정 및 worktree 기본 온보딩을 확인했다. facts 출력이 비거나 조회가 실패하면, 값이 미설정인 경우 `${MAM_ID_POST_DISCOVERED:-0}`에 의해 경고만 생략된다. rc=0/1의 빈 facts 탐침 모두 dry-run rc=0, nounset 오류 없음. Python 조회 불가 상황에 새 hard failure를 추가하지 않는 기존 best-effort 동작이다.
- `git grep -n worktree_prepare.sh` 및 `git grep -n -- --creator-agent`로 추적 파일을 전수 확인했다. 실행 호출은 아래 표와 같다. 숨은 자동 호출 스크립트는 없다.
| 호출 위치 | 바뀐 기본값의 영향 |
|---|---|
| `test_issue21_acceptance.py:47,207`, `test_issue21_phase2_loop_a.py:422` | 온보딩과 무관한 기존 검증이므로 명시적 --no-onboard 추가가 맞음 |
| `test_issue21_phase2_loop_a.py:339` | 이미 --onboard이며 실제 mock 완료를 검증 |
| `test_issue21_phase2_loop_a.py:355` | submodule 초기화 거부가 creator 단계보다 앞서 발생; 온보딩 대기 없음 |
| `test_issue50_onboard.py:192` | 기존 --onboard + stub의 44/45 전달 검증 유지 |
| `test_issue50_dispatch_herdr.py:868` | 이미 --onboard를 명시한 실제 herdr 통합 테스트. 이번 제약에 따라 실행하지 않음 |
| `test_issue57_logs_follow_registry.py:276` | 기존 --onboard 및 mock 완료. 이번 Mac 실행 통과 |
| 새 테스트 `:202,219,237` | 전달·기본 온보딩·skip를 의도적으로 각각 검증 |
| create `SKILL.md:205`, `docs/design/worktree-creator-model.md:48`–`:52` | 사용자 실행 예시는 이제 기본 온보딩을 수행. SKILL의 `:213`이 44/45 및 세션·worktree 보존을 명시 |
| README/README.ko의 `:51`, VERSIONS의 역사 기록, `lib_py/worktree.py:3` | 설명/주석이며 추가 실행 호출 없음 |
- `tests/data/skill_code_blocks.json`: 변경된 evidence/passthrough 9곳을 base와 HEAD의 실제 줄 내용으로 비교해 모두 동일함을 확인했다. 변경된 비핀 필드는 worktree 사용 예시의 sha 1개(`38836d31bf38 → 8bfabafb0328`)뿐이며 --onboard → --no-onboard에 해당한다. inventory 테스트 통과.
- 새 테스트는 단순 문자열 존재 검사에 그치지 않고 옵션 전달, 실제 mock 잡의 completed 상태, skip 시 잡 미생성, 행의 안정 필드, 후속 거부를 확인한다. 아래 base 대조 결과도 예상과 일치했다.
## Mac 실행 및 결과
환경: Darwin arm64, `bash`는 `/bin/bash` 3.2.57, `/usr/bin/python3` 및 사용한 제어 루트 venv Python은 3.9.6. 검증 트리에는 venv가 없어 브리프 상단에 지정된 제어 루트 인터프리터를 사용했다. 모든 pytest 실행 cwd는 검증 루트이며 공통 접두부는 다음과 같다.
```bash
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID \
-u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME -u HERDR_SESSION \
-u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR \
-u DELEGATE_JOB_LOGS_DIR -u AGENT_SESSIONS_YAML \
PYTHONDONTWRITEBYTECODE=1 \
/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python \
-m pytest -p no:cacheprovider --basetemp=<아래의 TMPDIR 경로> -q <선택 항목>
```
TMPDIR 접두부는 `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/`이다.
| 실행 | 선택 항목·추가 옵션 | 결과·증거 |
|---|---|---|
| 주 실행, basetemp `mam-review-ee26d64c-main` | `tests/test_issue68_onboard_default.py tests/test_issue21_acceptance.py tests/test_issue21_phase2_loop_a.py tests/test_issue26_ints.py tests/test_issue42_skill_blocks.py tests/test_issue50_onboard.py tests/test_uuid_target.py tests/test_issue21_worktree_prereqs.py` | 265 passed, 1 failed, 1 skipped / 819.55s. [main.log](evidence/main.log) |
| 위 실패 사례 재실행, basetemp `mam-eval-ee26d64c-a4` | `tests/test_issue21_acceptance.py::test_a4_main_checkout_is_unchanged_by_the_whole_cycle` | 1 passed / 2.04s. [a4.log](evidence/a4.log) |
| 계약/create 회귀, basetemp `mam-review-ee26d64c-contract` | `tests/test_a4_adapter_contract.py::test_agent_adapter_registry ::test_facts_bridge_eval_contract ::test_cli_bridge_subcommands_and_quote_safety`(각각 전체 node 경로 사용), `tests/test_tier2_component.py`, `tests/test_issue57_logs_follow_registry.py::test_worktree_prepare_keeps_the_logs_next_to_the_control_root_registry`; `-k 'create or facts_bridge or agent_adapter_registry or cli_bridge'` | 16 passed, 30 deselected / 184.63s. 마지막 logs 노드는 이 필터에서 제외되어 아래 별도 실행. [contract.log](evidence/contract.log) |
| logs 별도 실행, basetemp `mam-eval-ee26d64c-logs` | `tests/test_issue57_logs_follow_registry.py::test_worktree_prepare_keeps_the_logs_next_to_the_control_root_registry` | 1 passed / 18.13s. [logs.log](evidence/logs.log) |
| 외부 탐침, basetemp `mam-review-ee26d64c-probes` | `tests/test_issue68_onboard_default.py -s -p probe_issue68`; 추가 env `PYTHONPATH=/tmp/mam-review-ee26d64c-harness` | 12 passed / 41.84s. legacy 6종 경고+기본 온보딩 1건, 빈 facts 2건, 마지막 skip 옵션 1건, 기본 44/45 전달 2건. [probes.log](evidence/probes.log), [probe_issue68.py](evidence/probe_issue68.py) |
| base 대조, basetemp `mam-eval-ee26d64c-base` | 같은 새 테스트 파일에 `-p base_issue68`; 같은 추가 PYTHONPATH | 의도한 20 failed, 5 passed / 77.25s. [base.log](evidence/base.log), [base_issue68.py](evidence/base_issue68.py) |
주 실행 실패는 `tests/test_issue21_acceptance.py:142`의 “worktree list 어디에도 mam-review 문자열이 없어야 한다”는 기존 단언 때문이다. 이 검토의 basetemp 이름 자체에 그 문자열이 들어갔다. 바로 앞의 HEAD·branch·status·branch tip·worktree list 원상복구 단언은 통과했다. 소스나 단언을 바꾸지 않고 basetemp 이름만 `mam-eval-ee26d64c-a4`로 바꾼 재실행이 통과했으므로 제품 회귀로 판정하지 않는다. 새 테스트 25건은 주 실행에서 모두 통과했다.
skip 1건은 `test_issue42_skill_blocks.py:266`: 검증 worktree에 추적되지 않는 `.claude/skills` 링크가 없는 경우다. 해당 링크의 합성 layout 테스트들은 실행됐다. 주 실행의 경로 보정까지 반영하면 제품 검증은 266건 통과·1건 skip이며, 추가 회귀/탐침 29건도 통과했다. 중복 확인한 A3 단독 실행은 별도 총계에 넣지 않았다.
base 대조는 다른 checkout에서 실행한 것이 아니다. HEAD의 새 테스트와 fixtures를 그대로 두고, `git show b9c828f:<path>`로 얻은 제품 파일 3개(create, worktree_prepare, agents CLI)만 임시 샌드박스에 넣었다. 직접 facts를 조회하는 6건은 base CLI를 임시 스크립트로 실행했고, 어댑터는 변경 없는 검증 트리 것을 사용했다. 실패 구성은 facts 6 + dry-run 경고 4 + 실제 행 검증 후 경고 4 + 후속 거부 경고 1 + 전달 3 + 기본 완료 1 + skip 1이다. 통과 5건은 claude/grok 경고 없음 각 2건과 기존 --onboard 전달 1건이다.
추가 정적 검사: 변경 셸 2개 `/bin/bash -n` 통과, 변경 Python 5개 `ast.parse(..., feature_version=(3,9))` 통과, diff 공백 검사 통과. ShellCheck는 설치되어 있지 않아 실행하지 않았다. 전체 스위트는 실행하지 않았다.
## 발견 사항
- **차단: 없음.**
- **비차단(P3):** `tests/test_issue68_onboard_default.py:17`의 `import yaml`은 사용되지 않는다. 해당 1줄을 제거하면 된다. 동작성·데이터 유실 문제는 아니며 판정을 막지 않는다.
- 위 A4 경로 문자열 단언의 민감성은 이번 diff에 도입되지 않았다. 이 리뷰에서는 경로 보정으로 검증을 완료했으며 PR 범위 확대를 요구하지 않는다.
## 격리·잔존 확인 및 사용자 확인 필요
모든 create/worktree 동작은 테스트의 mock herdr와 임시 작업 공간에서만 실행했다. 실제 에이전트 홈 DB를 열거나 실제 opencode 서비스·herdr 서버를 사용하지 않았다. 실제 .mam.env를 읽어 출력하거나 export하지 않았다. 테스트 종료 후 이번 실행의 임시 경로를 가진 프로세스는 0개이고, 실제 제어 루트 모니터는 시작·종료 모두 PID 3714다([process-audit.json](evidence/process-audit.json)). 패턴 kill, pkill, killall 및 실제 모니터에 대한 신호는 사용하지 않았다. 제품 소스·브랜치·이슈/PR 상태를 수정하거나 push/merge하지 않았다. 제어 평면 쓰기는 승인된 잡 이벤트와 이 리포트·증거뿐이다.
사용자 확인 필요: 없음. 결정 변경이나 재설계가 필요하지 않다.
[VERDICT: PASS]
@@ -0,0 +1,14 @@
{
"loop_id": "loop-20261029T045625Z-74296d",
"base_sha": "b9c828f09214b4bed6651a223cbb941e7b432647",
"head_sha": "3b81f9973223d2a910369711c08adc772003639d",
"tree_sha": "ff705b61bf25fe40d0ff054c372a399eacc79730",
"review_commit": "3b81f9973223d2a910369711c08adc772003639d",
"reviewer": "reviewer-agy-01",
"job_id": "ace63ec3",
"verdict": "PASS",
"transport": "herdr",
"evidence": "review-tree",
"isolation": "worktree",
"verified_at": "2026-10-29T06:08:06Z"
}
@@ -0,0 +1,121 @@
# Code Review Report — PR #79 (Issue #68: `worktree_prepare.sh` Default Creator Onboarding & `create --no-onboard` Warning)
- **Job ID**: `ace63ec3`
- **Reviewer**: `agy` (`herdr:reviewer-agy-01`)
- **Loop ID**: `loop-20261029T045625Z-74296d` (Round 1)
- **Review Snapshot Path**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261029T045625Z-74296d/1`
- **Branch**: `fix/issue-68`
- **Base Commit**: `b9c828f09214b4bed6651a223cbb941e7b432647`
- **Head Commit**: `3b81f9973223d2a910369711c08adc772003639d` (5 commits)
- **Tree Hash**: `ff705b61bf25fe40d0ff054c372a399eacc79730`
---
## 1. 확인한 것 (Files & Line Ranges Inspected in Review Snapshot)
- **기준 문서 대조 (`INSTRUCTION.md`, `tea issues 68 --comments`, `tea pulls 79`)**:
- `INSTRUCTION.md:1-13` (스크립트·테스트 우선 원칙 및 `SKILL.md`와 코드의 줄 단위 일치 원칙 확인)
- Issue #68 댓글("구현 전에 정한 것", 결정 1–4 및 완료 조건)과 PR #79 설명 대조
- **어댑터 `id_lifecycle` 및 `facts` 브리지**:
- `.agents/skills/lib_py/agents/__main__.py:4, 75` (`from lib_py.agents.base import POST_DISCOVERED`, `MAM_ID_POST_DISCOVERED={1 if adapter.id_lifecycle == POST_DISCOVERED else 0}`)
- `.agents/skills/lib_py/agents/base.py:174-175, 379` (기본값 `POST_DISCOVERED`: `agy`, `codex`, `hermes`, `opencode`)
- `.agents/skills/lib_py/agents/adapters/claude.py:188`, `grok.py:18` (`PRE_ASSIGNED`: `claude`, `grok`)
- 다른 `lib_py.agents facts` 호출 지점 영향 확인:
- `.agents/skills/lib.sh:2596-2598` (`wait_for_tui_ready` `eval "$_facts"`)
- `.agents/skills/lib.sh:2957` (`send_keys_safe` `eval ...`)
- `.agents/skills/lib.sh:3156-3170` (`_mam_load_dialog_facts` — `sed -n`으로 특정 키만 추출)
- `tests/test_issue23_24_startup_path.py:480-500` (`MAM_STARTUP_DIALOGS=` 행만 필터링)
- 모든 기존 호출자가 새 `MAM_ID_POST_DISCOVERED` 키 추가에 전혀 영향받지 않음을 확인.
- **`create_session.sh` 및 `worktree_prepare.sh` 구현·문서 대조**:
- `.agents/skills/multi-agent-mux-create/scripts/create_session.sh:67, 88, 207-211`:
- `ONBOARD=1` 기본 유지, `--no-onboard` 유지.
- `eval "$("$(_delegate_py_bin)" -m lib_py.agents facts "$AGENT" 2>/dev/null || true)"` 직후 `if [ "$ONBOARD" = 0 ] && [ "${MAM_ID_POST_DISCOVERED:-0}" = 1 ]; then`으로 stderr 경고 1줄 출력(`create_session.sh:209-211`).
- `facts` 호출이 실패하거나 빈 값일 때도 `${MAM_ID_POST_DISCOVERED:-0}` 기본값 `0`으로 `set -u` 아래 안전하게 통과.
- `spawn` 및 `--dry-run` 분기(`219`)보다 앞에 위치하여 `--dry-run`이나 이후 `#63` 대기 거부(`225`) 시에도 경고가 먼저 출력되며, 종료 코드와 레지스트리 행은 전혀 바꾸지 않음.
- `.agents/skills/multi-agent-mux-create/scripts/worktree_prepare.sh:6-19, 30, 42-43, 231-232`:
- `ONBOARD=1`로 기본값 변경(`30`), `--onboard`는 `ONBOARD=1`로 계속 허용(`42`), `--no-onboard`는 `ONBOARD=0` 설정(`43`), `create_session.sh`에 `--onboard` 또는 `--no-onboard` 전달(`232`).
- 상단 주석(`6-19`, `usage()`가 `sed -n '2,15p'`로 출력하는 범위 포함)이 코드와 정확히 일치.
- `.agents/skills/multi-agent-mux-create/SKILL.md:173, 202-214`:
- 옵션 표(`173`)와 `worktree_prepare.sh` 시놉시스(`205`), `--creator-agent` 설명(`210`), 종료 코드 설명(`213`)을 줄 단위로 코드와 대조하여 일치 확인.
- **저장소 전체 `--creator-agent` 호출 전수 조사 (`git grep -- "--creator-agent"`)**:
- `tests/test_issue21_acceptance.py:47, 207`: `--no-onboard` 명시 추가됨.
- `tests/test_issue21_phase2_loop_a.py:339`: 기존 `--onboard` 명시.
- `tests/test_issue21_phase2_loop_a.py:355`: 서브모듈 초기화 실패(단계 4) 테스트로 creator 단계(단계 5)에 도달하지 않음.
- `tests/test_issue21_phase2_loop_a.py:422`: `--no-onboard` 명시 추가됨.
- `tests/test_issue50_dispatch_herdr.py:868`, `tests/test_issue50_onboard.py:192`, `tests/test_issue57_logs_follow_registry.py:276`: 모두 기존 `--onboard` 명시.
- `docs/design/worktree-creator-model.md:50`: 실제 워크트리 creator 생성 예시로 기본 온보딩 의도와 부합.
- **핀 이동 및 정수 환경변수 분류**:
- `tests/data/skill_code_blocks.json`: `create_session.sh` 208행 이후 참조들이 정확히 `+4`행, `worktree_prepare.sh` 43행 이후 참조가 `+1`행(`250`→`251`), `SKILL.md:202-206` 블록 해시가 `8bfabafb0328`로 내용 그대로 이동됨을 확인.
- `tests/test_issue26_ints.py:111`: `NOT_ARITHMETIC`에 `"MAM_ID_POST_DISCOVERED"` 등록 확인.
- **신규 테스트 (`tests/test_issue68_onboard_default.py:1-247`) 검증**:
- 총 25개 케이스: `test_facts_expose_post_discovered`(6), `test_no_onboard_warning_dry_run`(6), `test_no_onboard_warning_keeps_exit_and_row`(6), `test_no_onboard_warning_precedes_a_later_refusal`(1), `test_prepare_forwards_onboarding_choice`(4), `test_prepare_onboards_by_default_end_to_end`(1), `test_prepare_no_onboard_sends_none`(1).
- base `b9c828f` 기준 대조 결과: `claude`·`grok` 경고 없음 4건(`dry_run` 2 + `keeps_exit_and_row` 2)과 `--onboard` 전달 1건을 제외한 **20건이 base에서 정확히 실패**함을 코드로 확인(작성자 주장 일치).
---
## 2. 결정 1–4 및 완료 조건 대조표
| 항목 | 요구사항 요약 | 구현 위치 | 테스트 커버리지 | 상태 |
|---|---|---|---|---|
| 결정 1 | `create_session.sh`의 `--no-onboard` 유지, 기본값 온보딩(`ONBOARD=1`) 유지 | `create_session.sh:67, 88` | `test_no_onboard_warning_dry_run`, `test_no_onboard_warning_keeps_exit_and_row` | 충족 |
| 결정 2 | `worktree_prepare.sh --creator-agent` 기본을 온보딩(`ONBOARD=1`)으로 변경, `--no-onboard` 추가 및 전달, 기존 `--onboard`도 동일 동작으로 수용 | `worktree_prepare.sh:30, 42-43, 232` | `test_prepare_forwards_onboarding_choice`, `test_prepare_onboards_by_default_end_to_end`, `test_prepare_no_onboard_sends_none` | 충족 |
| 결정 3 | `create --no-onboard` 시 후발견 ID 에이전트(`agy`·`codex`·`hermes`·`opencode`)에만 `#63` 대기 가능성 경고 1줄 출력, `claude`·`grok`에는 미출력, 종료 코드·레지스트리 행 불변 | `lib_py/agents/__main__.py:75`, `create_session.sh:207-211` | `test_facts_expose_post_discovered`, `test_no_onboard_warning_dry_run`, `test_no_onboard_warning_keeps_exit_and_row`, `test_no_onboard_warning_precedes_a_later_refusal` | 충족 |
| 결정 4 | `multi-agent-mux-create/SKILL.md` 옵션 표와 worktree 준비 절의 기본값 설명만 최소 수정 | `multi-agent-mux-create/SKILL.md:173, 205, 210, 213` | `tests/test_issue42_skill_blocks.py` | 충족 |
| 완료 조건 3 | 기존 worktree 테스트 중 기본 미온보딩을 전제하던 호출 수정 및 macOS 통과 | `test_issue21_acceptance.py:47, 207`, `test_issue21_phase2_loop_a.py:422`, `test_issue26_ints.py:111` | 아래 macOS 실측 265 passed | 충족 |
빠진 완료 조건: **없음**.
---
## 3. 실행한 테스트와 결과 (macOS 실측)
검증 경로(`/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261029T045625Z-74296d/1`)에서 브리프의 격리 실행 명령으로 바뀐 테스트 파일과 create/worktree 관련 테스트를 모두 실행했습니다.
### 명령 1 (`test_issue68_onboard_default.py`, `test_issue26_ints.py`, `test_issue42_skill_blocks.py`, `test_issue50_onboard.py`)
```bash
BT="$(mktemp -d "${TMPDIR:-/tmp}/mam-rev-ace63ec3-1.XXXXXX")"
trap 'rm -rf "$BT"' EXIT
cd /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261029T045625Z-74296d/1 && \
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME -u HERDR_SESSION -u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR -u DELEGATE_JOB_LOGS_DIR \
PYTHONDONTWRITEBYTECODE=1 /Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python -m pytest -p no:cacheprovider --basetemp="$BT/pytest" \
tests/test_issue68_onboard_default.py \
tests/test_issue26_ints.py \
tests/test_issue42_skill_blocks.py \
tests/test_issue50_onboard.py
```
- **결과**: `177 passed, 1 skipped in 245.18s (0:04:05)` (exit code `0`)
### 명령 2 (`test_issue21_acceptance.py`, `test_issue21_phase2_loop_a.py`, `test_issue57_logs_follow_registry.py`, `test_issue63_same_cwd_ids.py`)
```bash
BT="$(mktemp -d "${TMPDIR:-/tmp}/mam-rev-ace63ec3-2.XXXXXX")"
trap 'rm -rf "$BT"' EXIT
cd /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261029T045625Z-74296d/1 && \
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME -u HERDR_SESSION -u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR -u DELEGATE_JOB_LOGS_DIR \
PYTHONDONTWRITEBYTECODE=1 /Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python -m pytest -p no:cacheprovider --basetemp="$BT/pytest" \
tests/test_issue21_acceptance.py \
tests/test_issue21_phase2_loop_a.py \
tests/test_issue57_logs_follow_registry.py \
tests/test_issue63_same_cwd_ids.py
```
- **결과**: `88 passed in 485.68s (0:08:05)` (exit code `0`)
### 명령 3 (`/bin/bash -n` 구문 검사 및 프로세스·워크트리 무결성 확인)
- `create_session.sh`, `worktree_prepare.sh` `/bin/bash -n` 통과 (`exit 0`).
- `git status --short`: 출력 없음 (검증 스냅샷 깨끗함).
- `ps -ef`: 본 체크아웃의 기존 `reconcile.sh --subscribe` 데몬(PID `3714`)만 정상 유지 중이며, 테스트가 남긴 자식·더미 프로세스 없음.
---
## 4. 발견 사항 (차단 / 비차단)
- **차단 (Blocking)**: 없음.
- **비차단 (Non-Blocking)**:
- `[N-1]` `tests/test_issue68_onboard_default.py:18`: 쓰이지 않는 `import yaml` 1줄이 남아 있습니다(PR #79 본문에서도 인지됨, 동작에 영향 없음).
---
## 5. 사용자 확인 필요
- 없음.
[VERDICT: PASS]
@@ -0,0 +1,14 @@
{
"loop_id": "loop-20261029T045625Z-74296d",
"base_sha": "b9c828f09214b4bed6651a223cbb941e7b432647",
"head_sha": "3b81f9973223d2a910369711c08adc772003639d",
"tree_sha": "ff705b61bf25fe40d0ff054c372a399eacc79730",
"review_commit": "3b81f9973223d2a910369711c08adc772003639d",
"reviewer": "reviewer-grok-01",
"job_id": "8900db9e",
"verdict": "PASS",
"transport": "herdr",
"evidence": "review-tree",
"isolation": "worktree",
"verified_at": "2026-10-29T06:08:06Z"
}
@@ -0,0 +1,78 @@
# PR #79 (Issue #68) 리뷰
검증 경로는 `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261029T045625Z-74296d/1` 뿐이다. HEAD `3b81f9973223d2a910369711c08adc772003639d`, tree `ff705b61bf25fe40d0ff054c372a399eacc79730`, base `b9c828f09214b4bed6651a223cbb941e7b432647` 는 조상이다. 작업 트리는 깨끗하고 `git diff --check` 도 깨끗하다. 변경은 9파일, +277/−22 이다. 스냅샷에는 `.venv` 가 없다. 테스트는 제어 평면 Python 3.9.6 과 `/bin/bash` 3.2.57 로 돌렸다.
## 확인한 것
결정 1–4 는 코드와 같다.
| 완료 조건 | 구현 | 테스트 |
|---|---|---|
| create 의 `--no-onboard` 유지, 기본은 onboarding | `create_session.sh:51` 도움말, `:67` `ONBOARD=1` | dry-run 기본 경로는 경고 0줄 (`test_issue68_onboard_default.py:84-91`) |
| `worktree_prepare.sh --creator-agent` 는 기본 onboarding. `--no-onboard` 는 create 로 넘기고, `--onboard` 는 같은 뜻 | `:30` `ONBOARD=1`, `:42-43` 마지막 플래그가 이김, `:232` 둘 중 하나만 전달. 44/45 는 `:247-248`, `exit "$rc"` 는 `:251` | 전달 4건, 기본 e2e 1건, `--no-onboard` 면 잡 없음 1건 |
| 경고는 agy·codex·hermes·opencode 만. claude·grok 는 없다. 종료 코드와 행은 그대로 | `:208-210`. 판정은 facts 의 `MAM_ID_POST_DISCOVERED` | dry-run 6, 실제 행 6, 이후 거절 1 |
| 문서 변경은 create SKILL.md 옵션 표와 worktree 절 | `SKILL.md:173`, `:205`, `:210`, `:213` | `tests/test_issue42_skill_blocks.py` 핀이 현재 본문과 일치 (아래 1건 스킵) |
경고 판정은 셸의 에이전트 목록이 아니다. `__main__.py:75` 가 `adapter.id_lifecycle == POST_DISCOVERED` 이면 `MAM_ID_POST_DISCOVERED=1`, 아니면 `0` 을 찍는다. 기본값은 `base.py:379-382` 의 `post_discovered` 이고, `claude.py:188-190` 과 `grok.py:18-20` 만 `pre_assigned` 다. 기대표(`test_issue68_onboard_default.py:30-37`)와 같다.
facts 를 통째로 eval 하는 `lib.sh:2957` 은 토큰 변수만 읽고, `_mam_load_dialog_facts` (`lib.sh:3157`) 는 `MAM_STARTUP_DIALOGS` 줄만 꺼낸다. 추가 대입 한 줄은 그 두 경로의 결과를 바꾸지 않는다. `MAM_DELEGATION_PY=0` 은 `lib.sh:2323` 근처의 레거시 헬퍼 스위치이고, create 의 facts 호출(`create_session.sh:207`)은 그 스위치 밖에 있다. facts 가 실패하면 `|| true` 로 변수가 비고, `${MAM_ID_POST_DISCOVERED:-0}` 이라 경고는 나오지 않는다.
경고는 spawn 전이다. `--dry-run` 종료는 `create_session.sh:286` 이고, `#63` 대기는 `:291` 이다. 그래서 dry-run 에도 경고가 나오고, 이후 거절보다 경고가 먼저다.
`--creator-agent` 호출:
- `tests/test_issue21_acceptance.py:47`, `:207` 과 `tests/test_issue21_phase2_loop_a.py:422` 는 `--no-onboard` 를 넘긴다. `:339` 는 원래 `--onboard` 다.
- `test_w6c` (`test_issue21_phase2_loop_a.py:355`) 는 플래그가 없다. 서브모듈 초기화가 `:356` 에서 실패하고 `:360` 에서 행이 비어, creator 까지 가지 않는다.
- `tests/test_issue50_onboard.py:192` 와 `tests/test_issue57_logs_follow_registry.py:276` 은 `--onboard` 다.
- `tests/test_issue50_dispatch_herdr.py:868` 은 `--onboard` 이고 실제 herdr 를 띄운다. 이번 리뷰에서는 실행하지 않았다.
- 다른 스크립트가 `worktree_prepare.sh` 를 호출하지는 않는다. `docs/design/worktree-creator-model.md:50` 의 claude 예시는 플래그가 없어서 이제 기본 onboarding 이다. `README.md:51` 은 `--onboard` 와 준비 스크립트만 언급한다. `VERSIONS.md` 는 당시 기록이다.
`tests/data/skill_code_blocks.json` 의 create 핀은 경고 4줄이 들어간 뒤쪽 범위가 +4 다 (`360`→`364`, `518-545`→`522-549`, `259-274`→`263-278`, `490-608`→`494-612`, exit 4 핀 `550`→`554`). worktree 의 `exit "$rc"` 핀은 옵션 한 줄 때문에 `250`→`251` 이고, `:24` 는 그대로다. sha `38836d31bf38`→`8bfabafb0328` 은 줄 이동이 아니라 SKILL 예시가 `--no-onboard` 로 바뀐 것이다 (`skill_code_blocks.json:90-102`, `SKILL.md:202-206`). 핀 테스트는 그 본문과 맞춰 통과했다.
새 테스트 25건을 base 에 올려 놓지 않고 단정만 세면, facts 6건, dry-run 경고 4건, 행 검사의 경고 단계 4건(`:150-152`. 행 단정은 그 앞에 있어 base 는 경고에서 실패), 거절 1건, 전달 4건 중 명시적 `--onboard` 를 뺀 3건, 기본 e2e 1건, `--no-onboard` 준비 1건이 실패한다. 20실패·5통과로 작성자 주장과 같다. 통과하는 5건은 claude·grok 의 경고 없음(dry-run 과 행) 4건과 명시적 `--onboard` 전달 1건이다.
## 실행한 테스트와 결과
스냅샷에 `.venv` 가 없어 제어 평면 인터프리터를 썼다. cwd 는 스냅샷, basetemp 는 `/tmp/mam-i68-8900db9e` 이다.
```
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME -u HERDR_SESSION -u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR -u DELEGATE_JOB_LOGS_DIR \
PYTHONDONTWRITEBYTECODE=1 \
/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python -m pytest \
-p no:cacheprovider --basetemp=/tmp/mam-i68-8900db9e \
tests/test_issue68_onboard_default.py \
tests/test_issue21_acceptance.py \
tests/test_issue21_phase2_loop_a.py \
tests/test_issue26_ints.py \
tests/test_issue42_skill_blocks.py \
tests/test_issue50_onboard.py \
tests/test_issue57_logs_follow_registry.py \
-q --tb=line
```
결과: `238 passed, 1 skipped, 1 error in 497.36s (0:08:17)`, 프로세스 종료 코드 1. 제품 단정이 실패한 테스트는 없다. `test_issue26_ints.py` 는 `MAM_ID_POST_DISCOVERED` 를 문자열 비교로 분류한다 (`:111`).
스킵 1건은 quiet 로그가 노드 이름을 찍지 않는다. 스냅샷에 `.claude/skills` 가 없고, 그 조건의 스킵은 `tests/test_issue42_skill_blocks.py:263-266` `test_claude_skills_link_resolves_to_agents_skills` 이다.
세션 종료 오류는 `tests/test_issue57_logs_follow_registry.py::test_a_symlinked_registry_dir_resolves_to_one_audit_log` 에 붙어 있고, 본문 단정이 아니다. `conftest.py:1581` 의 `agent_home_leak_guard` 가 세션 동안 생긴 agy 홈 항목 10개(brain 디렉터리 5, conversation db 5)를 보고했다. 가드는 이름을 읽고 지우지 않는다 (`conftest.py:1586-1592`). claude 만 예외이고 그 외 디렉터리는 예외가 없다 (`tests/_agent_home_guard.py:106`).
그 10개 항목의 mtime 은 pytest 구간(로그 생성 1793252159, 종료 1793252657, 약 14:36–14:44) 안이다. 다섯 db 를 연 프로세스는 pid 83251, `agy --hub`, 시작 13:50:53, 부모는 Antigravity IDE 헬퍼(82581)이다. pytest 자식이 아니다. 이번 테스트의 agy 경로는 `mock_agents` 이다. 파일은 열거나 지우지 않았고 그 자리에 두었다. 이 오류는 동작 중인 agy 가 자기 홈에 새 대화를 쓴 경우이고, 제품 결함으로 보지 않는다.
테스트 뒤 pytest 프로세스와 mock herdr, 추가 `reconcile.sh` 는 없었다. 체크아웃 모니터 pid 3714 (`reconcile.sh --subscribe --idle-timeout 0`, 부모 1) 는 그대로다. 신호를 보내지 않았다. `tests/test_issue50_dispatch_herdr.py` 는 실제 herdr 를 띄우므로 돌리지 않았다. 전체 스위트와 `test_issue34_job_tree.py` 도 돌리지 않았다.
## 발견 사항
차단: 없다.
비차단:
- `tests/test_issue68_onboard_default.py:17` 의 `import yaml` 는 쓰이지 않는다. 같은 파일의 `agent_sessions_yaml` 은 딕셔너리 키이다.
- `SKILL.md:173` 은 같은 폴더의 같은 종류 create 가 막힌다고 쓰고, `create_session.sh:210` 은 그 생성이 기다린다고 쓴다 (`Issue #63`, `MAM_ID_ORDER_WAIT_S`). 종료 코드와 경고 조건은 스크립트와 결정이 같다.
- 전달 테스트는 `[]`, `--onboard`, `--no-onboard`, `--no-onboard --onboard` 네 가지다 (`:186-193`). `--onboard --no-onboard` 순서는 같은 while 루프(`worktree_prepare.sh:31-43`)라 마지막이 이기고, 파라미터에는 없다.
- 위의 세션 가드 오류. 재현하려면 동작 중인 agy 를 끄거나, 그 홈을 가드 범위 밖으로 두어야 한다. 제품 수정 대상은 아니다.
## 사용자 확인 필요
없다. 본문의 `--no-onboard` 삭제 제안은 2026-10-28 결정으로 대체됐고, 구현은 그 결정(플래그 유지, worktree 기본 onboarding, 네 에이전트 경고, 문서 최소 변경)을 따른다.
[VERDICT: PASS]