From 35860f4bf8f71410c4cfaa54daab332cf8743671 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 16:46:13 -0700 Subject: [PATCH] Worker: a command that never exits is stopped and reported, not a crash Docscope's fix round ran 'python -m http.server' to test its page; the 600s timeout raised and took the whole round down. The run tool now stops a command after TIME_RUN_TIMEOUT (default 180s) and tells the model to use one-shot commands. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UpT7eWzeLhRwuYmsSQnbRb --- .github/time/test_time.py | 10 ++++++++++ .github/time/time.py | 7 ++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/time/test_time.py b/.github/time/test_time.py index cfcf1e3..739210a 100644 --- a/.github/time/test_time.py +++ b/.github/time/test_time.py @@ -715,3 +715,13 @@ vt.tm.think = lambda *a: (_ for _ in ()).throw(RuntimeError("POST x -> 429: over assert vt.judge_product(w16)[0] == [] and "skipped" in vt.judge_product(w16)[1] vt.tm.think = seat_brain print("ALL OK 21") + +# 30 a worker command that never exits is stopped and reported to the model, not a crash +os.environ["TIME_RUN_TIMEOUT"] = "1" +h = tm.Hands.__new__(tm.Hands) +h.n, h.branch, h.pr, h.steps, h.checkout = 1, "b", None, 0, None +h._checkout = lambda: os.getcwd() +out = h.call("run", {"command": "sleep 5"}) +assert out.startswith("timed out after 1s") and "one-shot" in out, out +os.environ.pop("TIME_RUN_TIMEOUT") +print("ALL OK 22") diff --git a/.github/time/time.py b/.github/time/time.py index 9276c5d..25571d5 100644 --- a/.github/time/time.py +++ b/.github/time/time.py @@ -466,7 +466,12 @@ class Hands: self.checkout = self._checkout() # fresh: see the latest writes # Cards and venture inputs can carry third-party text, so the shell the model drives sees no secrets. clean = {k: v for k, v in os.environ.items() if not re.search(r"TOKEN|KEY|SECRET|PASSWORD|ACTIONS_", k, re.I)} - p = subprocess.run(["bash", "-lc", a["command"]], cwd=self.checkout, capture_output=True, text=True, timeout=600, env=clean) + limit = int(os.environ.get("TIME_RUN_TIMEOUT") or 180) + try: + p = subprocess.run(["bash", "-lc", a["command"]], cwd=self.checkout, capture_output=True, text=True, timeout=limit, env=clean) + except subprocess.TimeoutExpired: # a server or watcher never exits: tell the model, don't crash the card + return (f"timed out after {limit}s and was stopped. Servers and watchers never exit; run one-shot commands " + f"(a parser, a test script, node -e '...') instead") sha = subprocess.run(["git", "rev-parse", "HEAD"], cwd=self.checkout, capture_output=True, text=True).stdout.strip() # GitHub does not run pull_request workflows for commits made with the Actions token, so the worker's own # test run is recorded as a commit status; land() counts statuses as checks.