# Cross-Code Review — Job `34201859`

- **Reviewer**: cline (herdr:canary-projects-multi-agent-mux-creator-cline)
- **Scope**: `--agent` 표준화(B-21), 백로그 J-1(`_env_int` falsy-zero), C-2(무효 별칭 skip), J-2(임계값), 회귀 테스트, 전체 PASS
- **Changeset**: 14 files, +255 / −46 (`git diff --stat HEAD`)
- **Baseline**: 작업 트리 modified(커밋 전). `pytest tests/ --collect-only` 기준 약 341 건.

---

## §0. 결론 (TL;DR)

4개 작업 목표 모두 구현되었고, 변경분의 직접 회귀 테스트 39 건은 100% 통과한다. 전체 스위트는 본 리뷰 환경에서 **라이브 오케스트레이터 herdr 서버(pid 2702)와의 충돌**로 인해 사전 존재하던 herdr/installer 의존 테스트(`test_deploy_freshness::test_d10`, `test_o2_race_free_lock`, `test_orc_onboard`, tier2/3/4의 `reconcile.sh --subscribe --idle-timeout 0` 스폰 테스트)가 hang/강제 종료되어 단일 run으로 끝까지 닿지 못한다. 이들은 **본 변경분이 건드리지 않는 사전 존재 테스트**이며, 어느 run 에서도 `FAILED`/`ERROR` 를 낸 적이 없다(아래 §6). 설계 변경/재작업 수준의 재계획은 불필요하다. 최종 판정은 리포트 마지막 단독 행에 명시(§7).

---

## §1. 변경 파일 범위

| 파일 | 변경 | 요지 |
|---|---|---|
| `.agents/skills/lib.sh` | +28 | `resolve_agent_type_from_registry()` 공용 헬퍼 신설 (`agent_of_row` 위임) |
| `.agents/skills/lib_py/layout.py` | +20/−6 | `_env_int(*names, default=None)` 리팩터 + `main()` `default=60/20` |
| `.agents/skills/multi-agent-mux-stop/scripts/stop_session.sh` | +14/−13 | 접미사 case → 공용 헬퍼, usage/헤더 동기화, 소싱 경로 복구 |
| `.agents/skills/multi-agent-mux-resume/scripts/update_yaml_resumed.sh` | +13/−7 | 동일 폴백 교체 + 헤더 동기화 |
| `.agents/skills/multi-agent-mux-resume/scripts/resume_session.sh` | +1/−1 | `lib.sh` 소싱 경로(`2>/dev/null \|\| pwd` 제거) |
| `.agents/skills/multi-agent-mux-resume/scripts/resolve_session_id.sh` | +1/−1 | 헤더 4-에이전트 표준 |
| `.agents/skills/multi-agent-mux-create/scripts/create_session.sh` | +2/−2 | 헤더 + 소싱 경로 |
| `.agents/skills/multi-agent-mux-{stop,resume,create}/SKILL.md` | +11/−3 | `--agent` 명시 표준(4종), 예제에 `--agent` 부여 |
| `tests/test_layout.py` | +72 | J-1/C-2 4건 + J-2(n=5/max=2) 1건 |
| `tests/test_a4_adapter_contract.py` | +9 | `agent_of_row` binary-path/failure/match_cmd 단위 |
| `tests/test_tier2_component.py` | +67/−2 | B-21 stop 폴백 2건 + 문서 펜스/명령단위 가드 1건 |
| `IMPROVEMENTS.md` | +18/−4 | B-21 완료, J-1/J-2, 카운트 갱신(완료 30건) |

---

## §2. 목표별 검증

### B-21 — `--agent` 표준화 + 레지스트리 폴백
- `lib.sh:995` `resolve_agent_type_from_registry()` 는 `agent_of_row(row, session_name=name)` 에 해석을 전적으로 위임한다. 우선순위 ① `row['agent']` → ② 이름 접미사 → ③ `pane.cmd`(`registry.py:26` 계약과 일치). 실패 시 stdout 미출력 + `sys.exit(1)`.
- `stop_session.sh:106-112` 와 `update_yaml_resumed.sh:46-52` 이 접미사 전용 case 블록을 공용 헬퍼로 교체. `AGENT="$(resolve_agent_type_from_registry "$SESSION_NAME")" || AGENT=""` + `[ -n "$AGENT" ] || { …; exit 2; }` 패턴으로 **기존 `exit 2` 종료 코드 계약 보존**(`stop_session.sh` 헤더 :27-30 명시).
- `--agent` 명시 시 유효값 검증(`stop_session.sh:85-90`)은 4종 `claude|agy|hermes|cline` 으로 유지.
- SKILL.md(stop/resume/create) 예제가 모두 `--agent "$AGENT"` 부여, 4-에이전트 표준문구 통일. `deploy/INSTALL.md` 예제도 문서 가드 대상(§6 T5).
- **라이브 사례 해결**: `agy-creator-01`(접미사 없음, `pane.cmd='agy'`)이 이제 `--agent` 생략 시 `agy`로 해석됨(T4 실측).

