fix(issue-17): review R1 - a finalize wait is measured on the monotonic clock, like bash's sleep

codex, PR #51 round 1. wrapper._sleep computed the span and the remainder
with time.time(). The broker re-observation (up to 3 s) and the disk-heartbeat
grace (1 s) use it, so a wall clock stepped back during the wait stretched it
by the step: on a mocked clock stepped back 10 s, an already completed job was
seen after 11 s / 13 s instead of 1 s / 3 s. The old bash ran `sleep 1` /
`sleep "$left"`, which do not follow the wall clock.

_sleep now measures on time.monotonic(). The deadline (START_TIME + TIMEOUT),
the evidence window and event timestamps stay on the wall clock (_now), as in
the bash.

test_u_a_wait_is_not_stretched_by_a_wall_clock_step_back (1 s, 3 s) swaps the
module's time for a clock stepped back 10 s during the first sleep; on the
previous code it measures 11.0 / 13.0 and fails. The comparison test and the
finalize-related behaviour tests (issue33, issue18, issue14) on macOS /
Python 3.9: 321 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-08 00:53:09 +09:00
1 parent 518bedac5d
commit 4c86107846
2 files changed
+43 -3

No files matched your search

+37
View File
@@ -591,3 +591,40 @@ def test_c_an_unreaped_wrapper_leaves_the_real_record_alone(tmp_path):
time.sleep(6)
states.append((rc, took < 4.5, json.loads((reg / f"{jid}.json").read_text())["status"]))
assert states[0] == states[1] == (-15, True, "pending"), states
# --- review R1 (codex): a wall clock stepped back does not stretch a wait ----
class _SteppedClock:
"""A `time` stand-in: wall and monotonic both advance on sleep(), and the
wall clock is stepped back once, during the first sleep."""
def __init__(self, step_back: float):
self.wall, self.mono, self.step_back, self.slept = 1000.0, 50.0, step_back, 0.0
def time(self):
return self.wall
def monotonic(self):
return self.mono
def sleep(self, dt):
self.wall += dt
self.mono += dt
self.slept += dt
if self.step_back:
self.wall -= self.step_back
self.step_back = 0
@pytest.mark.parametrize("seconds", [1, 3])
def test_u_a_wait_is_not_stretched_by_a_wall_clock_step_back(monkeypatch, seconds):
"""The broker re-observation (up to 3 s) and the disk-heartbeat grace (1 s)
re-read the record after `seconds`, as bash's `sleep N` did, even when the
wall clock steps back 10 s meanwhile (on the old wall-clock arithmetic the
wait became seconds + 10)."""
import argparse
clock = _SteppedClock(step_back=10)
monkeypatch.setattr(decide, "time", clock)
decide._sleep(argparse.Namespace(watch_pid=None), seconds)
assert seconds <= clock.slept <= seconds + 0.5, clock.slept