refactor(issue-17): item 4 - the delegate-job wrapper's decisions move to Python #51

Merged
Godopu merged 9 commits from refactor/issue-17-item4 into main 2026-10-07 16:37:53 +00:00
9 Commits
Author SHA1 Message Date
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
GodopuandClaude Opus 5.5 4c86107846 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
2026-10-08 00:53:09 +09:00
GodopuandClaude Opus 5.5 518bedac5d fix(issue-17): review R1 round 2 - an exited, unreaped wrapper is not a live owner
kill(pid, 0) succeeds for a zombie. A caller that captures the wrapper's
output and calls communicate() after TERM leaves the wrapper unreaped while
the finalizer holds its pipes, so the owner check passed until the deadline
and the job was still closed (codex, round 2; reproduced with the real
registry). _alive now asks `ps -o stat=` (POSIX, no /proc) once kill(0)
succeeds and treats state Z as gone, as tests/conftest.py::_pid_alive does;
no ps answer keeps kill(0)'s verdict. The owner is looked at every 0.5 s.

Tests: TERM + communicate() with no wait() for both graces (stand-ins) and
for the timeout grace with the real registry, old vs new; a zombie is not
alive. All four fail on c5cebe6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 08:09:13 +00:00
GodopuandClaude Opus 5.5 c5cebe6c32 fix(issue-17): review R1 - the finalizer ends with its wrapper
finalize-end ran the disk grace and the broker re-observation as a child
of the wrapper; TERM to the wrapper left it running, and at the deadline it
still closed the job and published the error (codex R1, reproduced with the
real registry). The bash loops it replaced ended with the wrapper.

The wrapper now passes its own pid (--watch-pid "$$", as for the stall
watcher). finalize-end checks it every 0.2 s through both waits and before
the close and the event, and leaves without either once it is gone.
A comparison test sends TERM to the old and the new wrapper inside each
grace: both exit at once, leave no process behind and make no call.

Also: no blank line at the end of the old-decisions fixture, and the #42
inventory follows main() one line down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 07:02:26 +00:00
GodopuandClaude Opus 5.5 66d1490230 test(issue-17): item 4 - l15's stand-in control root carries lib_py/ints.py next to lib_int.sh
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 05:37:02 +00:00
GodopuandClaude Opus 5.5 6947d3c785 test(issue-17): item 4 - the #42 inventory follows runner.py's shorter header
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 05:36:48 +00:00
GodopuandClaude Opus 5.5 3b3ce307df test(issue-17): item 4 - the #42 inventory points at main() where it now is
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 05:36:23 +00:00
GodopuandClaude Opus 5.5 6bf9f92462 test(issue-17): item 4 - the frozen-mapping test imports the wrapper module directly (it has no scripts/ shim)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 05:08:35 +00:00
GodopuandClaude Opus 5.5 63d9c205ff refactor(issue-17): item 4 - the delegate-job wrapper's decisions move to Python
The wrapper keeps spawn / wait / kill, key injection and the herdr
diagnostic probe; what it decided in bash is now lib_py/delegation/wrapper.py,
reached through one `_decide` helper:

- finalize_unfinished: the clock choice, the disk grace and broker
  re-observation, the close request / label, the close and the event
  (finalize-begin / finalize-end; bash runs only the busy probe between them)
- start_stall_watch: whether to watch (MAM_STALL_WATCH, remote, human)
- _map_sub_rc, _rc_for (+ MAM_DELEGATE_FAIL_CLOSED), the subscriber
  early-exit check and cmd_wait's rc normalisation
- mam_int / mam_int_knob run lib_py/ints.py, which is also the runner's
  _positive_int: one implementation of the Issue #26 rule

No behaviour change: tests/test_issue17_item4_decisions.py runs the old
bash functions (copied verbatim from 7209750) and the new wrapper on the
same inputs and compares output, FINAL_JOB_STATUS and the registry /
publish calls. Three static tests that pinned the old bash literals now
pin the Python entry points instead.

Refs #17

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 04:59:58 +00:00