Files
multi-agent-mux/.agents/reports/reviewer-grok-01/report-0d52f435.md
T
GodopuandClaude Opus 5.5 53f87e4560 release(v4.8.0): bump framework and eight skills to 4.8.0 in lockstep; archive PR #41 reviews (three rounds)
Issue #33 (job budget, wall_clock_timeout vs deadline_timeout) and
Issue #30 (notify-only stall watcher). Reviews of PR #41 in the merge
workspace: round 1 (@1673818) claude N1 / codex R1 R2 NOT PASS, agy grok
PASS; round 2 (@af0a2a2) grok N1 / codex D1 D2 NOT PASS, claude agy PASS;
round 3 (@9200562) 4/4 PASS. Reports and the round-3 identity sidecars go
to .agents/reports/<session>/. The design consensus on items A-D is in the
VERSIONS.md entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
2026-09-26 16:08:37 +09:00

49 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🔍 Review Report — Job 0d52f435 (PR #41 @ `1673818`)
- **Reviewer**: `reviewer-grok-01` · 2026-09-26
- **검증 경로**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260926T025230Z-a30a6d/1`
- **identity**: base `8ea65bb` head `1673818` tree `00d5e03` (일치)
- **본 체크아웃**: `main` `8ea65bb` 유지. stall_watch 를 실제 세션에 붙이지 않음.
`git diff --check 8ea65bb...HEAD` 클린. 6커밋.
## 코드
**(1) 예산.** `--timeout` > `MAM_JOB_TIMEOUT_S`(양의 정수, 아니면 경고 후 3600) > 3600. 루프 `contract_args` 가 모든 `_dispatch` 에 `--timeout str(job_budget)` 을 붙인다. `job_wait_s` = 예산 + `MAM_WAIT_GRACE_S`(기본 300). `MAM_CHILD_WAIT_S` 가 있으면 그 값, 없으면 `job_wait_s`. 원격 러너는 `timeout_sec` 초과를 `wall_clock_timeout: …` 로, 관측 실패를 `wall_clock_timeout (remote runner)` 로 닫고 첫 단어 분류가 `CLOSED-UNCONFIRMED` 에 넣는다.
**(2) 라벨.** 구독자 `RC_*` 와 래퍼 `SUB_RC_*` 가 0/1/2/3/4. `test_issue5_phase1_delegation.py` 가 이름과 값을 맞춘다. `finalize_unfinished` 는 rc 4 또는 디스크 유예가 `START_TIME+TIMEOUT` 에 닿으면 `wall_clock_timeout`, 그 외 침묵은 `deadline_timeout`. preflight/idle_wait 는 `cancelled`. `delegate-job wait` 는 rc 4 를 rc 2 로 접는다(G-8). 닫은 뒤 디스크가 `completed` 면 래퍼는 0 으로 돌아간다. 이미 `error` 인 레코드에 늦은 `completed` 는 엔진 터미널 전이가 거부한다.
**(3) 감시자.** `stall_watch.py` 의 유일한 발행은 `_notify` 의 `progress`. `close`/`error`/`cancelled` 호출이 없다. herdr `agent wait`(`watcher.wait_once`)로 상태를 받고, 판단 직전에 `agent get`·process-info·`agent read` 로 자손과 입력창을 본다. `blocked` 는 `stalled:blocked` + detection 한 줄, 키 입력 없음. `idle` 은 `MAM_STALL_IDLE_S`(600), 상주 자식·heartbeat 타이머 제외, 입력창이 비었을 때만 잡당 1회 `stalled:idle` + nudge. 원격·human·`MAM_STALL_WATCH=0` 은 기동하지 않는다. herdr 실패는 경고 후 `MAM_STALL_HERDR_FAIL_S`(120) 에 exit 2. 래퍼는 SIGTERM + `wait`. `.stall.out` 은 로그로 남는다(프로세스는 회수).
**(4) 경계.** 새 bash 판정은 셋이다. 항목 4 이전이 예고돼 있으므로 비차단.
| bash | 하는 일 | 분류 |
|---|---|---|
| `FINALIZE_CLOCK` | 디스크 유예가 벽시계에 닿았는지로 라벨을 고름 | 판정. 구독자 rc 4 는 Python 이 이미 정함 |
| `MAM_JOB_TIMEOUT_S` | 양의 정수가 아니면 3600 | 작은 검증 |
| rc → `close_req` | 2/4/preflight 를 라벨로 매핑 | 나르기. 매핑표는 bash 에 있음 |
**(5) 테스트.** G-8 은 두 시계가 같은 rc 2 였던 단언을 rc 4(벽시계)로 고쳤다. 새 테스트는 mock herdr·tmp. 1회차 스위트에서 `test_b3_a_heartbeating_job…` 가 공개 브로커가 heartbeat 를 놓쳐 구독자는 idle 로 끝났고(래퍼 라벨은 이미 `wall_clock_timeout`), 재실행은 **1 passed in 18s**.
**(6)–(7)** loop SKILL 하위 위임 절이 `wall_clock_timeout` 을 `CLOSED-UNCONFIRMED` 에 넣는다. delegate-job/loop SKILL 에 `--job-timeout`·`MAM_JOB_TIMEOUT_S`·감시자 변수가 있다. 4.8.0 bump 는 오케스트레이터 예정.
## 설계 합의
**(A) 동의.** 갱신 1(알림만, 자동 수락 없음, 판정으로 닫지 않음)을 `stall_watch.py` 가 강제한다. 종결은 #33 시계뿐이다.
**(B) 동의.** 러너가 래퍼를 동기 호출하므로 연장 정책을 그 안에서 물을 수 없다. #39 위험은 에이전트가 `progress` 로 연장을 반복하는 것이다. 보완: 연장 횟수 상한을 프로토콜과 별개로 두고, heartbeat 만 있고 `state_change_seq` 가 그대로면 거절한다.
**(C) 조건부 동의.** 트리거는 `completed` 를 검증하는 쪽이어야 한다. 워크트리 creator(`MAM_NO_SUBSCRIBER_DAEMON=1`)도 잡마다 래퍼 구독자가 `completed` 를 받으므로 핀은 그 구독자가 맞고, 루프 `wait_for_job` 은 구독자가 없을 때의 보조다. 항목 4 가 종결 처리를 Python 으로 옮긴 그 함수에 붙이면 된다.
**(D) 동의.** 라벨 분리만으로 #33 은 성립하고, 종결 처리 이전은 더 큰 변경이다. 항목 4 때 Python 으로 옮길 것은 `FINALIZE_CLOCK` 선택, `MAM_JOB_TIMEOUT_S` 검증, rc→`close_req` 매핑이다. bash 에는 `start_stall_watch`/`stop_stall_watch` 와 키 주입만 남긴다.
## 테스트
`test_issue30_stall_watch.py` + `test_issue33_budget.py` + `test_tier1_unit.py`: **1 failed, 86 passed, 48 skipped**, 이어서 실패 1건 재실행 **passed**.
## 종합
#33 두 시계와 #30 알림 전용이 코드와 맞다. bash 의 라벨 선택은 예고된 이전이 남았고 병합을 막지 않는다.
[VERDICT: PASS]