Files
multi-agent-mux/.agents/reports/canary-projects-multi-agent-mux-creator-claude/plan-e691297c.md
T

18 KiB

리뷰 및 보완 구현 계획서 Rev.2 — A-1 / A-5 / .mam.env

Job: 4dbf4feb | Role: Planner | 작성일: 2026-08-05 대체 대상: Rev.1 (e691297c) — 본 문서가 우선한다 반영 피드백: Creator agy Challenge Report 3daf49ab 리뷰 대상 코드: 68eff79..8dcb2b2 + 미커밋 워킹트리 1건 (변동 없음)

Rev.1의 §1~§11은 아래에서 명시적으로 수정하지 않은 한 그대로 유효하다. 본 문서는 R-3 / F4 하나를 재설계하고, 그 과정에서 발견한 결함 1건을 추가한다.


0. 이의제기 판정

agy의 주장을 넷으로 분해해 각각 실행으로 검증했다.

# agy의 주장 판정 근거
1 derive_session_nameagent_type을 요구하는데 resolve_herdr_session에는 그 정보가 없어 폴백 로직이 붕괴한다 반증(사유), 인정(증상) 슬러그는 agent 인자 유무와 무관하게 동일하다(E-A). 붕괴하는 진짜 원인은 정보 부재가 아니라 set -u 하의 인자 개수이며, ${2:-} 한 글자로 해소된다
2 herdr 세션명은 워크스페이스 수준이어야 하고, create의 sed 's/-creator-.*//'가 그 증거다 인정 옳다. 전용 헬퍼를 두는 형태(shape)는 채택한다
3 대안 — derive_workspace_slug 신설 후 양쪽에서 직접 호출 구현 기각 제시된 구현이 create_session.sh4개 경로 전수 불일치(E-B). F4가 없애려던 이중 규칙을 세 번째 규칙으로 되살린다
4 그 헬퍼를 resolve_herdr_session 폴백에서 derive_workspace_slug "$WORKSPACE"로 호출 설계 기각 resolve_herdr_session 스코프에는 $WORKSPACE없다(E-C). ${1:-$PWD} 기본값이 오늘의 cwd 의존을 그대로 물려받아, 같은 세션명이 호출 위치마다 다른 herdr 세션으로 해석된다(E-D)

요약: agy옳은 형태를 틀린 이유로, 틀린 구현과 함께 제안했다. 헬퍼 도입은 채택한다. 다만 규칙을 새로 쓰는 대신 기존 규칙을 추출해야 하고, 빠진 파라미터는 $AGENT가 아니라 $WORKSPACE다 — agy는 자신이 진단한 결여를 자기 처방에서 그대로 반복했다.


1. 신규 측정 증거

E-A — agent 인자는 슬러그에 아무 영향이 없다

$ derive_session_name "$WS" claude | sed 's/-creator-.*//'   ->  [parent-dir-my-project]
$ derive_session_name "$WS"        | sed 's/-creator-.*//'   ->  [parent-dir-my-project]
$ derive_session_name "$WS" ""     | sed 's/-creator-.*//'   ->  [parent-dir-my-project]

derive_session_nameprintf '%s-creator-%s' "$slug" "$agent"로 끝난다. 슬러그는 workspace 경로만으로 계산되고 agent는 접미사에만 쓰인다. sed가 그 접미사를 잘라내므로 agent가 비어 있어도 결과가 같다. 따라서 "에이전트 타입 정보 부재로 폴백이 붕괴한다"는 인과는 성립하지 않는다.

다만 붕괴 자체는 실재한다 — 원인이 다르다.

$ set -u; derive_session_name "$WS"
  ABORT: .agents/skills/lib.sh: line 595: $2: unbound variable

그리고 resolve_herdr_session을 호출하는 스크립트는 8개 전부 set -euo pipefail이다:

create_session.sh  run_loop.sh  resume_session.sh  reconcile.sh
resolve_session_id.sh  update_yaml_resumed.sh  status.sh  stop_session.sh

