# 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 ` 를 직접 실행했다. - 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]