Files
multi-agent-mux/.agents/reports/reviewer-grok-01/report-b78ad46e.md
T
GodopuandClaude Opus 5.5 8fde39be33 release(v4.8.6): Issue #17 item 4 - archive PR #51 reviews and bump the lockstep version
Merge-workspace review: round 1 (@518beda) claude agy grok PASS, codex
NOT PASS (finalize wait measured on the wall clock); fixed in 4c86107.
Round 2 delta (@4c86107) claude agy grok PASS; codex (24b21b9c, after
817d1650 closed deadline_timeout with no report) found R1 closed and no
new defect, but withheld PASS only because its sandbox could not bind
the suite's loopback broker. The same two-file suite run here at
4c86107: 278 passed. Full suite at 518beda on macOS / Python 3.9:
1711 passed / 1 failed / 38 skipped; the failure
(test_issue45_restore, herdr 0.9.3 cwd restore) also fails on main.

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

3.9 KiB
Raw Blame History

Review: PR #51 round 2 @ 4c86107

  • Role: Reviewer (grok)
  • Identity: loop loop-20261007T155310Z-56d5a7, base 518bedac5d8ab832347bfc6682b146f3201021f1, head 4c86107846d1e037f9a69a1201257725e8673179, tree e6f67f6136b8f0cec15ce98400ae7d7710cedf1e, one commit, clean snapshot
  • Scope: git diff 518beda HEAD. Two files, +43/−3, git diff --check clean. Main stayed 7209750.
  • Verified read-only at /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261007T155310Z-56d5a7/1. Python 3.9.6 from the pr-51 venv. Inherited HERDR_*, MAM_*, and MQTT_* were unset. HOME and WORKSPACE_ROOT were the basetemp. .mam.env was not exported.

Codex R1

Codex 4c86107
R1. _sleep measured the remaining time with time.time(). A wall clock stepped back during the broker re-observe (up to 3 s) or the disk-heartbeat grace (1 s) stretched that one wait by the same amount. A 10 s step back turned 1 s into 11 s and 3 s into 13 s. Bash sleep 1 / sleep "$left" does not follow the wall clock. _sleep (wrapper.py:145-156) sets end = time.monotonic() + seconds and computes left from time.monotonic(). The 0.5 s owner poll is min(left, 0.5) on that same remainder. test_u_a_wait_is_not_stretched_by_a_wall_clock_step_back steps the wall clock back 10 s on the first sleep for both 1 s and 3 s.

Wall clock stays the deadline

The monotonic clock is used only inside _sleep (:150, :153). Everything that decides whether the job is finished still reads the wall clock:

  • _now is int(time.time()) (:45-46), the same value bash's $(date +%s) returns.
  • finalize_begin builds deadline and evidence_until from _now (:182-184).
  • The broker loop takes left = deadline - _now() and only then calls _sleep(a, min(left, 3)) (:208-211). After the sleep it labels the clock wall when _now() >= deadline (:218).
  • The grace loop's condition, the heartbeat reopen, and the idle-window check all use _now (:226-240). The sleep inside that loop is _sleep(a, 1) (:239).
  • recent_disk_heartbeat still ages the events.log timestamp with time.time() (:115).

A wall step back during one sleep no longer lengthens that sleep. The next loop pass still sees the stepped wall clock and can sleep again until START_TIME + TIMEOUT, which is what the old bash loop did after each fixed sleep. A wall step forward is noticed on the next _now() check, after the current monotonic slice returns. The owner poll does not become a deadline: it only splits the slice _sleep was given.

subprocess.run(..., timeout=10) on ps (:133-134) is unchanged and is not the job deadline.

The test

_SteppedClock (tests/test_issue17_item4_decisions.py:598-616) is the module's time. sleep(dt) adds dt to both clocks and to slept, and subtracts 10 s from the wall clock once. There is no real time.sleep and no thread. monkeypatch.setattr(decide, "time", clock) (:628) replaces the import time the wrapper calls (wrapper.py:35).

For 1 s the fake clock records two 0.5 s sleeps (slept == 1). For 3 s it records six (slept == 3). 0.5 is exact in binary floating point, so the result does not depend on the scheduler. The bound seconds <= slept <= seconds + 0.5 (:630) rejects the old 11 s / 13 s waits. watch_pid=None skips the process check. The same two durations are the ones finalize_end passes: min(left, 3) and 1.

Scope

The commit changes _sleep and adds this test. No label, registry write, event, or stall-watch decision moves. The notes left for a later change (the wrapper importing a package that loads paho, exit "" → 255, lib_int.sh using python3 on PATH, and the 0.2 s text versus the 0.5 s poll) are not in this diff.

Tests

--basetemp=/tmp/b78afollow.yeVKnK. tests/test_issue17_item4_decisions.py and tests/test_issue33_budget.py: 278 passed in 318.09 s, exit 0. Snapshot git status was empty after the run.

[VERDICT: PASS]