Files
multi-agent-mux/.agents/reports/canary-projects-multi-agent-mux-creator-claude/report-dcbdf349.md
T
Godopu f7e1513585 refactor: standardize --agent option usage, improve YAML registry fallback, and fix layout falsy-zero trap (J-1)
- In stop_session.sh and update_yaml_resumed.sh: standardize explicit --agent option and use resolve_agent_type_from_registry to read agent type from YAML/DB state rather than brittle suffix-only regex inference.
- Update multi-agent-mux-stop/SKILL.md, multi-agent-mux-resume/SKILL.md, multi-agent-mux-create/SKILL.md, and deploy/INSTALL.md to standardize passing --agent explicitly.
- Fix J-1 in layout.py: refactor _env_int(*names, default=None) to take an explicit default parameter, eliminating the falsy-zero trap so MAM_MIN_PANE_COLS=0 is respected.
- Add regression and contract tests: test_j1_env_zero_min_cols_matches_flag_zero, test_j1_env_zero_min_rows_matches_flag_zero, test_comp_stop_agent_fallback_*, test_comp_docs_stop_examples_pass_agent.
- Verified 100% UNANIMOUS PASS from Planner claude and Reviewers claude and cline.
2026-08-24 10:08:27 +09:00

10 KiB
Raw Blame History

🔍 교차 코드 리뷰 — Job dcbdf349

  • 역할: Reviewer
  • 대상: Rev.2 계획서(d6f54b7f) 구현분 — 워킹 트리 수정 14파일 (+255 / 46)
  • 기준 커밋: 14e306b / 미추적 파일 0건

1. 결론

계획서 Rev.2 의 8개 작업항목(S1~S8)이 전부 사양대로 구현됐습니다. 전체 스위트 341 passed / 425.16s / exit 0 으로 계획이 예측한 수치와 정확히 일치하고, 뮤테이션 10종 전부 지정 테스트를 FAIL 시킵니다.

차단 사유 없음. P3 관찰 3건만 기록합니다.


2. 검증 결과 요약

검증 결과
전체 스위트 341 passed, 425.16s, exit 0 (계획 예측 341 과 일치)
배포 신선도 단독 31 passed (기존 유지)
bash -n 6개 스크립트 6/6 OK
py_compile (시스템 Python 3.9.6) OK
수집 수 333 → 341 (신설 8건)
test_layout.py 19 → 23 (IMPROVEMENTS.md 기재치와 일치)
보호 대상 2파일 무수정 test_tier1_unit.py / test_tier3_integration.pygit diff --stat 출력 0줄
뮤테이션 10/10 검출

3. 뮤테이션 매트릭스 — 10/10 검출

격리 rsync 사본에서 실행. 무뮤테이션 대조군은 대상 7건 전건 통과(7 passed in 2.73s).

# 뮤테이션 결과
M1 stop_session.sh 폴백을 옛 case 블록으로 복원 …reads_pane_cmd FAILED
M2 헬퍼에서 row 폐기 (agent_of_row({}, …)) 2건 모두 FAILED
M3 헬퍼에 match_cmd=False …reads_pane_cmd FAILED / …prefers_explicit_agent_field PASSED
M4 default=60… or 60 test_j1_env_zero_min_cols… FAILED
M5 except ValueError: continuereturn None 2건 모두 FAILED
M5b continuereturn default (Rev.1 안으로 복귀) test_j1b… FAILED / …malformed_env_behaviour_unchanged PASSED
M6 헤드리스 홀수 분기에도 상한 검사 추가 test_headless_max_columns_growth_guard FAILED
M7 SKILL.md 예제 1곳에서 --agent 삭제 문서 가드 FAILED
M7b INSTALL.md 두 호출 중 하나만 --agent 삭제 문서 가드 FAILED
M7c SKILL.md 워크플로 예제 1개 통째 삭제 문서 가드 FAILED

값어치 있는 세 가지

M3 이 정확히 하나만 깬다. 두 T4 테스트가 서로 다른 성질을 잡는다는 것이 실증됐습니다. …reads_pane_cmd 하나만 있었다면 pane.cmd 를 직접 긁는 얕은 구현도 통과했을 것이고, …prefers_explicit_agent_field 가 그 구현을 배제합니다.

