Merge-workspace review loop (--all-reviewer): round 1 (@8241bd5) claude grok PASS, agy NOT PASS (two static wrapper-literal tests did not follow _decided/_exit_for), codex NOT PASS (R1: a yes/no decision that could not run read as "no"); fixed in541c3feand65b78b6. Round 2 (@65b78b6) 4/4 PASS. Full suite at65b78b6on macOS / Python 3.9 / herdr 0.9.3: 1730 passed / 0 failed / 56 skipped; 18 of the skips were the uninitialized nats-docker submodule in the fresh worktree, and with it tests/test_deploy_freshness.py is 31 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
5.2 KiB
Review: Issue #17 follow-ups @ 8241bd5
- Role: Reviewer (grok)
- Identity: loop
loop-20261007T224638Z-cf1efb, base56d0bfda54e4f4fe1ccc138cc262edfb14cfb4a3(main), head8241bd53b179cf8332541264c3bf12b8e3eca44a, treeefef640d36f6666f107e188d554c39f05400d4ac, six commits, clean snapshot - Scope:
git diff 56d0bfd HEAD. Seven files, +192/−22,git diff --checkclean. No version bump and noVERSIONS.mdedit. Main stayed56d0bfd. - Verified read-only at
/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261007T224638Z-cf1efb/1. Python 3.9.6 from the follow-up worktree venv, bash 3.2.57, herdr 0.9.3. InheritedHERDR_*,MAM_*, andMQTT_*were unset.HOMEandWORKSPACE_ROOTwere the basetemp..mam.envwas not exported.
1. herdr 0.9.3 restored cwd
test_b_only_the_resumed_sessions_restored_shell_is_closed accepts Y's cwd as either rig.root or rig.root/wsY (tests/test_issue45_restore.py:275-277). The comment names 0.9.1 ($HOME) and 0.9.3 (the old path). The close still does not read cwd.
herdr_restore.py:4-20 says the same thing. SKILL.md describes the close as "same session id, no agent, nothing running" and does not claim the missing directory becomes $HOME. The historical VERSIONS.md line is outside this change, as the task asked.
On 0.9.3 a removed directory comes back as a placeholder: restore_error is set and pane process-info fails with pane_not_found. _nothing_running (herdr_restore.py:58-65) closes that pane. Any other CalledProcessError still propagates, so the run stops and the pane is not closed. A process-info that succeeds still uses _shell_in_foreground (:50-55): a real shell pid in the foreground, and nothing else. The unit tests cover the placeholder, pane_not_found without restore_error, and a different error (tests/test_issue45_restore_unit.py:447-462).
On this Mac the whole tests/test_issue45_restore.py file passed, including Y being closed and X's normal empty shell still being the one that closes, while the user's shell, the live agent, and the busy shell stay. The fixture's HOME is the throwaway rig (test_issue45_restore.py:5-6, :179). ~/.config/herdr/config.toml mtime stayed 1784456394 and the directory mtime stayed 1791382452.
2. A failed decision exits 1
_decided (multi-agent-mux-delegate-job:112-118) keeps the printed answer only when the command exits 0 and the answer is non-empty. Otherwise _decision_failed (:106-109) prints the subcommand and exit 1. _exit_for (:122-126) also requires a decimal answer before exit. cmd_wait uses the same two checks (:1070-1071). finalize-end keeps its fd-3 swap and treats a non-zero status as the same failure (:852-857). An empty answer with status 0 is still accepted there, which is the path that leaves the job unclosed when the wrapper is already gone.
printf -v and [[ =~ ^[0-9]+$ ]] are valid on this bash 3.2.57. The assignment is not inside local, so a failing command substitution is visible to the || branch.
Sourced from base 56d0bfd, the same human submit with a broken exit-code ended at the old line 414: exit: : numeric argument required, rc 255, after a normal wall-clock close. The new _exit_for on that failure, on an empty answer, and on wait-rc rc 127 each exits 1 with could not decide.
subscriber-up stays in if _decide subscriber-up (:358, :530). A non-zero result is "not up", and the following _decided sub-status exits 1 when the module itself is broken. stall-watch stays _decide stall-watch … || return 0 (:692 area, unchanged). A failed watch decision skips the watcher and the job continues; the watcher never closes a job, and turning that skip into exit 1 would fail a job that 7209750 and 56d0bfd would still run. The static guard test_s_no_printed_decision_is_read_raw allows only the _decided capture and the finalize-end capture, and forbids exit "$(.
Successful decisions are unchanged: the old-bash comparison in tests/test_issue17_item4_decisions.py passed, and test_f_the_normal_path_is_unchanged gets rc 3, the audit-log path on the last stdout line, and no could not decide.
3. "Stdlib only"
wrapper.py:24-31 now says this module imports the standard library, and python -m lib_py.delegation.wrapper imports the package first. lib_py/delegation/__init__.py:19-20 imports service, and service.py imports mqtt_common, which imports paho.mqtt.client. The wrapper's $PY already needed paho for the subscriber and publish_event.py. The command line is still _decide at multi-agent-mux-delegate-job:99-101.
4. python3 on PATH
lib_int.sh:9-10 records that mam_int and mam_int_knob run python3 from PATH and, without one, print nothing and return 127. The function bodies are still the two python3 -I calls (:17-18). No caller was switched to $PY.
Tests
--basetemp=/tmp/a652follow.8mWeKg. tests/test_issue17_item4_decisions.py, tests/test_issue33_budget.py, tests/test_issue45_restore_unit.py: 305 passed in 360.13 s.
--basetemp=/tmp/a652herdr.CltSYm. tests/test_issue45_restore.py: 5 passed in 65.96 s. Snapshot git status was empty after both.
[VERDICT: PASS]