# 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]