M5 와 M5b 가 서로 다른 테스트를 깬다. C-2 반영의 검증 조건이 그대로 성립했습니다 — M5(None 복귀)는 크래시 경로를, M5b(Rev.1 안 복귀)는 별칭 섀도잉을 각각 잡습니다. 둘 중 하나라도 잡히지 않았다면 T1b 는 장식이었을 것입니다.

M7b / M7c 가 서로 다른 사유로 깨진다. 문서 가드의 두 독립 기제가 각각 살아 있다는 뜻입니다.

[M7b] AssertionError: INSTALL.md: stop_session.sh example without --agent:   ← 커맨드 단위 검사
[M7c] AssertionError: SKILL.md: expected >= 3 examples, saw 2                ← 문서별 개수 하한

M7b 는 Rev.1 원안(블록 단위)이 놓쳤던 바로 그 케이스입니다. 챌린저 9f85218e 의 지적이 실물 가드에서 값어치를 증명했습니다.


4. 동작 실측

4.1 핵심 결함 — 라이브 세션 해석

agy-creator-01                                     -> agy
canary-projects-multi-agent-mux-creator-cline      -> cline
bad-session-name                                   -> <none rc=1>

--agent 없이 exit 2 로 거부되던 실제 running 세션 agy-creator-01pane.cmd 로 해석됩니다. 동시에 bad-session-name 은 rc=1 로 실패해 호출자의 exit 2 계약이 유지됩니다.

계약 테스트 직접 확인: test_stop_session_invalid_agent_suffix PASSED (무수정 상태). 계획 §3 안 B 의 "기존 테스트를 한 줄도 안 고치고 결함만 제거" 라는 수용 조건이 충족됐습니다.

4.2 J-1 / C-2

MAM_MIN_PANE_COLS=0             : {"direction": "right",    "reason": "single_pane_height_constrained"}
--min-cols 0                    : {"direction": "right",    "reason": "single_pane_height_constrained"}   ← 동치
MAM_MIN_COLS=foo +PANE_COLS=25  : {"direction": "right",    "reason": "single_pane_height_constrained"}   ← C-2
MAM_MIN_COLS=foo +PANE_COLS=bar : {"direction": "overflow", "reason": "single_pane_overflow"}             ← 불변식 보존
baseline                        : {"direction": "overflow", "reason": "single_pane_overflow"}

3행이 C-2 수정(무효 별칭이 문서화된 변수를 가리지 않음), 4행이 Rev.1 불변식 보존(모든 후보 무효 → 문서화된 기본값)입니다. 두 성질이 한 구현에 공존합니다.

4.3 실패 경로 — set -euo pipefail 하 안전성

PYTHONPATH 를 파손시킨 상태에서:

rc-guarded, AGENT=[]  (빈 값이면 호출자가 exit 2 로 처리)
stderr 첫 줄: Traceback (most recent call last):

AGENT="$(...)" || AGENT=""set -e 조기 종료를 막고, 계획대로 stderr 를 억제하지 않아 traceback 이 보입니다. 진짜 오류와 정상 해석 실패가 구분됩니다. 명시 --agent bogus 검증도 그대로입니다(invalid agent type 'bogus').

4.4 S8 소싱 경로 복구 — 실효 확인

계획이 "드롭 가능한 별도 커밋" 으로 분리했던 항목이라, 실제 효과가 있는지 되돌려 봤습니다.

[되돌린 사본]  / 에서 WORKSPACE_ROOT 없이 실행
  → stop_session.sh: line 39: //.agents/skills/lib.sh: No such file or directory

[현행]         / 에서 WORKSPACE_ROOT 없이 실행
  → Usage: ... --session <name> [--agent claude|agy|hermes|cline] ...

장식이 아니라 실제 장애를 닫습니다. cd성공할 때 빈 문자열이 되던 결함이라 1차 소싱 경로가 100% 죽어 있었고, 이제 살아났습니다.


5. 관찰 사항 (P3 — 전부 비차단)

🟡 O-1: S8 소싱 복구에 회귀 가드가 없다

되돌린 사본에 tier1+tier2+tier3 전체를 돌린 결과 78 passed — 아무 테스트도 잡지 못합니다. 모든 테스트가 WORKSPACE_ROOT 를 설정하거나 저장소 루트에서 실행되므로 :36 폴백이 항상 성공하기 때문입니다.

