test(followups): F1 - A8 writes the marker lstart as loop_lock.sh reads it

`ps -o lstart=` pads a one-digit day ("Oct  1"); loop_lock.sh's mam_lstart
squeezes the spaces before comparing, but A8 wrote the raw value, so the
live holder's marker looked stale and the second loop was not refused on
the 1st-9th of every month. The test now normalises like the product (the
product is unchanged) and also runs with a `ps` shim that always prints a
padded lstart, so the padded case is checked on every date.

The other tests that record a live lstart (test_o3_scoped_guard
_get_lstart) already normalise; test_o2's markers carry fixed stale values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGpJXhSZasJLU38ksDghe
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-02 08:08:26 +09:00
1 parent 0051fd6c3b
commit 75936f11c6
1 file changed
+34 -5
+34 -5
View File
@@ -16,6 +16,8 @@ import subprocess
import time import time
from pathlib import Path from pathlib import Path
import pytest
from test_issue21_loop_b import LOCAL_ROWS, _drive, _reviews, _sidecars, _state from test_issue21_loop_b import LOCAL_ROWS, _drive, _reviews, _sidecars, _state
from test_issue21_phase2_loop_a import (REM, _calls, _prepare, _resume, _rows, _run, _skill, _wt, # noqa: F401 from test_issue21_phase2_loop_a import (REM, _calls, _prepare, _resume, _rows, _run, _skill, _wt, # noqa: F401
ctl) ctl)
@@ -253,19 +255,46 @@ def test_a7_reviewer_test_output_stays_out_of_the_source_and_the_sandbox(wt_repo
# A8 ------------------------------------------------------------------------- # A8 -------------------------------------------------------------------------
def test_a8_second_loop_is_refused_before_a_scheduler_exists(ctl): # `ps -o lstart=` pads a one-digit day with a second space ("Oct 1"); this
# stands in for it so the padded case runs on every date, not only on the 1st-9th.
_PADDED_PS = """#!/bin/sh
case " $* " in
*" lstart= "*) out=$(/bin/ps "$@") || exit $?; [ -n "$out" ] && echo "Thu Oct 1 08:02:03 2026"; exit 0 ;;
esac
exec /bin/ps "$@"
"""
def _marker_lstart(pid: int, env: dict) -> str:
"""The lstart a marker records, normalised as loop_lock.sh's mam_lstart does
(`tr -s ' '`, ends trimmed) - the raw value keeps the padding and never matches."""
out = subprocess.run(["ps", "-p", str(pid), "-o", "lstart="], capture_output=True, text=True, env=env).stdout
return " ".join(out.split())
@pytest.mark.parametrize("ps", ["real", "padded"])
def test_a8_second_loop_is_refused_before_a_scheduler_exists(ctl, tmp_path, ps):
main = ctl main = ctl
wt2 = _wt(main, "wt2") wt2 = _wt(main, "wt2")
_g(main, "worktree", "add", "-q", "--detach", str(wt2)) _g(main, "worktree", "add", "-q", "--detach", str(wt2))
env = {**os.environ, "WORKSPACE_ROOT": str(main), "MAM_LOOP_NO_FREEZE": "1"}
env.pop("MAM_LOOP_PY", None)
if ps == "padded":
shim = tmp_path / "ps-shim"
shim.mkdir()
(shim / "ps").write_text(_PADDED_PS)
(shim / "ps").chmod(0o755)
env["PATH"] = f"{shim}{os.pathsep}{env['PATH']}"
holder = subprocess.Popen(["sleep", "60"]) holder = subprocess.Popen(["sleep", "60"])
try: try:
lstart = subprocess.run(["ps", "-p", str(holder.pid), "-o", "lstart="], capture_output=True, lstart = _marker_lstart(holder.pid, env)
text=True).stdout.strip() assert lstart, "ps found no holder"
if ps == "padded":
assert lstart == "Thu Oct 1 08:02:03 2026", f"the shim was not used: {lstart!r}"
marker = main.parent / f"{main.name}-loop-marker" marker = main.parent / f"{main.name}-loop-marker"
content = f"pid={holder.pid}\nlstart={lstart}\nstarted={time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}\n" content = f"pid={holder.pid}\nlstart={lstart}\nstarted={time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}\n"
marker.write_text(content) marker.write_text(content)
env = {**os.environ, "WORKSPACE_ROOT": str(main), "MAM_LOOP_MARKER": str(marker), "MAM_LOOP_NO_FREEZE": "1"} env["MAM_LOOP_MARKER"] = str(marker)
env.pop("MAM_LOOP_PY", None)
res = subprocess.run(["bash", _skill(main, "multi-agent-mux-loop", "scripts", "run_loop.sh"), res = subprocess.run(["bash", _skill(main, "multi-agent-mux-loop", "scripts", "run_loop.sh"),
"--creator", "c", "--task", "t", "--worktree", str(wt2), "--base", "HEAD", "--creator", "c", "--task", "t", "--worktree", str(wt2), "--base", "HEAD",
"--review-only", "--reviewer", "r"], "--review-only", "--reviewer", "r"],