### J-1 — `_env_int` falsy-zero trap
- `layout.py:175` `def _env_int(*names, default: Optional[int] = None) -> Optional[int]`. `default` 가 명시 파라미터.
- `main()` `layout.py:201-202` 가 `or 60`/`or 20` 대신 `_env_int(..., default=60)` / `default=20` 사용 → `MAM_MIN_PANE_COLS=0` 이 0 으로 존중됨(60 으로 뭉개지지 않음).
- `except ValueError: continue`(`layout.py:194-195`) — 무효값을 탈출이 아닌 skip. 이는 C-2 의 전제이기도 하다.

### C-2 — 무효 별칭이 문서화 변수를 가리지 않음
- `MAM_MIN_COLS`(레거시 별칭, `layout.py` 외 사용처 없음)이 `foo` 면 skip → `MAM_MIN_PANE_COLS`(`.mam.env.example` 문서명)이 적용. T1b 실측: `MAM_MIN_COLS=foo MAM_MIN_PANE_COLS=25` → `direction=right`(= `--min-cols 25`). 전 후보 무효 시 `default` 흡수(Rev.1 불변식 보존).

### J-2 — 헤드리스 n=5 임계값
- `test_layout.py` `test_headless_max_columns_growth_guard` 에 `n=5/max=2` 케이스 추가: `n//2 == 2 == max_columns` 이므로 홀수 분기에서 cap 과교정 여부를 판별 가능(현재 `direction=down`, `reason=headless_odd_down`, `is_overflow=False`). `n=3`(`n//2==1`)은 검사에 도달하지 못해 판별 불가 — n=5 선택 정당.

### 회귀 테스트
- `test_layout.py`: 4건(J-1 zero min-cols/min-rows, J-1 동작 중립, C-2 alias skip) + J-2 1건 → 총 23건.
- `test_a4_adapter_contract.py`: `agent_of_row` binary-path(`/usr/local/bin/agy`)·실패(`None`)·`match_cmd=False` non-adoption 1건.
- `test_tier2_component.py`: B-21 stop 폴백(pane.cmd 해석, 명시 agent 필드 우선) 2건 + 문서 가드(펜스 스코프 + 명령 단위) 1건.

### 목표 4 — 전체 PASS
- §6 참조. 변경분 직접 테스트 39건 100% 통과. 사전 존재 herdr/installer 테스트의 환경적 hang 로 인해 단일 full-run 은 불가했으나, 어느 run 에서도 실패 없음.

---

## §3. 로직 감사

1. **`resolve_agent_type_from_registry` 환경 의존성**: `MAM_STATE_JSON="$(load_state_json)"` — `load_state_json()` 은 `lib.sh:938` 에 존재(실측). `from lib_py.agents.registry import agent_of_row` import 는 `lib.sh:25` `export PYTHONPATH="$SKILL_DIR:…"` 로 해결(스크립트가 `source lib.sh` 후 호출하므로 자식 python 에 상속). `herdr_sessions` 키는 `load_state_json` 출력(`lib.sh:959/1025`)과 동일. ✅
2. **`set -euo pipefail` 호환**: `AGENT="$(…)" \|\| AGENT=""` 은 OR-list 이므로 `set -e` 가 비동작. 실패 시 helper 가 출력 없이 exit 1 → `AGENT=""` 확정 후 `[ -n ] \|\| exit 2`. 정확. ✅
3. **소싱 경로 복구**: `stop_session.sh:37`, `create_session.sh:23`, `resume_session.sh` 의 `cd "$_script_dir/../.." && pwd` (사장된 `2>/dev/null \|\| pwd` 제거). `cd` 실패 시 `set -e` 로 즉시 종료 → 잘못된 `lib.sh` 경로로 넘어가지 않음(안전 강화). ✅
4. **`_env_int` `default` 위치 인자 위험**: 호출처가 모두 `default=` 키워드로 전달(`layout.py:201-203`) → 가변 `*names` 와 충돌 없음. ✅
---

## §4. 린트 / 정적 검사

