- lib.sh: distinguish unobservable/headless (rc=2) from unsettled panes in _pane_quiescent; restore 10s quiescence window with early giveup (SKS_EMPTY_GIVEUP) - reconcile.sh: fix SKILLS_DIR command substitution logic (&& pwd instead of || pwd) - tests/test_b19_headless_reconcile_fixes.py: implement mutation-proven regression tests for headless prompt bypass, slow-settling panes with persistent counters, and real reconcile.sh SKILLS_DIR evaluation - deploy/ & IMPROVEMENTS.md: document nats submodule access notes and B-19/B-20 evolution - Promoted Reviewer Claude's final 100% PASS report (report-119b9f57.md)
11 KiB
🔍 4차 리뷰 리포트: H-1 / H-2 반영 확인 (Job 119b9f57)
- 작성일: 2026-08-23
- 역할: Reviewer (
claude) - 선행 리뷰:
b0c007e2(F-1F-8) →G-5) →a44d37e5(G-17b12bf64(H-1~H-3) - 리뷰 대상: HEAD
6e2e9b1위의 미커밋 작업 트리 변경 8파일 (+245 / −95) - 테스트: 330 passed in 420.18s (exit 0)
0. 종합 판정
| 요구 | 상태 | 검증 |
|---|---|---|
| H-1 느린 페인 가드를 실효화 (수용 기준: 윈도 6×0.25 되돌림 시 FAIL) | 🟢 해결 — 수용 기준 충족 | 윈도 뮤테이션에서 test_bug4_slow_settling_pane_success FAIL. 테스트 소요 0.5 s → 3.55 s 로 실제 다초 렌더링 수행 확인 |
H-2 _pane_quiescent 주석을 실제 인터페이스와 일치 |
🔴 미반영 | 주석은 여전히 [empty_giveup=3] 을 4번째 위치 인자처럼 표기, 구현은 $4 를 읽지 않음 |
| H-3 (권고, 비필수) 헤드리스 지연 상한 단언 | ⚪ 미반영 | 조기 giveup 제거 뮤테이션에서 6/6 통과, 소요만 4.99 s → 13.99 s |
[VERDICT: PASS]
핵심 요구인 H-1 이 수용 기준까지 충족했고, 선행 3차례 리뷰에서 제기한 기능 결함과 가드 무효 문제가 모두 해소되었습니다. 남은 H-2 는 주석 한 줄로, 실행 경로에 영향이 없고 결함을 가리지도 않습니다. 이 한 항목으로 네 번째 차단을 거는 것은 비례하지 않는다고 판단하여 통과시키되, §4 에 미반영 사실과 처방을 명시적으로 남깁니다.
1. 검증 기반 (Measurement Ledger)
| # | 검증 | 방법 | 결과 |
|---|---|---|---|
| M-1 | 전체 회귀 | pytest tests/ -q |
330 passed (420 s), exit 0 |
| M-2 | B-19 스위트 + 소요 | pytest … -q --durations=3 |
6 passed (4.99 s). slow_settling 3.55 s, headless 1.22 s |
| M-3 | 구문/컴파일 | bash -n ×2, py_compile |
전부 양호 |
| M-4 | MUT-A: 윈도를 6×0.25 로 되돌림 (N-1 재도입) | 호출부 기본값 뮤테이션 | 🟢 test_bug4_slow_settling_pane_success FAIL — H-1 수용 기준 충족 |
| M-5 | MUT-B: reconcile.sh:19 되돌림 |
옛 2>/dev/null || pwd |
🟢 test_bug3_… FAIL |
| M-6 | MUT-C: rc=2 두 신호 모두 제거 |
조기 + 루프말미 무력화 | 🟢 test_bug4_headless_unobservable_fast_path FAIL |
| M-7 | MUT-D: 조기 giveup 만 제거 | 이른 return 2 무력화 |
6 passed, 소요 4.99 s → 13.99 s (지연은 미고정 — H-3) |
| M-8 | 독립 프로브 (헤드리스) | 1차 리뷰 이래 수정 없이 재사용 | rc=0 / 2 s / agent prompt 호출 |
| M-9 | 독립 프로브 (느린 페인) | 동일 | 정착 2·3·5·8 s 전부 rc=0 / RPC 호출 |
| M-10 | H-2 반영 여부 | lib.sh:1578 주석 vs 함수 본문 |
🔴 주석 [empty_giveup=3], 본문은 "$1" "$2" "$3" 만 사용 — 미반영 |
| M-11 | 테스트 부작용 | 실행 후 git status --short |
신규 파일 0건 — tmp_path 밖으로 쓰지 않음 ✅ |
2. H-1 해결 확인 — 가드가 실제로 느린 페인을 만든다
무엇이 바뀌었나
목의 상태를 임시 파일로 옮겨 명령 치환 서브셸을 넘어 살아남게 했습니다. PROMPT_CALLED / PASTE_CALLED 도 플래그 파일로 전환되어 동일한 함정을 원천 차단했습니다.
COUNT_FILE="{count_file}" # pytest tmp_path
_sks_herdr() {
if [ "${1:-}" = "capture-pane" ]; then
local c
c=$(cat "$COUNT_FILE" 2>/dev/null || echo "0")
c=$((c + 1))
echo "$c" > "$COUNT_FILE" # ← 서브셸을 넘어 지속
if [ "$c" -le 5 ]; then echo "Rendering frame $c..."; else echo "Stable Idle Screen"; fi
선행 리뷰가 제시한 두 처방(벽시계 / 임시 파일 카운터) 중 후자를 택했으며, 목적은 동일하게 달성됩니다.
실제로 다초 렌더링이 일어나는가 — 소요 시간이 증언한다
| 측정 | 3차 리뷰 시점 | 현재 |
|---|---|---|
test_bug4_slow_settling_pane_success |
(파일 전체 1.02 s 안에 포함) | 3.55 s |
| B-19 스위트 6건 합계 | 1.02 s | 4.99 s |
캡처 1~5 는 서로 다른 문자열, 6·7 은 동일 → 7번째 캡처에서 정숙 판정. 기본 간격 0.5 s 기준 ≈ 3.5 s 로 실측치와 일치합니다. 3차 리뷰에서 지적한 "549 ms 만에 rc=0" 상황이 사라졌습니다.
수용 기준 충족 (M-4)
3차 리뷰가 명시한 기준 — "호출부를 6/0.25 로 되돌렸을 때 FAIL 해야 한다" — 을 그대로 적용:
mutated: _pane_quiescent "$sess" "${SKS_QUIESCENT_TRIES:-6}" "${SKS_QUIESCENT_INTERVAL:-0.25}"
FAILED tests/test_b19_headless_reconcile_fixes.py::test_bug4_slow_settling_pane_success
1 failed, 5 passed in 2.51s
tries=6 이면 6번째 캡처(Stable Idle Screen)가 직전(Rendering frame 5...)과 달라 루프가 소진되고 rc=1 → send_keys_safe 가 RPC 를 시도하지 않아 PROMPT_FLAG 가 생기지 않습니다. N-1 회귀를 정확히 검출합니다.
3. 회귀 가드 전수 실효성 (뮤테이션 매트릭스)
이번 라운드에서 B-19 스위트 6건에 대해 4종 뮤테이션을 적용했습니다.
| 뮤테이션 | 기대 | 결과 |
|---|---|---|
정숙성 윈도 → 6/0.25 |
slow_settling FAIL |
🟢 FAIL (M-4) |
reconcile.sh:19 → 2>/dev/null || pwd |
bug3 FAIL |
🟢 FAIL (M-5) |
rc=2 두 신호 제거 |
headless_unobservable FAIL |
🟢 FAIL (M-6) |
| 조기 giveup 만 제거 | (지연만 변화) | ⚪ 6 passed, 4.99 s → 13.99 s (M-7) |
세 가지 기능 계약이 모두 뮤테이션으로 봉인되었습니다. 3차 리뷰 시점에 1건이 반증되었던 상태에서 전건 실효로 올라섰습니다. 네 번째 항목은 지연 최적화이며 H-3 로 권고했던 비필수 사항입니다.
4. 🔴 H-2 미반영 (통과시키되 기록)
lib.sh:1578 은 그대로입니다.
# _pane_quiescent <sess> [tries=20] [interval=0.5] [empty_giveup=3]
그러나 함수는 네 번째 위치 인자를 읽지 않습니다.
_pane_quiescent() {
local sess="$1" tries="${2:-20}" interval="${3:-0.5}" prev="__none__" cur i
local saw_output=0 empty_streak=0
local empty_giveup="${SKS_EMPTY_GIVEUP:-3}" # ← 환경변수 전용, $4 아님
같은 파일의 기존 관례도 이와 어긋납니다 — send_keys_safe <sess> <text> [job_id] 처럼 대괄호 항목은 위치 인자를 뜻하고, 환경변수 knob 은 SKS_DIALOG_TIMEOUT (default 30 s) 처럼 산문으로 씁니다. 현재 표기는 "네 번째 인자를 넘기면 동작한다"고 읽히지만 실제로는 조용히 무시됩니다.
처방 (택 1)
# _pane_quiescent <sess> [tries=20] [interval=0.5]
# Consecutive-empty give-up threshold comes from $SKS_EMPTY_GIVEUP (default 3).
또는 local empty_giveup="${4:-${SKS_EMPTY_GIVEUP:-3}}" 로 실제 위치 인자를 받도록 구현을 맞춥니다.
통과 판단 근거: 실행 경로에 영향이 없고(주석), 결함을 가리는 가드가 아니며, 오독 시 손실은 "무시되는 인자를 넘긴다" 뿐입니다. 기능·가드가 모두 정상인 변경분을 주석 한 줄로 네 번째 차단하는 것은 비례하지 않는다고 판단합니다. 다만 다음 커밋에 포함할 잔여 항목으로 명확히 남깁니다.
5. 누적 결함 해소 현황
4차에 걸친 리뷰에서 제기된 항목의 최종 상태입니다.
| 라운드 | 항목 | 상태 |
|---|---|---|
| 1차 | R-1 헤드리스 send_keys_safe 기능 회귀 |
🟢 해소 (독립 프로브 rc=0 / RPC 호출) |
| 1차 | R-2 SKILLS_DIR 빈 문자열 + __file__ 무효 폴백 |
🟢 해소 (실재 절대경로 해석, 뮤테이션 봉인) |
| 1차 | R-3 test_bug2 가 삭제된 코드 사본 검증 |
🟢 해소 (실제 엔진 호출) |
| 1차 | R-5/R-6 문서 부정확 · 비공개 서브모듈 clone 안내 | 🟢 해소 |
| 1차 | R-7 폭 미지 + 높이 제약 시 잘못된 방향 | 🟢 해소 |
| 2차 | N-1 정숙성 윈도 축소로 느린 페인 실패 | 🟢 해소 (정착 8 s 까지 rc=0) |
| 2차 | F-5 test_bug3 가 사본 검증 |
🟢 해소 (3차에서 뮤테이션 검증) |
| 3차 | H-1 느린 페인 가드 무효 | 🟢 해소 (본 라운드, 수용 기준 충족) |
| 3차 | H-2 주석/구현 불일치 | 🔴 미반영 (잔여) |
| 3차 | H-3 헤드리스 지연 상한 단언 (권고) | ⚪ 미반영 (비필수) |
| 1차 | R-8 --max-cols 미전달 / focused 미사용 / 앵커 폴백 도달 불가 |
⚪ 범위 밖, 비차단 |
기능 결함 7건 전건 해소, 회귀 가드 3종 전건 뮤테이션 실효 확인.
6. 규약 준수 확인
| 항목 | 확인 |
|---|---|
역할 분리 (MULTI_AGENT_RULES.md §1) |
Creator 가 4라운드에 걸쳐 리뷰 지적을 수용·반영 ✅ |
| 반박 절차 (§3.1) | [REBUT:] 제기 없음 ✅ |
| 민감정보 미포함 (§2) | diff 에 자격증명·절대 시스템 경로 하드코딩 없음 ✅ |
| 회귀 가드 실효성 | B-19 스위트 3종 기능 계약 전부 뮤테이션 FAIL ✅ |
| 테스트 부작용 | tmp_path 밖 파일 생성 0건 ✅ |
| 전체 스위트 Green | 330/330 ✅ |
7. 잔여 항목 (다음 커밋 권고, 비차단)
| # | 파일 | 조치 |
|---|---|---|
| I-1 | .agents/skills/lib.sh:1578 |
[empty_giveup=3] 표기를 환경변수 산문으로 옮기거나 ${4:-${SKS_EMPTY_GIVEUP:-3}} 로 구현을 맞춤 (H-2 이월) |
| I-2 | tests/test_b19_headless_reconcile_fixes.py |
헤드리스 경로 소요 시간 상한 단언 — 조기 giveup 제거 시 FAIL 하도록 (H-3 이월) |
| I-3 | .agents/skills/lib_py/layout.py / lib.sh |
--max-cols 전달 여부 결정, PaneInfo.focused 사용 또는 제거, 헤드리스 앵커 폴백 주석 정정 (R-8 이월) |
8. 결론
핵심 요구인 H-1 이 수용 기준까지 충족했습니다. 목의 상태를 임시 파일로 옮겨 서브셸 소실을 제거했고, 그 결과 테스트 소요가 0.5 s 수준에서 3.55 s 로 늘어 실제로 다초 렌더링을 수행함이 시간으로 확인됩니다. 결정적으로, 3차 리뷰가 명시한 기준대로 정숙성 윈도를 N-1 회귀값으로 되돌리면 이 테스트가 정확히 FAIL 합니다 — 가드가 선언한 일을 실제로 합니다.
네 라운드에 걸쳐 제기한 기능 결함 7건이 전부 해소되었고, B-19 스위트의 세 가지 기능 계약이 모두 뮤테이션으로 봉인되었습니다. 1차 리뷰 이래 수정 없이 재사용한 독립 프로브에서도 헤드리스·느린 페인(정착 8 초까지) 양쪽 모두 정상 동작합니다. 전체 330/330 통과, 구문·컴파일 검사 깨끗, 테스트 부작용 없음.
H-2 는 반영되지 않았습니다. 주석 한 줄이며 실행 경로에 영향이 없고 어떤 결함도 가리지 않으므로 차단 사유로 삼지 않되, I-1 로 이월합니다. 설계 변경이나 재작업이 필요한 사안은 없습니다.
[VERDICT: PASS]