계획이 M8(update_yaml_resumed.sh 폴백 무가드)을 정직하게 남긴 것과 같은 성격입니다. 다만 S8 은 도달 불가 경로가 아니라 실측된 실동작 결함(§4.4)을 고친 것이므로 M8 보다 가드 부재의 무게가 큽니다. 처방은 한 줄입니다 — 저장소 밖 cwd + WORKSPACE_ROOT 미설정으로 --help 를 실행해 rc=0 을 단언.

차단하지 않는 이유: 변경 자체가 순수 개선이고(되돌리면 명백히 실패), 계획이 이 커밋을 분리 가능하도록 설계했으며, 가드 부재가 다른 어떤 것도 가리지 않습니다.

🟡 O-2: create/SKILL.md 스니펫이 자기모순 상태가 됐다

  agy)
    herdr new-session ... "agy --dangerously-skip-permissions"
    ;;
  *) echo "ERROR: --agent must be claude, agy, hermes or cline, got: $AGENT"; exit 2 ;;

오류 메시지는 4종을 허용한다고 광고하는데 case arm 은 claude/agy 둘뿐입니다. 스니펫을 그대로 따라 --agent hermes 를 주면 *) 로 떨어져 "hermes 는 허용된다" 는 메시지를 내며 죽습니다. 변경 전에는 메시지와 구현이 (둘 다 2종으로) 일치했으므로, 이 한 스니펫의 내부 정합성은 오히려 나빠졌습니다.

실물 create_session.sh:187agy|hermes|cline) 로 4종을 정상 처리하므로 생산 코드에는 결함이 없습니다. 계획 §4.4 는 이 지점에 대해 "스니펫을 축약하고 실물을 가리키게 하는 쪽을 권장" 했고 Creator 는 메시지 수정 쪽을 골랐는데, 그 선택이 계획이 축약을 권한 이유를 그대로 드러냈습니다. agy)agy|hermes|cline) 한 글자 수정이면 정합해집니다.

🟡 O-3: update_yaml_resumed.sh:45 주석의 라인 참조가 남의 것

# 종전과 동일하게 exit 2 (헤더 :27-30 의 종료 코드 계약 유지).

:27-30stop_session.sh 의 종료 코드 헤더 위치입니다. update_yaml_resumed.sh:27-30 은 인자 파서이고, 이 파일에는 종료 코드 계약 헤더 자체가 없습니다. 두 스크립트에 같은 블록을 심으면서 따라온 복사 흔적입니다. 동작 무영향.


6. 계획 대비 이행 점검

항목 이행
S1 resolve_agent_type_from_registry() 계획 코드 그대로. 이름 분리(run_loop 동명 함수 섀도잉 회피) 반영
S2 stop_session.sh :101 위치 유지, 메시지·종료 코드 불변, 헤더/usage() 갱신
S3 update_yaml_resumed.sh 동일 블록 + 4종 표기
S4 문서 동기화 SKILL.md 3종 + 스크립트 헤더 2종
S5 J-1 + C-2 default= 인자화 + continue, docstring 이 두 결정 근거를 모두 기술
S6 테스트 8건 + J-2 보강 341 collected
S7 IMPROVEMENTS.md B-21 절 신설, 완료 29→30, 테스트 수 19→23 갱신
S8 소싱 복구 3곳 (가드 없음 — O-1)
범위 준수 run_loop.sh·reconcile.sh 무수정 (K-1/K-4 유지)

usage() 에 4개 에이전트명이 모두 남아야 하는 제약(test_comp_stop_usage_matches_parser)도 유지됐고, FEATURE 3 주석 개수(4→7)와 import re 추가라는 사전 조건 2건도 반영됐습니다.


7. 총평

계획 Rev.2 는 챌린지 라운드를 거치며 문서 가드가 두 번 재설계됐는데, 그 결과가 M7b 에서 값어치를 증명했습니다 — Rev.1 설계였다면 통과했을 회귀를 현행 가드가 잡습니다. C-2 도 M5/M5b 가 서로 다른 테스트를 깨면서 "행동 변경이지만 기존 불변식은 보존" 이라는 주장이 실증됐습니다.

남은 3건은 전부 P3 이고 어느 것도 결함을 가리지 않습니다. O-2 는 문서 스니펫 한 글자, O-3 은 주석 한 줄, O-1 은 가드 신설 권고입니다. 다음 커밋에 함께 정리하면 충분합니다.

[VERDICT: PASS]