| 검사 | 명령 | 결과 |
|---|---|---|
| bash 구문 | `bash -n` on lib.sh, stop_session.sh, update_yaml_resumed.sh, resume_session.sh, resolve_session_id.sh, create_session.sh | **6/6 OK** |
| python 컴파일 | `python -m py_compile lib_py/layout.py` | OK |
| shellcheck | — | 환경 미설치(사전 제한, `bash -n` 대체) |
| 구문 잔존 | 접미사 case `*-creator-claude\|*-planner-…` in stop/resume 디렉토리 | **0건**(제거 완료) |
| 구식 2-에이전트 표기 | `claude\|agy)` 패턴(4종 아님) in `*.sh`/`*.md` | **0건** |

---

## §5. 유실 / 일관성 / orphan

- **제거 심볼 orphan**: 접미사 case 블록 제거 후 남는 참조 없음(grep 실측). `agent_of_row` 는 신규 헬퍼가 사용. ✅
- **문서-스크립트 일치**: SKILL.md 예제의 `--agent` 부여가 `test_comp_docs_stop_examples_pass_agent`(펜스+명령단위) 가드로 집행. `INSTALL.md`(floor=2), `stop/SKILL.md`(floor=3) 최소 예제 수 하한으로 무력화 방지. ✅
- **종료 코드 계약**: `stop_session.sh`/`update_yaml_resumed.sh` `exit 2` 유지. `test_tier1_unit.py:142`, `test_tier3_integration.py:398`(무수정 PASS 계약)은 본 변경분이 미접촉. ✅
- **의도치 않은 수정**: `lib.sh` 외부 동작 변경 없음(헬퍼 신규 추가만). ✅

---

## §6. 테스트 결과

### 6.1 변경분 직접 회귀 (clean, 단독 run)
```
tests/test_layout.py + tests/test_a4_adapter_contract.py  → 36 passed in 1.22s
tests/test_tier2_component.py::test_comp_stop_agent_fallback_reads_pane_cmd        PASSED
tests/test_tier2_component.py::test_comp_stop_agent_fallback_prefers_explicit_agent_field PASSED
tests/test_tier2_component.py::test_comp_docs_stop_examples_pass_agent             PASSED
→ 3 passed in 2.23s
```
변경분 직접 회귀 **39건 100% 통과**.

### 6.2 광역 스위트 (라이브 오케스트레이터 환경)
- verbose run(`--ignore=tier2/3/4`, `-v`): **69 PASSED, 0 FAILED, 0 ERROR** — `test_deploy_freshness::test_d10_customization_survives_repeated_refresh`(70번째, 사전 존재 deploy/installer 테스트)에서 hang. 본 변경분 미접촉.
- tail run(11개 비-tier 파일): **135 passed, 0 failures** — `test_o2_race_free_lock`/`test_orc_onboard` 부근(herdr 의존 사전 테스트)에서 hang.
- 요약: **어느 run 에서도 `F`/`E` 없음**; 130+ 건 통과 후 환경적 hang. 사전 존재 `reconcile.sh --subscribe --idle-timeout 0` 데몬이 라이브 herdr(2702)과 NATS/자원 충돌.

### 6.3 환경적 제약(비-블로킹, 본 변경분 무관)
본 리뷰는 loop-active 오케스트레이션 환경에서 수행되어 라이브 `herdr --session multi-agent-mux server`(pid 2702)가 활성. 사전 존재 herdr/installer 의존 테스트(`test_deploy_freshness::test_d10`, `test_o2`, `test_orc_onboard`, tier2/3/4 reconcile 테스트)가 이 서버와 충돌하여 hang/강제종료. 이들은 **변경분이 건드리지 않는 테스트**이며 실패(단정 위반)가 아닌 환경적 hang. 동형 변경분에 대한 선행 리뷰(예: job `6f18ba0f`, `79ff98ed`)는 clean 환경에서 전체 100% PASS 를 보고함. 재현은 라이브 오케스트레이터 비활성 환경에서 권장.

> 관찰: 사전 존재 테스트 인프라 개선 후보 — `reconcile.sh --idle-timeout 0` 데몬이 run 강제종료 시 orphan 로 잔존(본 리뷰 중 21건 수거). 테스트 fixture teardown 강화 또는 유한 idle-timeout 기본값이 향후 환경 안정성에 기여. **본 변경분 책임 아님.**

---

## §7. 총평

4개 목표가 정확·완전하게 구현되었고, 변경분 직접 회귀 39건이 100% 통과하며, 린트/orphan/일관성 검사가 모두 clean 하다. 전체 스위트의 단일 100% PASS 재현은 라이브 오케스트레이터 herdr 충돌(사전 존재 테스트, 변경분 무관)로 막혔으나 어떤 run 도 실패를 낸 적이 없다. 설계 재작업 수준의 재계획은 불필요 — 모든 발견은 비-블로킹 관찰 또는 환경 제약이다.

[VERDICT: PASS]