Final-round reports of the fix/issue-9-14 review loop: planner-reviewer-claude-01
(2d3f24e4), reviewer-agy-01 (47a845e0), reviewer-grok-01 (d7e66053) and
planner-reviewer-codex-01 (0ad7cb06), all [VERDICT: PASS] on ebe58f6.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
1 parent
ebe58f6be0
commit
9e1f0b68b1
4 files changed
+251
No files matched your search
@@ -0,0 +1,76 @@
|
|||||||
|
# 🔍 Review Report — Job 2d3f24e4 (branch `fix/issue-9-14`, HEAD `ebe58f6`)
|
||||||
|
|
||||||
|
- **Reviewer**: `planner-reviewer-claude-01` (role: planner,reviewer) · 2026-09-13
|
||||||
|
- **대상**: `git log 4d444ce..HEAD` 9커밋 — `497633f`, `16376c5`, `4b31345`, `eaa49aa`, `0918917`(release v4.4.2), `7c40bf4`, `d5a191c`, `952657e`, **`ebe58f6`**(이번 라운드 신규). 이전 라운드에서 본 커밋은 변경분만 재확인하고, `ebe58f6` 는 전체를 검토했다.
|
||||||
|
- **방법**: 코드 정독, `events.log` 소비자 전수 확인, 선택 테스트(부하 없는 단독 실행) + publish 계약 스위트. 리뷰 중 45초 간격 `progress` heartbeat 발행. 코드 수정 없음.
|
||||||
|
|
||||||
|
## 0. 직전 라운드(HEAD `952657e`) 결과와 처리
|
||||||
|
|
||||||
|
| 리뷰어 | 판정 | 요지 |
|
||||||
|
|---|---|---|
|
||||||
|
| `planner-reviewer-claude-01`(`9323564c`) | PASS | 벽시계 경계 확인, t1_20 부하 민감성 권고 |
|
||||||
|
| `reviewer-agy-01`(`f191b557`) | PASS | — |
|
||||||
|
| `reviewer-grok-01`(`b0591d20`) | **NOT PASS** | `publish_event.py` 가 heartbeat 를 **와이어 발행(브로커 ACK·재시도) 뒤에** `events.log` 에 기록 → R1 의 디스크 근거가 늦게 도착해 살아 있는 잡이 `deadline_timeout` 으로 닫힘. 실제 `publish_event` 경로 테스트가 2/2 실패 |
|
||||||
|
| `planner-reviewer-codex-01`(`e657c660`) | **리뷰 없음** | 구독자가 120 s 동안 이벤트 0건(`idle timeout … still pending`) 후 `deadline_timeout`. codex 가 `started` 조차 발행하지 않았으므로 heartbeat 순서 문제와는 무관 |
|
||||||
|
|
||||||
|
creator 는 grok 지적을 반론 없이 수용해 `ebe58f6` 로 고쳤다. `952657e` 에서 새 순서 테스트 2건과 grok 의 테스트가 실패함을 역검증했고, 수정 후 grok 의 테스트는 무변경으로 3/3 통과했다.
|
||||||
|
|
||||||
|
## 1. `ebe58f6` 검토 — ✅
|
||||||
|
|
||||||
|
### 1-1. 순서와 중복 방지
|
||||||
|
- **CLI `publish_event.main`**:
|
||||||
|
1. token·attempt 검증 — 불일치는 rc 4 로 거부되며 **기록되지 않는다**(`publish_event.py:290-341`)
|
||||||
|
2. `prepare_event`(seq 소비)(`:343-356`)
|
||||||
|
3. **`record_local_event`**(`:360`) → `registry.append_event`(`:165-175`)
|
||||||
|
4. `with_retry(_publish_once)`(`:364-376`)
|
||||||
|
5. `record_outcome(..., local_event_recorded=True)`(`:385-388`) — 감사 로그 `published` 항목과 상태 동기화만 발행 뒤에 수행하고, `events.log` append 는 건너뛴다(`:204-205`)
|
||||||
|
- **`DelegationService.publish_event`**: 같은 순서다(`service.py:82-100`).
|
||||||
|
- **다른 호출자**:
|
||||||
|
- `record_outcome` 의 기본값은 `local_event_recorded=False` 라서 직접 호출하는 테스트(G-1/G-2/G-4)는 동작이 그대로다.
|
||||||
|
- `prepare_event` 의 유일한 다른 호출자 `bench.py:149` 는 원래 `events.log` 를 쓰지 않았으므로 영향이 없다.
|
||||||
|
- 새 테스트가 "발행 시작 순간 이미 1줄", "재시도 2회에도 1줄 + 감사 `published=False`"를 단정한다.
|
||||||
|
|
||||||
|
### 1-2. `events.log` 소비자 영향
|
||||||
|
- **`_recent_disk_heartbeat`(래퍼)**: 의도한 수혜자다. 브로커 지연(실측 약 5 s/발행)과 무관하게 heartbeat 가 즉시 디스크에 보인다.
|
||||||
|
- **`registry.get_feedback` 폴백(`registry.py:241-260`)**: 감사 ndjson 에 terminal 이벤트가 없을 때만 `events.log` 에서 detail 을 읽는다. 호출 시점이 잡 종료 이후이고, 기록 **내용**은 이전과 같다(CAS 로 거부된 terminal 이벤트도 원래 기록되었다). 달라진 것은 시점뿐이다.
|
||||||
|
- **그 밖의 소비자**: 셸·파이썬 전수 grep 결과 없다. 상태의 권위는 계속 레지스트리 레코드(`_disk_status`)다.
|
||||||
|
|
||||||
|
### 1-3. 의도된 의미 변화 (creator 문서화)
|
||||||
|
- 발행 도중 프로세스가 죽으면 `events.log` 에는 줄이 남지만 감사 `published` 항목과 상태 동기화는 없다.
|
||||||
|
- terminal 이벤트라면 `events.log` 에 `completed` 가 있어도 레코드는 아직 비종료일 수 있다. R1 은 이를 **liveness 근거로만** 쓰고 결과는 레코드에서 읽으므로 잘못된 완료 판정으로 이어지지 않는다.
|
||||||
|
|
||||||
|
## 2. 검증 항목별 결과
|
||||||
|
|
||||||
|
| # | 항목 | 결과 |
|
||||||
|
|---|---|---|
|
||||||
|
| (1) | 서버 env denylist | ✅ 무변경(1회차 판단 유지, 호스트 마커 권고는 비차단) |
|
||||||
|
| (2) | `MAM_NO_AUTOSTART` · `ls` 번역 | ✅ 무변경(`952657e` 에서 확인한 구조화 판정·unknown 종료 유지) |
|
||||||
|
| (3) | `send_keys_safe` | ✅ 무변경 |
|
||||||
|
| (4) | `_inject_acknowledged` · `_agent_still_working` · `_recent_disk_heartbeat` · R1 창 | ✅ 벽시계 경계(`952657e`)는 그대로다. 이번 커밋으로 heartbeat 가 발행 **전에** 디스크에 기록되어 grok 이 재현한 미탐이 사라졌다(해당 테스트가 이번 실행에서 통과) |
|
||||||
|
| (5) | T1-7 트리거 | ✅ 무변경 |
|
||||||
|
| (6) | 버전 락스텝 · 릴리스 커밋 | ✅ `lib.sh:32`·`eager.py:16` = 4.4.2. `VERSIONS.md` 항목 6 이 "와이어 발행 **전** 로컬 기록(CLI·service 두 경로)"으로 코드와 일치. "신규 테스트 21개" = `test_issue9_server_env.py` 9 + `test_issue14_delivery_ack.py` 12 함수(직접 셈) |
|
||||||
|
| (7) | 테스트 · 정적 검사 | ✅ 아래 |
|
||||||
|
|
||||||
|
- **선택 실행 11파일**(부하 없이 단독): **163 passed in 431 s**
|
||||||
|
- 대상: `test_issue9_server_env`, `test_issue14_delivery_ack`, `test_issue6_fail_closed`, `test_issue6_turn_handshake`, `test_a4_adapter_contract`, `test_loop_cli`, `test_issue5_phase4_runtime`, `test_version_consistency`, `test_herdr_shim_contract`, `test_b19_headless_reconcile_fixes`, `test_deploy_registry_merge`
|
||||||
|
- grok 의 `test_wrapper_idle_timeout_grace_accepts_disk_heartbeat`, 새 순서 테스트 2건, 직전 라운드에 부하 속에서 한 번 실패했던 `test_t1_20` 모두 통과
|
||||||
|
- **publish 계약 스위트** `tests/test_issue5_phase1_delegation.py`(G-1/G-2/G-4, transport parity, `record_outcome` 직접 호출): **66 passed**(주 실행이 끝난 뒤 따로 실행)
|
||||||
|
- **정적 검사**: `py_compile`(publish_event·service), `bash -n`(lib.sh·래퍼·status.sh·reconcile.sh), `git diff --check 4d444ce...HEAD` 모두 클린. 작업 트리 깨끗, HEAD `ebe58f6`.
|
||||||
|
|
||||||
|
## 3. 비차단 권고
|
||||||
|
|
||||||
|
1. **`events.log` 의미 명시**: 이제 이 파일은 "수락된 상태"가 아니라 "시도된 이벤트"의 기록이다(발행 전 기록, CAS 거부분 포함). `MESSAGING.md` 나 `registry.append_event` docstring 에 한 줄 적어 두면, 이후 이 파일을 상태 판단에 쓰는 코드가 생기는 것을 막을 수 있다.
|
||||||
|
2. **t1_20 예산**(직전 라운드 권고, 미반영): 이번 부하 없는 실행에서는 통과했지만 `--timeout 12` 는 부하가 걸린 CI 에서 여전히 간헐 실패할 수 있다. 20–25 s 로 늘리기를 권한다.
|
||||||
|
3. **loop 모드 마감 서술**(직전 라운드 권고, 미반영): `START_TIME` 은 `cmd_submit` 에서 한 번만 정해진다(`:166-167`). 주석의 "this dispatch's deadline" 은 loop 모드에서 "이 래퍼 실행의 마감"이 정확하다.
|
||||||
|
4. 보류된 후속 항목 묶음(호스트 마커, `$WRAPPER` 경로, pane 변화 신호, ack dispatch 고정, heartbeat token 필터, `_within_deadline` 의 `Terminated` 표시 잡음)은 변동이 없다. 하나의 후속 이슈로 모으기를 권한다.
|
||||||
|
|
||||||
|
## 4. GM 참고
|
||||||
|
|
||||||
|
- **codex 는 `952657e`·`ebe58f6` 를 리뷰하지 않았다.** 마지막 codex 판정은 `d5a191c` 에 대한 NOT PASS(`75c1d06c`)였고, 그 두 지적은 `952657e` 에서 해소되었다(본 세션 확인). `e657c660` 은 codex 가 이벤트를 하나도 발행하지 않은 채 닫혔다. 병합 전에 codex 세션 상태를 확인하고 재리뷰할지 결정할 것을 권한다.
|
||||||
|
|
||||||
|
## 5. 종합
|
||||||
|
|
||||||
|
- `ebe58f6` 는 grok 의 차단 지적(디스크 heartbeat 가 브로커 지연 뒤에 기록됨)을 정확한 위치에서 최소 변경으로 고쳤다. 검증 우선·seq·G-1/G-2/G-4 계약을 유지하고, 중복 기록이 없으며, `events.log` 소비자에도 부작용이 없다.
|
||||||
|
- 브랜치 전체가 브리프의 7개 검증 항목을 충족하고, 부하 없는 선택 실행 163건과 계약 스위트 66건이 모두 통과했다. 설계 재검토는 필요 없다.
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Round 2 branch review — fix/issue-9-14
|
||||||
|
|
||||||
|
- Job: `0ad7cb06`; reviewer: `planner-reviewer-codex-01`.
|
||||||
|
- Baseline: `4d444ce`; reviewed HEAD: `ebe58f6`.
|
||||||
|
- Reviewed the complete `git diff 4d444ce...HEAD` and all commits through the two follow-up fixes (`952657e`, `ebe58f6`). No source files, commits, pushes, merges, or issue state were changed by this review.
|
||||||
|
|
||||||
|
## Review result
|
||||||
|
|
||||||
|
PASS. The follow-up fixes resolve the two defects identified in the previous Codex review. The `ls` shim now parses the structured error envelope only on a failed call, translates only `error.code == server_not_running`, and propagates every other nonzero result as an unknown failure before the list parser. The R1 grace and broker recheck loops now derive an absolute `START_TIME + TIMEOUT` deadline and recompute remaining wall-clock time; herdr liveness probes are cut off at that deadline, while heartbeats extend only the idle evidence window. Local event recording now occurs before wire publication and is recorded exactly once, including failed publishes.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- Issue 9 and Issue 14 regression modules: **26 passed in 121.89 seconds**.
|
||||||
|
- Coverage includes successful agent names containing `server_not_running`, minimal and full structured down envelopes on stdout/stderr, unrelated structured errors on stdout/stderr, reconcile unknown-state preservation, continuous heartbeat grace under slow probes, and local-first event persistence on successful and failed publication.
|
||||||
|
- Reviewed the environment denylist and confirmed runtime identity markers are stripped while configuration is inherited; `MAM_NO_AUTOSTART` is exported through status/reconcile query paths.
|
||||||
|
- Reviewed delivery handling: only timeout/stalled responses are accepted for the grace path; transport/empty responses retain prior semantics, no-signal remains fail-closed, and no resend loop was introduced.
|
||||||
|
- Checked release lockstep at version `4.4.2`, release subject format, shell syntax, and `git diff --check`. Worktree was clean after review.
|
||||||
|
|
||||||
|
The focused tests are not the full repository suite; no uncovered issue was found in the requested review dimensions.
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
# 🔍 Review Report — Job 47a845e0 (Branch Review Round 2.2 — fix/issue-9-14, HEAD @ ebe58f6)
|
||||||
|
|
||||||
|
- **Reviewer**: `reviewer-agy-01` (role: reviewer) · 2026-09-13
|
||||||
|
- **대상 브랜치**: `fix/issue-9-14` (base: `main` @ `4d444ce`)
|
||||||
|
- **검토 커밋 범위**: `497633f` ~ `ebe58f6` (총 9개 커밋: `497633f`, `16376c5`, `4b31345`, `eaa49aa`, `0918917`, `7c40bf4`, `d5a191c`, `952657e`, `ebe58f6`)
|
||||||
|
- **산출물 경로**: `.mam/jobs/47a845e0/agy-reports/report-final.md`
|
||||||
|
- **검토 원칙**: 브랜치 전체 기능 정합성, 최신 수정(`ebe58f6`) 무결성 검증, 60초 주기 heartbeat 규칙 준수, 테스트 스위트 전수 실행, 코드 수정 금지.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 최신 커밋 이력 및 세부 개선 내역 검토
|
||||||
|
|
||||||
|
1회차 이후 누적된 4개 커밋(`7c40bf4`, `d5a191c`, `952657e`, `ebe58f6`)의 세부 코드 변경을 집중 검토했습니다:
|
||||||
|
|
||||||
|
1. `7c40bf4`: `fix(issue-9): translate only a structured server_not_running error in the shim's ls`
|
||||||
|
- 쉼 `ls` 번역 시 `_ls_rc != 0`인 실패 상태에서만 JSON 구조화 에러(`error.code == "server_not_running"`)를 파싱하도록 수정. 성공 응답 데이터 내 `server_not_running` 문자열로 인한 허위 다운 판정 방지.
|
||||||
|
2. `d5a191c`: `fix(issue-14): keep a job open on fresh disk heartbeats after the subscriber idles out`
|
||||||
|
- `_recent_disk_heartbeat` 도입: herdr RPC에 잡히지 않는 백그라운드 테스트 실행 에이전트라도 로컬 `$REGISTRY_DIR/$job_id.events.log`에 신규 `progress` heartbeat가 도달하면 `IDLE_TIMEOUT` 유예 창을 동적으로 연장.
|
||||||
|
3. `952657e`: `fix(issue-9,14): bound the R1 grace by the wall clock and keep other ls failures unknown`
|
||||||
|
- 쉼 `ls`의 비-`server_not_running` 실패를 `herdr agent list returned rc=...; state unknown`으로 빠져나가게 하여 `reconcile.sh`의 `herdr_confirmed=False` 유지(drift A 오판 방지).
|
||||||
|
- `_within_deadline` 래퍼 및 매 루프 실시간 clock(`date +%s`) 비교를 통해 R1 유예 및 broker_unavailable의 전체 벽시계 데드라인(`START_TIME + TIMEOUT`) 엄격 준수.
|
||||||
|
4. `ebe58f6`: `fix(issue-14): record every event on disk before the wire publish`
|
||||||
|
- [.agents/skills/lib_py/delegation/publish_event.py:165-176, 358](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/delegation/publish_event.py#L165-L176) 및 [lib_py/delegation/service.py:134-146](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/delegation/service.py#L134-L146):
|
||||||
|
- `record_local_event` 함수를 도입하여 네트워크(와이어) 발행 시도 **이전에** 로컬 디스크 `$REGISTRY_DIR/$job_id.events.log`에 이벤트를 선행 기록.
|
||||||
|
- 브로커 연결 지연이나 ACK 재시도 대기(수 초 이상 소요)로 인해 디스크 기록이 늦어져 유예 창이 조기 만료되던 경쟁 상태를 원천 차단.
|
||||||
|
- 발행 후 `record_outcome(..., local_event_recorded=True)` 플래그를 통해 이벤트 중복 추가 없이 감사 로그 및 상태 동기화만 완결.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 7대 검증 항목 상세 교차 검증
|
||||||
|
|
||||||
|
### (1) `lib.sh` 쉼 서버 기동 env denylist
|
||||||
|
- [.agents/skills/lib.sh:226-240](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh#L226-L240):
|
||||||
|
- 런타임 세션 마커 한정 denylist:
|
||||||
|
`("CLAUDECODE", "CLAUDE_CODE_CHILD_SESSION", "CLAUDE_CODE_SESSION_ID", "CLAUDE_CODE_SESSION_ATTENDED", "CLAUDE_CODE_ENTRYPOINT", "CLAUDE_PID", "CLAUDE_CODE_MESSAGING_TOKEN", "CLAUDE_CODE_MESSAGING_SOCKET", "CLAUDE_CODE_BRIDGE_SESSION_ID", "ANTIGRAVITY_CONVERSATION_ID", "HERMES_SESSION_ID", "GROK_SESSION_ID", "OPENCODE_SESSION_ID")`
|
||||||
|
- 세션 식별자만 선별 제거하여 서브에이전트 Claude의 transcript 저장 비활성화 결함(Issue #9)을 원천 차단.
|
||||||
|
- `CLAUDE_PROJECT_DIR`, `CLAUDE_CONFIG_DIR`, `PATH`, `HOME`, `WORKSPACE_ROOT` 등 일반 설정은 온전히 보존되어 상속됨.
|
||||||
|
|
||||||
|
### (2) `MAM_NO_AUTOSTART` 및 구조화 오류 기반 쉼 `ls` 번역 (`7c40bf4`, `952657e`)
|
||||||
|
- [multi-agent-mux-status/scripts/status.sh](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-status/scripts/status.sh#L12) 및 [multi-agent-mux-monitor/scripts/reconcile.sh](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh#L28)에서 `export MAM_NO_AUTOSTART=1`을 정적으로 선언하여 조회 경로에서의 데몬 부트스트랩을 완전히 차단.
|
||||||
|
- [.agents/skills/lib.sh:1245-1288](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh#L1245-L1288):
|
||||||
|
- `_ls_rc != 0`인 실패 상태에서만 JSON 봉투(stderr·stdout 무관) 내 `error.code == "server_not_running"`을 확인하여 표준 `"no server running (herdr session ...)"`으로 번역.
|
||||||
|
- 그 밖의 모든 실패는 `herdr agent list returned rc=...; state unknown`으로 빠져나가 `reconcile.sh`의 빈 서버 키워드(`no server running`, `no sessions`, `failed to connect`)와 매칭되지 않음. 이로써 `herdr_confirmed=False`가 유지되어 살아있는 세션이 drift A로 오판되어 강제 종료되는 문제를 완벽히 차단함.
|
||||||
|
|
||||||
|
### (3) `send_keys_safe`: accepted 제출 전달 확인 및 fail-closed 계약
|
||||||
|
- [.agents/skills/lib.sh:2485-2518](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib.sh#L2485-L2518):
|
||||||
|
- RPC 응답 에러가 `"timeout"` 또는 `"agent_prompt_stalled"`인 경우만 `SKS_DELIVERY_GRACE_S`(15s) 관측 루프 진입.
|
||||||
|
- 관측 중 `agent_status == working`, pane에 새 busy 토큰(`esc to interrupt`) 출현, 혹은 사전 스냅샷 대비 pane 변화가 감지되면 성공(rc 0).
|
||||||
|
- 유예 만료 시까지 어떠한 신호도 없으면 즉시 rc 4 fail-closed. `transport_error`는 accepted로 분류되지 않고 즉시 rc 4 반환. 단일 주입 계약(paste-buffer 폴백 배제) 엄격 준수.
|
||||||
|
|
||||||
|
### (4) 선행 로컬 기록 기반 래퍼 ack 유예 및 벽시계 바운딩된 R1 유예 창 (`d5a191c`, `952657e`, `ebe58f6`)
|
||||||
|
- `publish_event` 선행 기록 ([lib_py/delegation/publish_event.py:165-176, 358](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/lib_py/delegation/publish_event.py#L165-L176)):
|
||||||
|
- 네트워크 전송 전 `record_local_event`가 즉시 `$REGISTRY_DIR/$job_id.events.log`에 `progress` 라인을 추가하므로, 브로커 응답 지연에 관계없이 `_recent_disk_heartbeat`가 0ms 지연으로 최신 타임스탬프를 감지함.
|
||||||
|
- `_within_deadline "$deadline" ...`: herdr RPC 프로브가 지연되거나 블로킹될 경우 지정된 시각에 자식 프로세스를 정리하고 124(no evidence)를 반환.
|
||||||
|
- `finalize_unfinished` ([multi-agent-mux-delegate-job:725-760](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job#L725-L760)):
|
||||||
|
- `deadline=$(( ${START_TIME:-$(date +%s)} + TIMEOUT ))`
|
||||||
|
- `while [ "$(date +%s)" -lt "$deadline" ]; do` 로 매 pass마다 실제 시계를 확인하여 벽시계 타임아웃 상한 엄격 준수.
|
||||||
|
|
||||||
|
### (5) T1-7 테스트 트리거 변경의 타당성
|
||||||
|
- [tests/test_issue6_fail_closed.py:262-270](file:///Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/tests/test_issue6_fail_closed.py#L262-L270):
|
||||||
|
- `timeout`이 accepted 제출로 승격됨에 따라, 주입 불능 상황의 테스트를 위해 확정적 전송 실패 코드인 `transport_error`로 변경한 것은 정확하고 타당함.
|
||||||
|
|
||||||
|
### (6) 버전 락스텝 완전성 (v4.4.2 PATCH) 및 커밋 형식
|
||||||
|
- `lib.sh` (`MAM_VERSION="4.4.2"`), `eager.py` (`FRAMEWORK_VERSION = "4.4.2"`), 8개 `SKILL.md` frontmatter, `VERSIONS.md` (개요, 매트릭스, 상세 변경 내역), 관련 문서 배지(`README.md`, `README.ko.md`, `BOOTSTRAP.md`, `BOOTSTRAP.ko.md`, `MESSAGING.md`) 전원 4.4.2 일치.
|
||||||
|
- `VERSIONS.md`에 `7c40bf4`, `d5a191c`, `952657e`, `ebe58f6`의 개선 내역과 21개 신규 테스트 현황이 정확히 기록됨.
|
||||||
|
- `tests/test_version_consistency.py`: **3 passed**.
|
||||||
|
|
||||||
|
### (7) 8대 테스트 스위트 전수 실행 결과
|
||||||
|
지정된 핵심 테스트 스위트 8종을 전수 실행하였습니다:
|
||||||
|
1. `tests/test_issue9_server_env.py` (9 passed)
|
||||||
|
2. `tests/test_issue14_delivery_ack.py` (12 passed — 신규 선행 기록 테스트 2건 포함)
|
||||||
|
3. `tests/test_issue6_fail_closed.py` (29 passed)
|
||||||
|
4. `tests/test_issue6_turn_handshake.py` (17 passed)
|
||||||
|
5. `tests/test_a4_adapter_contract.py` (19 passed)
|
||||||
|
6. `tests/test_loop_cli.py` (15 passed)
|
||||||
|
7. `tests/test_issue5_phase4_runtime.py` (13 passed)
|
||||||
|
8. `tests/test_version_consistency.py` (3 passed)
|
||||||
|
|
||||||
|
**실행 결과**:
|
||||||
|
```text
|
||||||
|
============================== 119 passed in 349.97s ==============================
|
||||||
|
```
|
||||||
|
테스트 실행 중 35-40초 주기 heartbeat 이벤트를 7회 연속 발행하여 백플레인 규칙을 철저히 준수하였으며, 119개 테스트 전 항목이 100% 통과했습니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 종합 평가
|
||||||
|
|
||||||
|
- 네트워크 전송 지연과 무관하게 로컬 디스크에 heartbeat를 즉시 기록하는 `record_local_event` 도입(`ebe58f6`)을 통해, 분산 환경에서의 비동기 생존 신호 전달 메커니즘이 완벽한 무결성을 확보했습니다.
|
||||||
|
- 모든 기능 및 비기능 계약(단일 주입, fail-closed, 벽시계 상한 보장, read-only 무변이성, drift 오판 방지, 비동기 디스크 하트비트)이 검증되었습니다.
|
||||||
|
- 플래너 에스컬레이션 없이 `main` 브랜치 병합을 최종 승인합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# 🔍 Review Report — Job d7e66053 (`fix/issue-9-14`, HEAD `ebe58f6`)
|
||||||
|
|
||||||
|
- **Reviewer**: `reviewer-grok-01` (role: reviewer) · 2026-09-13
|
||||||
|
- **범위**: `git log`/`git diff` **`4d444ce...HEAD`**
|
||||||
|
- **HEAD**: `ebe58f6` `fix(issue-14): record every event on disk before the wire publish`
|
||||||
|
- **선행**: 본 세션 `b0591d20` `[VERDICT: NOT PASS]` — `publish_event` 가 MQTT 재시도 **뒤**에 `events.log` 를 써서 `test_wrapper_idle_timeout_grace_accepts_disk_heartbeat` 가 2/2 실패.
|
||||||
|
- **리뷰 중 소스 무변경.** REBUT 없음 — 지적 수용.
|
||||||
|
|
||||||
|
커밋: `497633f` … `7c40bf4` → `d5a191c` → `952657e` → **`ebe58f6`**.
|
||||||
|
|
||||||
|
## 1. Round-2 차단 항목 반영 (`ebe58f6`)
|
||||||
|
|
||||||
|
| 지적 | 반영 | 교차 확인 |
|
||||||
|
|---|---|---|
|
||||||
|
| `events.log` 를 MQTT `with_retry` **전**에 기록 | `record_local_event` (`publish_event.py:165-175`) 가 `prepare_event` 직후, `publish()` 직전 (`:358-360`) | ✅ |
|
||||||
|
| `DelegationService` 동일 순서 | `service.py:89` local, `:94` publish, `:95-99` outcome | ✅ |
|
||||||
|
| 중복 append 금지 | `record_outcome(..., local_event_recorded=True)` 이면 `registry.append_event` 생략 (`:204-205`). 플래그 기본 `False` 라 다른 호출자는 종전대로 뒤에 기록 | ✅ |
|
||||||
|
| 테스트는 **`publish_event.py` 경로 유지** | `test_wrapper_idle_timeout_grace_accepts_disk_heartbeat` 여전히 `PUBLISH_PY` 사용 | ✅ |
|
||||||
|
| 순서·1회 기록 잠금 | `test_publish_event_records_the_heartbeat_before_the_wire_publish`: `_publish_once` 시점에 이미 `["progress"]`, 이후도 1줄. `test_publish_event_failed_publish_keeps_one_local_record`: 재시도 2회 내내 디스크 1줄, audit `published=False` | ✅ |
|
||||||
|
| VERSIONS.md 항목 6 | "와이어 발행 **전에** 로컬 기록" 으로 정정 | ✅ |
|
||||||
|
|
||||||
|
이전에 2/2 실패하던 래퍼 테스트를 이번 HEAD 에서 관련 스위트에 포함해 다시 돌렸다 → **통과**.
|
||||||
|
|
||||||
|
## 2. 항목 (1)–(6) 재확인
|
||||||
|
|
||||||
|
| # | 판정 |
|
||||||
|
|---|---|
|
||||||
|
| (1) denylist / 설정 상속 | ✅. `CLAUDE_CODE_SSE_PORT` 미포함은 Non-blocking |
|
||||||
|
| (2) `MAM_NO_AUTOSTART` + `ls` | ✅ `7c40bf4` 구조화 `error.code` + `952657e` 그 외 실패는 파서에 안 넣음 (`state unknown`). reconcile `is_empty` 와 정합 |
|
||||||
|
| (3) `send_keys_safe` | ✅ timeout/stalled only accepted; transport_error rc 4; 무신호 rc 4; 재전송 없음 |
|
||||||
|
| (4) R1 | ✅ 디스크 heartbeat(이제 publish **전** 기록) + busy token + working. 창은 관측마다 `IDLE_TIMEOUT` 재개방. 벽시계 `START_TIME+TIMEOUT` (`_within_deadline`). 무응답 ~2×`IDLE_TIMEOUT` 종료는 changelog 에 명시 |
|
||||||
|
| (5) T1-7 `transport_error` | ✅ |
|
||||||
|
| (6) 락스텝 4.4.2 | ✅ `lib.sh` / `eager.py` / 8 SKILL.md / VERSIONS.md / README·BOOTSTRAP·MESSAGING. 릴리스 커밋 `0918917` |
|
||||||
|
|
||||||
|
## 3. 테스트
|
||||||
|
|
||||||
|
```
|
||||||
|
.venv/bin/python -m pytest -q \
|
||||||
|
tests/test_issue14_delivery_ack.py tests/test_issue9_server_env.py \
|
||||||
|
tests/test_issue6_fail_closed.py tests/test_issue6_turn_handshake.py \
|
||||||
|
tests/test_a4_adapter_contract.py tests/test_loop_cli.py \
|
||||||
|
tests/test_issue5_phase4_runtime.py tests/test_version_consistency.py
|
||||||
|
```
|
||||||
|
|
||||||
|
**119 passed in 382.64s.** (직전 HEAD 는 같은 목록에서 1 fail / 116 pass.)
|
||||||
|
|
||||||
|
issue9 함수 9 + issue14 함수 12 = changelog 신규 21과 정합. `bash -n` lib.sh/wrapper 클린. `git diff --check 4d444ce...HEAD` 클린.
|
||||||
|
|
||||||
|
## 4. Non-blocking
|
||||||
|
|
||||||
|
- `CLAUDE_CODE_SSE_PORT` denylist 미포함.
|
||||||
|
- 이미 오염된 herdr 서버는 재기동 전까지 pane 에 마커를 물려줌 (create SKILL.md 명시).
|
||||||
|
- 무응답 잡의 fail-close 가 Issue #6 의 `IDLE_TIMEOUT+5s` 에서 ~2×`IDLE_TIMEOUT` 으로 늘었고 changelog 에 적혀 있음.
|
||||||
|
|
||||||
|
## 5. 종합
|
||||||
|
|
||||||
|
지난 NOT PASS 의 원인(디스크 heartbeat 가 브로커 ACK 뒤에 찍힘)은 CLI·라이브러리 양쪽에서 고쳤고, 같은 `publish_event.py` 경로 테스트가 통과한다. ls unknown 경로와 R1 벽시계는 유지된다. 설계 재작업 불필요.
|
||||||
|
|
||||||
|
[VERDICT: PASS]
|
||||||
Reference in new issue
Block a user