즉 실제 위험은 셸 엄격 모드에서의 인자 개수이고, local agent="${2:-}" 로 끝난다. agy의 결론(직접 호출하지 말라)은 방어 가능하나, 제시한 이유는 틀렸고 그 이유를 근거로 설계를 바꾸면 엉뚱한 곳을 고치게 된다.

E-B — agy가 제시한 구현은 4개 경로 전수 불일치

챌린지 리포트의 함수를 원문 그대로 옮겨 create_session.sh의 실제 산출물과 대조했다.

  workspace                create_session.sh writes      agy derive_workspace_slug
  parent_dir/my_project    mam-parent-dir-my-project      mam-parentdir-myproject      ** MISMATCH **
  Upper_Case/Web_App       mam-upper-case-web-app         mam-uppercase-webapp         ** MISMATCH **
  /tmp                     mam-workspace-tmp              mam--tmp                     ** MISMATCH **
  /                        mam-workspace-root             mam--                        ** MISMATCH **

원인 두 가지:

  1. 밑줄 처리가 반대다. derive_session_nametr '_' '-'변환하는데, agy의 구현은 tr -cd 'a-z0-9-'삭제한다. my_projectmy-project가 아니라 myproject가 된다.
  2. 경계 가드가 없다. derive_session_name은 부모가 /·.·빈 문자열일 때 workspace를, 작업 디렉터리가 그럴 때 root를 대입하고 선행 하이픈을 제거한다. agy의 구현에는 이 가드가 전부 없어 /tmp에서 mam--tmp, 루트에서 mam--라는 사실상 이름이 아닌 문자열을 만든다.

R-3은 "규칙이 두 개라 서로 다르다"는 결함이다. 이 처방은 세 번째 규칙을 추가해 세 개로 만든다. 고치려던 문제를 악화시킨다.

E-C — 폴백에 없는 파라미터는 $AGENT가 아니라 $WORKSPACE

