Merge-workspace review loop (--all-reviewer): round 1 (@8241bd5) claude grok PASS, agy NOT PASS (two static wrapper-literal tests did not follow _decided/_exit_for), codex NOT PASS (R1: a yes/no decision that could not run read as "no"); fixed in541c3feand65b78b6. Round 2 (@65b78b6) 4/4 PASS. Full suite at65b78b6on macOS / Python 3.9 / herdr 0.9.3: 1730 passed / 0 failed / 56 skipped; 18 of the skips were the uninitialized nats-docker submodule in the fresh worktree, and with it tests/test_deploy_freshness.py is 31 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
44 lines
8.0 KiB
Markdown
44 lines
8.0 KiB
Markdown
# 리뷰 리포트 — Job 4566e690 (Issue #17 후속, fix/issue17-followups 56d0bfd..8241bd5)
|
|
|
|
- 리뷰어: planner-reviewer-claude-01 (claude)
|
|
- 리뷰 identity: loop-20261007T224638Z-cf1efb / base 56d0bfd / head 8241bd5 / tree efef640 — 검증 경로에서 `git rev-parse HEAD 'HEAD^{tree}'` 일치, 미커밋 변경 없음
|
|
- 커밋 6개: 25c9970·f19f940(항목 1), a670ef5(항목 2), d6cb019(항목 3), c90a0af(항목 4), 8241bd5(테스트 환경 고정). 버전·VERSIONS.md 변경 없음(브리프대로).
|
|
|
|
## 결론 요약
|
|
항목 1~4 가 요구대로 반영됐고, 정상 경로의 종료 코드·출력·레지스트리·이벤트는 변하지 않았다. 추가 테스트 13건은 수정 전 코드에서 실제로 실패한다(255·127·2 등 예측된 코드로). 항목 1 에는 브리프 문구("테스트 전제 수정")를 넘는 **제품 코드 변경**(herdr_restore.py 의 placeholder 닫기)이 포함되는데, 실제 herdr 0.9.3 에서 그 변경 없이는 테스트도 resume 의 닫기도 성립하지 않음을 확인했으므로 정당한 범위 확장으로 판단한다(§1). 차단 결함 없음. 비차단 관찰 3건(§6).
|
|
|
|
## 1. 항목 1 — herdr 0.9.3 과 test_b
|
|
- 브리프의 전제 "닫기 동작은 cwd 를 보지 않는다 → :275 만 두 경로 허용" 은 불완전했다. herdr 0.9.3 은 디렉터리가 사라진 pane 을 **프로세스 없는 placeholder**(`restore_error` 설정)로 복원하고 `pane process-info` 는 `pane_not_found` 로 rc 1 을 낸다. 실제 서버 대조: 스크래치 사본에 **이전 herdr_restore.py** 만 넣고 test_b 를 돌리면 `close-restored-shells: Command […'pane','process-info','--pane','w2:p1'] returned non-zero exit status 1` 로 실패(1 failed, 11.8 s) — 즉 옛 코드는 Y 의 placeholder 에서 예외를 내 resume 의 닫기 단계 전체가 rc 1 로 끝나고(래퍼는 경고만), 아무 pane 도 닫지 못한다.
|
|
- 수정(herdr_restore.py:58-66 `_nothing_running`): `_shell_in_foreground` 가 CalledProcessError 를 내면 **pane 에 `restore_error` 가 있고 출력에 `pane_not_found` 가 있을 때만** "실행 중인 것 없음"으로 보고, 그 외 실패는 그대로 올린다. 두 조건이 모두 herdr 자신이 붙인 표지라 사용자 pane·다른 세션 pane 이 이 경로로 닫힐 수 없다(agent_session 일치 조건 :83 은 그 앞에서 여전히 적용). 단위 테스트 2건이 "restore_error 없음 + pane_not_found", "restore_error 있음 + 다른 오류" 를 모두 예외 유지로 고정한다. fail-safe 방향(닫는 쪽이 아니라 두는 쪽) 유지.
|
|
- `_herdr` 는 `subprocess.run(..., capture_output=True, check=True)` 이므로 CalledProcessError.stderr/.output 이 채워진다(:46-49) — 판정에 쓰는 문자열이 실제로 들어온다.
|
|
- test_issue45_restore.py:267·:275-277 주석·단언이 0.9.1($HOME)/0.9.3(원래 경로) 둘 다 허용. 다른 문서의 "$HOME 으로 복원" 주장: SKILL.md 들에는 없음(create:120, resume:63 은 "empty shells" 만 말함), VERSIONS.md 과거 항목은 브리프대로 제외.
|
|
- 실행: 이 Mac(herdr 0.9.3)에서 tests/test_issue45_restore.py **5개 모두 통과, skip 0**.
|
|
|
|
## 2. 항목 2 — N2 fail-closed
|
|
- 래퍼(:103-127): `_decision_failed` 는 stderr 에 사유를 적고 `exit 1`; `_decided <var> <sub> …` 는 rc≠0 또는 빈 출력이면 실패; `_exit_for` 는 답이 `^[0-9]+$` 가 아니면 실패. 다섯 `exit "$(_decide exit-code …)"` 가 `_exit_for` 로, 네 `sub-status` 대입과 `finalize-begin` 이 `_decided` 로, `finalize-end` 는 rc 검사(:856-857), `cmd_wait` 의 wait-rc 는 `_decided` + 숫자 검사(:1070-1071). 모든 호출이 서브셸 밖(직접 호출)이라 `exit 1` 이 래퍼를 끝낸다; `{ …; } 4>&1` 그룹도 서브셸이 아니다.
|
|
- 정상 경로 불변: `_decided` 는 같은 명령의 같은 한 줄 출력을 변수에 넣고, `finalize-end` 의 "소유자 사라짐 → rc 0·빈 답" 은 전과 같이 FINAL_JOB_STATUS="" 로 남는다(의도된 기존 동작). test_f_the_normal_path_is_unchanged(실제 래퍼, human 잡, 닿지 않는 브로커 → rc 3, 마지막 줄 = 로그 경로, 오류 문구 없음) 통과. 옛·새 비교 테스트(test_c_*) 전부 통과.
|
|
- rc 로만 읽는 호출: `subscriber-up` 실패(모듈 깨짐) → "subscriber died early" 경로 → `_decided sub-status` 가 실패 → exit 1(fail-closed, OK). `stall-watch` 실패 → `|| return 0` 으로 **감시만 꺼진 채 진행**(:718). 브리프가 "범위에 넣지 않은 것은 이유를 적으라" 했는데 리뷰어에게 그 이유는 보이지 않는다 — 관찰 N1. #30 감시자는 notify-only 라 잡 종결에는 영향이 없어 비차단.
|
|
- 추가 테스트가 수정 전 코드에서 실패하는가: 이전 래퍼(56d0bfd)를 넣은 사본에서 test_f_* 11건 + test_s_no_printed_decision_is_read_raw 모두 **실패** — exit-code 는 `exit: : numeric argument required` 로 **255**, 인터프리터 부재는 **127**, finalize-begin 빈 답은 finalize-end argparse `--evidence-until: invalid int value: ''` 로 **2**. 세 가지 모두 브리프가 금지한 종료 방식이며 새 코드는 전부 1 로 끝난다.
|
|
- 이식성: `/bin/bash -n` 통과(3.2), `printf -v`·`[[ =~ ]]` 는 3.2 에서 지원. 테스트는 `/bin/sh` 셸 스크립트 대역과 `sys.executable` 만 쓴다.
|
|
|
|
## 3. 항목 3 — N1 문구
|
|
wrapper.py:24-29 가 "이 모듈은 stdlib 만 import 하지만 `python -m lib_py.delegation.wrapper` 는 패키지 `__init__` 을 먼저 실어 paho 가 로드되며, 래퍼의 $PY 는 원래 paho 가 필요하다"로 정정. 실행 경로 변경 없음(diff 상 docstring 만).
|
|
|
|
## 4. 항목 4 — N3 주석
|
|
lib_int.sh:9-10 에 "PATH 의 python3 를 쓴다(단독 source 라 $PY 없음); 없으면 mam_int/mam_int_knob 이 아무것도 출력하지 않는다(rc 127)" 추가. 코드 불변.
|
|
|
|
## 5. 테스트 실행 (검증 경로, 워크트리 .venv Python 3.9.6, paho 있음, `env -i` 로 HERDR_*·MAM_*·MQTT_*·WORKSPACE_ROOT 제거)
|
|
| 실행 | 결과 |
|
|
|---|---|
|
|
| tests/test_issue45_restore.py, test_issue45_restore_unit.py, test_issue17_item4_decisions.py, test_issue33_budget.py | **310 passed / 0 failed / 0 skipped** (425 s) |
|
|
| 새 테스트 16건, 이전 래퍼·이전 herdr_restore.py 사본 | **13 failed** / 3 passed (실패 = F 11 + 정적 가드 + placeholder 단위) |
|
|
| test_b (실서버), 이전 herdr_restore.py 사본 | 1 failed (pane_not_found 예외) |
|
|
격리: 실행 전후 herdr 프로세스는 기존 `multi-agent-mux` 서버·attach·오케스트레이터 `agent wait`(pid 만 교체)뿐, `/private/tmp/m45*` 없음, `~/.config/herdr` sessions·config.toml md5 불변. 실제 .mam/jobs 항목 수 불변. 루프백 bind 제약 없음(브로커 테스트 정상 실행).
|
|
|
|
## 6. 비차단 관찰
|
|
- **N1 stall-watch 판정 실패 시 조용히 감시 생략**(래퍼 :718 `|| return 0`): 모듈이 깨지면 stderr 에 아무 말 없이 stall watcher 가 꺼진다. 종결·레지스트리·이벤트에는 영향이 없어 fail-closed 요구 밖이지만, `_decide` 의 rc 가 1(판정 "감시 안 함")인지 그 밖(실패)인지 구분해 후자는 경고 한 줄을 남기면 진단이 쉬워진다. 브리프가 요구한 "범위 제외 이유" 가 리포트에 있는지 오케스트레이터가 확인하길 권한다.
|
|
- **N2 `_env` 가 상속 WORKSPACE_ROOT 를 비우지 않음**(tests/test_issue17_item4_decisions.py:224-230): HERDR_/MAM_/SKS_ 만 걷어낸다. 새 테스트(:659-660, :692)는 WORKSPACE_ROOT 를 명시하지만, 래퍼를 source 하는 기존 `_run_both` 4곳(:246, :372, :561, :586, PR #51 유래)은 `_env(work, …)` 만 써서 에이전트 pane 에서 돌리면 그 pane 의 WORKSPACE_ROOT 로 lib.sh 가 초기화된다 — 브리프가 적은 사고(상속된 WORKSPACE_ROOT 로 다른 워크스페이스의 shim 재작성)와 같은 경로다. `_env` 에서 WORKSPACE_ROOT 를 제거하고 tmp_path 로 고정하면 한 줄로 막힌다. 이 델타가 만든 문제가 아니라 비차단.
|
|
- **N3 docstring 줄바꿈**(herdr_restore.py:7-8): "A pane keeps the\n`agent_session` its agent\nreported" 로 어색하게 끊겨 있다. 내용 문제 없음.
|
|
|
|
[VERDICT: PASS]
|