fix(followups): F5 - no test switch in the stall watcher
stall_watch read MAM_TEST_UNRELIABLE_AGENT to pretend an adapter's
agent_status was unreliable (PR #41 M7). The branch is gone. S13 now runs
the real stall_watch.main() in a process where the adapter itself reports
agent_status_reliable = False (_UNRELIABLE_MAIN), and checks the same
things as before: no idle notice or nudge, the blocked notice, and the
"idle judgement off" log line. A static check keeps MAM_TEST_ out of the
watcher (fails at 0051fd6). Without the seam S13 fails on this tree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGpJXhSZasJLU38ksDghe
This commit is contained in:
1 parent
fb1b93c665
commit
c252ac4d54
2 files changed
+20
-8
No files matched your search
@@ -225,8 +225,6 @@ class StallWatch(object):
|
|||||||
name = resolve_agent(args.agent, args.target)
|
name = resolve_agent(args.agent, args.target)
|
||||||
adapter = get_adapter(name) if name else None
|
adapter = get_adapter(name) if name else None
|
||||||
reliable = bool(adapter.agent_status_reliable) if adapter else True
|
reliable = bool(adapter.agent_status_reliable) if adapter else True
|
||||||
if os.environ.get("MAM_TEST_UNRELIABLE_AGENT") == args.agent:
|
|
||||||
reliable = False
|
|
||||||
self.st = WatchState(idle_s=float(os.environ.get("MAM_STALL_IDLE_S", "600")), reliable=reliable)
|
self.st = WatchState(idle_s=float(os.environ.get("MAM_STALL_IDLE_S", "600")), reliable=reliable)
|
||||||
self.fail_s = float(os.environ.get("MAM_STALL_HERDR_FAIL_S", "120"))
|
self.fail_s = float(os.environ.get("MAM_STALL_HERDR_FAIL_S", "120"))
|
||||||
self.once = set()
|
self.once = set()
|
||||||
|
|||||||
@@ -193,11 +193,20 @@ def _kill(p: subprocess.Popen) -> None:
|
|||||||
p.wait()
|
p.wait()
|
||||||
|
|
||||||
|
|
||||||
def _watch(env: dict, reg: Path, jid: str, target: str, agent: str) -> subprocess.Popen:
|
# The real watcher's main() in a process whose `agent` adapter reports an
|
||||||
|
# agent_status that cannot drive the idle judgement (S13) - the production
|
||||||
|
# code has no switch for it.
|
||||||
|
_UNRELIABLE_MAIN = ("import sys; from lib_py.agents.registry import get_adapter; "
|
||||||
|
"type(get_adapter(sys.argv[1])).agent_status_reliable = property(lambda self: False); "
|
||||||
|
"import lib_py.stall_watch as sw; sys.exit(sw.main(sys.argv[2:]))")
|
||||||
|
|
||||||
|
|
||||||
|
def _watch(env: dict, reg: Path, jid: str, target: str, agent: str, unreliable: bool = False) -> subprocess.Popen:
|
||||||
tok = _record(reg, jid)["dispatch_token"]
|
tok = _record(reg, jid)["dispatch_token"]
|
||||||
return subprocess.Popen([sys.executable, "-m", "lib_py.stall_watch", "--job", jid,
|
argv = ["--job", jid, "--registry-dir", str(reg), "--target", target, "--agent", agent,
|
||||||
"--registry-dir", str(reg), "--target", target, "--agent", agent,
|
"--expect-dispatch-token", tok]
|
||||||
"--expect-dispatch-token", tok],
|
entry = ["-c", _UNRELIABLE_MAIN, agent] if unreliable else ["-m", "lib_py.stall_watch"]
|
||||||
|
return subprocess.Popen([sys.executable, *entry, *argv],
|
||||||
env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
||||||
|
|
||||||
|
|
||||||
@@ -444,13 +453,12 @@ def test_s12_the_watcher_can_only_publish_progress():
|
|||||||
|
|
||||||
def test_s13_unreliable_agent_status_turns_idle_off_but_keeps_blocked(box):
|
def test_s13_unreliable_agent_status_turns_idle_off_but_keeps_blocked(box):
|
||||||
_, state, reg, env = box
|
_, state, reg, env = box
|
||||||
env["MAM_TEST_UNRELIABLE_AGENT"] = "claude"
|
|
||||||
jid = _job(env, reg)
|
jid = _job(env, reg)
|
||||||
agent = _proc("exec sleep 300")
|
agent = _proc("exec sleep 300")
|
||||||
try:
|
try:
|
||||||
_agent(state, "creator-claude-t", "claude", agent.pid, "idle", _pane("claude"),
|
_agent(state, "creator-claude-t", "claude", agent.pid, "idle", _pane("claude"),
|
||||||
detection="Do you want to proceed?")
|
detection="Do you want to proceed?")
|
||||||
w = _watch(env, reg, jid, "creator-claude-t", "claude")
|
w = _watch(env, reg, jid, "creator-claude-t", "claude", unreliable=True)
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
assert _details(reg, jid) == [] and not _prompts(state)
|
assert _details(reg, jid) == [] and not _prompts(state)
|
||||||
st = json.loads(state.read_text())
|
st = json.loads(state.read_text())
|
||||||
@@ -464,6 +472,12 @@ def test_s13_unreliable_agent_status_turns_idle_off_but_keeps_blocked(box):
|
|||||||
_kill(agent)
|
_kill(agent)
|
||||||
|
|
||||||
|
|
||||||
|
def test_s13_the_unreliable_case_needs_no_switch_in_the_product():
|
||||||
|
"""PR #41 M7: the test sets the adapter up (_UNRELIABLE_MAIN); the watcher
|
||||||
|
reads no environment variable to pretend an adapter is unreliable."""
|
||||||
|
assert "MAM_TEST_" not in STALL_WATCH.read_text()
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# scope - the #34 rule reaches the python herdr calls
|
# scope - the #34 rule reaches the python herdr calls
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in new issue
Block a user