lib.sh:555  resolve_herdr_session() {
lib.sh:556    local session_name="$1"
              # 인자는 세션명 하나. workspace도 agent도 없다.

agy의 제안 derive_workspace_slug "$WORKSPACE"는 이 스코프에서 정의되지 않은 변수를 쓴다. 그래서 그들의 헬퍼는 local ws="${1:-$PWD}"로 조용히 $PWD를 대신 쓴다 — 그 순간 자신이 지적한 "정보 결여"를 그대로 재현한다.

호출자별 workspace 보유 현황(실측):

  create_session.sh        has --workspace   L190 resolve_herdr_workspace "$SESSION_NAME"
  resume_session.sh        has --workspace   L47  resolve_herdr_session   "$SESSION_NAME"
  update_yaml_resumed.sh   has --workspace   L40  resolve_herdr_session   "$SESSION_NAME"
  stop_session.sh          no  --workspace   L85  resolve_herdr_workspace "$SESSION_NAME"

4곳 중 3곳은 workspace를 이미 갖고 있으면서 넘기지 않고 있다. stop_session.sh만 없는데, 그조차 L117에서 TARGET_CWD를 읽으므로 순서만 바꾸면 확보된다.

E-D — cwd 폴백은 같은 세션명을 호출 위치마다 다르게 해석한다

미등록 세션명 하나를 세 디렉터리에서 조회했다.

  cwd=/Users/…/canary_projects/multi-agent-mux   -> mam-multi-agent-mux
  cwd=/tmp                                        -> mam-tmp
  cwd=/…/scratchpad                               -> mam-scratchpad

동일 입력, 세 가지 답이다. 그리고 첫 줄은 R-3을 라이브로 재확인해 준다 — 이 워크스페이스에서 create가 만드는 이름은 mam-canary-projects-multi-agent-mux인데 폴백은 mam-multi-agent-mux를 낸다.

agy${1:-$PWD}는 이 동작을 그대로 보존한다.


2. 신규 결함

ID 결함 증거 등급
R-12 resolve_herdr_session의 폴백이 호출자의 cwd를 워크스페이스로 추측한다. 같은 세션명이 호출 위치에 따라 다른 herdr 세션으로 해석되어, stop/resume이 생성된 적 없는 세션을 대상으로 삼는다. R-3(규칙 두 개)보다 근본적이다 — 규칙을 통일해도 입력이 틀리면 결과는 여전히 틀리다 E-D, E-C 높음

Rev.1 대비 총계: 12건 (치명 3, 높음 4, 중간 5).


3. 재설계 — R-3 / F4

3.1 설계 원칙

agy의 형태를 채택하되 두 가지를 바꾼다.

  1. 규칙을 새로 쓰지 않고 추출한다. derive_workspace_slugderive_session_name의 정규화 블록을 그대로 옮긴 것이어야 하고, derive_session_name은 그 헬퍼를 호출해 접미사만 붙이도록 재작성한다. 그래야 규칙이 물리적으로 하나가 된다. 두 함수가 "같은 규칙을 따르기로 합의"하는 구조는 R-3이 이미 실패를 증명했다.
  2. 추측하지 않고 전달받는다. resolve_herdr_session에 선택적 두 번째 인자 [workspace]를 추가하고, workspace를 아는 호출자는 반드시 넘긴다. 모를 때는 cwd로 추측하지 않고 default를 반환하며 stderr에 경고한다. 틀린 세션을 조용히 가리키는 것보다 default가 안전하다 — 최소한 관측 가능하다.

3.2 추출안 검증

제안한 추출 구현을 실제로 작성해 5개 경로에서 대조했다.

  parent_dir/my_project     create=parent-dir-my-project      extracted=parent-dir-my-project      MATCH
  Upper_Case/Web_App        create=upper-case-web-app         extracted=upper-case-web-app         MATCH
  /tmp                      create=workspace-tmp              extracted=workspace-tmp              MATCH
  /                         create=workspace-root             extracted=workspace-root             MATCH
  canary_projects/multi-…   create=canary-projects-multi-…    extracted=canary-projects-multi-…    MATCH

  derive_session_name       : parent-dir-my-project-creator-claude
  derive_workspace_slug+sfx : parent-dir-my-project-creator-claude

5/5 일치, 그리고 derive_session_namederive_workspace_slug + -creator-<agent>로 정확히 분해된다. 이 형태면 create_session.shsed도 사라진다 — agy가 지적한 냄새의 근본 제거다.

3.3 set -u 대응

derive_session_namelocal agent="$2"local agent="${2:-}"로 바꾼다(E-A). 추출 후에도 이 함수는 남으므로(호출자 다수) 방어는 필요하다. agy가 감지한 증상에 대한 정확한 크기의 수정이다.

3.4 채택하지 않은 것

  • tr -cd 'a-z0-9-' 방식 — 밑줄을 삭제해 기존 이름과 어긋난다(E-B).
  • ${1:-$PWD} 기본값 — cwd 추측을 영속화한다(E-D). 명시 전달 또는 default.
  • derive_session_name을 그대로 호출하고 sed로 자르는 방식(Rev.1 F4 원안) — 동작은 하지만(E-A) 문자열 조작이 남고 set -u 지뢰를 유지한다. agy의 §2 지적이 이 부분에서는 맞다.

4. Rev.1 대비 변경

항목 Rev.1 Rev.2
F4 resolve_herdr_session 폴백이 derive_session_name 재사용 F4a/F4b/F4c로 분할. 추출 헬퍼 + workspace 파라미터 + cwd 추측 제거
결함 수 11건 12건 (R-12 추가)
차단 항목 BK-A, BK-B BK-A, BK-B, BK-C
V-6 두 슬러그가 같은 문자열을 낸다 유지 + V-11~V-15 추가

5. 수정된 커밋 계획 (변경분만)

Rev.1의 F1·F2·F3·F5~F9는 그대로다. F4만 분할한다.

# 커밋 내용 선행
F4a refactor(lib): extract derive_workspace_slug as the single naming rule derive_session_name의 정규화 블록을 헬퍼로 추출하고, derive_session_name은 그 헬퍼 + 접미사로 재작성. local agent="${2:-}" 방어 포함. 동작 변화 0 — 순수 리팩터 F2
F4b feat(lib): let callers pass the workspace to resolve_herdr_session 선택적 2번째 인자 추가. 폴백이 derive_workspace_slug "$ws" 사용. create/resume/update_yaml_resumed가 보유 중인 workspace 전달. stop_session.shTARGET_CWD 조회를 L85 앞으로 옮겨 전달 F4a
F4c fix(lib): stop guessing the workspace from the caller's cwd R-12. workspace 미지정 시 default 반환 + stderr 경고 1회. F4b와 같은 커밋에 넣지 않는다 — 전달 경로가 먼저 완성되어야 이 변경이 안전하다 F4b

create_session.sh:153derive_session_name … | sed 's/-creator-.*//'도 F4a에서 derive_workspace_slug "$WORKSPACE"로 교체한다.

순서 근거

  • F4a는 순수 리팩터여야 한다. 동작 변경과 섞으면 5/5 일치(§3.2)를 회귀로 검증할 수 없다.
  • F4a → F4b: 헬퍼가 없으면 전달할 대상이 없다.
  • F4b → F4c(BK-C): 전달 경로가 완성되기 전에 cwd 추측을 없애면, 아직 workspace를 넘기지 않는 호출자가 전부 default로 떨어져 stop이 세션을 못 찾는다 — R-1과 정확히 같은 고아 pane 증상을 새로 만든다.
  • F4 계열 전체는 F2 이후다. rename이 끝나기 전에 이름 규칙을 건드리면 어느 층에서 깨졌는지 분간할 수 없다.

6. 추가 테스트

Rev.1 V-1~V-10은 유효하다(V-6은 아래 V-11로 강화).

ID 검증
V-11 derive_workspace_slugcreate_session.sh의 실제 산출물이 5개 경로 전수 일치: 밑줄, 대문자, /tmp, /, 실제 저장소. §3.2 매트릭스를 회귀로 고정
V-12 derive_session_name "$WS" "$agent" == derive_workspace_slug "$WS" + -creator-$agent (분해 항등식)
V-13 set -u 하에서 derive_session_name "$WS"중단되지 않는다 — F4a 이전 반드시 실패 (E-A 재현)
V-14 동일 세션명을 서로 다른 cwd 3곳에서 조회해도 같은 결과를 낸다 — F4c 이전 반드시 실패 (E-D 재현)
V-15 workspace 미지정 시 default + stderr 경고. cwd 기반 추측 문자열이 나오지 않는다
V-16 grep -rn "sed 's/-creator" .agents/skills 결과 0 (문자열 조작 제거 확인)

신규 6건. V-13·V-14는 수정 전 반드시 실패해야 한다. V-11은 agy의 구현이 통과하지 못하는 테스트이며(E-B 4/4 불일치), 어떤 구현이든 이 테스트를 먼저 세우면 규칙이 셋으로 늘어나는 것을 막는다.


7. 추가 DoD 게이트

Rev.1 게이트 A~G에 더한다.

게이트 조건
H F4a 커밋의 diff가 동작 변경 0임을 V-11/V-12로 입증 (리팩터 순수성)
I grep -rn 'basename' .agents/skills/lib.sh .agents/skills/*/scripts 결과에 워크스페이스 슬러그를 만드는 두 번째 구현이 없다
J F4c 이후 resolve_herdr_session이 workspace 없이 호출되는 지점이 0 (있다면 그 호출자가 default를 받아도 무해함을 명시)

8. 추가 리스크

ID 리스크 완화
RK-F F4c가 workspace를 넘기지 않는 잔여 호출자를 default로 떨어뜨려 R-1과 같은 고아 pane을 유발 BK-C 순서 + 게이트 J + V-15. F4b에서 전 호출자 전달을 완료한 뒤에만 F4c 착수
RK-G F4a 리팩터가 미묘하게 이름을 바꿔 기존에 만들어진 herdr 세션과 어긋난다 V-11의 5경로 전수 대조를 F4a 이전에 먼저 작성해 현재 값을 스냅샷으로 고정. 리팩터는 그 스냅샷을 깨지 않아야 함

9. 차단 항목 (갱신)

BK-A, BK-B는 Rev.1과 동일하다. 하나 추가한다.

BK-C — cwd 추측 제거(F4c)는 workspace 전달 완료(F4b) 이후에만. 순서를 뒤집으면 아직 workspace를 넘기지 않는 호출자가 전부 default를 받아 살아있는 세션을 찾지 못한다. 이는 Rev.1 R-1이 만든 고아 pane과 동일한 증상을 새 경로로 재생산하는 것이다. 두 커밋을 합치는 것도 금지한다 — 합치면 F4b의 전달 경로가 올바른지 독립적으로 검증할 수 없다.

차단 항목은 BK-A, BK-B, BK-C 3건이다.


10. agy에 대한 평가

이번 이의제기는 Rev.1 F4의 실질적 약점을 짚었다. derive_session_name을 직접 호출하고 sed로 접미사를 깎아내는 방식은 확실히 나쁜 형태이고, 전용 워크스페이스 슬러그 헬퍼가 옳다는 §2 지적은 그대로 채택했다. create_session.shsed를 쓰는 이유를 개념적 불일치의 증거로 읽은 것도 정확한 독해다.

동시에 검증이 빠진 부분도 분명하다.

  • 핵심 논거인 "agent 정보 부재로 폴백 붕괴"는 한 번 실행해 보면 반증된다(E-A). 슬러그는 agent와 무관하다. 실제 붕괴 원인은 set -u 인자 개수이며, 이를 오진한 탓에 처방이 필요 이상으로 커졌다.
  • 제시한 구현은 자기 목적을 달성하지 못한다. 4개 경로 전수 불일치이고(E-B), 특히 밑줄을 삭제해 my_project → myproject를 만든다 — R-3이 지적한 바로 그 종류의 불일치를 새로 만든다.
  • 가장 아쉬운 점은 자기가 진단한 결여를 자기 처방에서 반복했다는 것이다. derive_workspace_slug "$WORKSPACE"$WORKSPACE는 그 스코프에 없고, 헬퍼의 ${1:-$PWD}가 그 사실을 조용히 덮는다(E-C). 빠진 파라미터는 $AGENT가 아니라 $WORKSPACE였고, 그것을 끝까지 따라갔다면 R-12에 스스로 도달했을 것이다.

결과적으로 이 라운드에서 R-12가 발굴되었고, F4의 형태가 개선되었다. 그 두 가지는 이의제기가 없었다면 나오지 않았다.


11. Planner 경계

본 문서는 설계·리뷰 산출물이며 저장소 코드는 한 줄도 수정하지 않았다. 모든 프로브(agy 제안 함수의 원문 재현, 추출안 프로토타입, cwd 3분기 대조)는 /tmp 하위 임시 디렉터리에서만 실행했고 종료 시 제거했다. 라이브 herdr 세션에는 이번 라운드에서 접근하지 않았다.

워킹트리의 M .agents/skills/lib.sh여전히 미커밋 상태이며 리뷰 대상이다 (Rev.1 R-6 / BK-A — 변동 없음). *.tmp 잔재는 이번 job 시작 시점에도 또 관측되었다 (…31385_22852.tmp4회 연속 재발, Rev.1 B-6).

MULTI_AGENT_RULES.md §1에 따라 구현은 Creator, 커밋은 GM 소관이다.

차단 항목은 BK-A, BK-B, BK-C 3건이며, F1 커밋이 여전히 모든 작업의 선행 조건이다.

[AGREEMENT: REACHED]