fix(scripts): set the tsgo watchdog default from measured lane duration

ClawSweeper on c7a699ee82 reversed its earlier guidance: the opt-in default
adopted last iteration "deliberately preserves the indefinite tsgo hang that
this PR is meant to fix". Its objection was never that a default existed, only
that 45 minutes was unmeasured.

Measured instead of guessed: hosted tsgo lanes (check-test-types, and its core
stripes) complete in 1-2 minutes across recent successful main runs, against CI
job caps of 15-20 minutes. 30 minutes is 15-30x the observed duration, leaves
room for a far slower local host, and still bounds the 90-minute and multi-hour
wedges that motivated this PR. OPENCLAW_TSGO_TIMEOUT_MS remains the documented
override for hosts that need longer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jesse Merhi
2026-08-17 16:33:28 +10:00
parent c7a699ee82
commit 0d9f3604e8
3 changed files with 17 additions and 14 deletions
+6 -5
View File
@@ -694,11 +694,12 @@ Native dependency policy:
after 5 minutes with no stdout or stderr output. Set
`OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=0` to disable the watchdog for
an intentionally silent investigation.
- `scripts/run-tsgo.mjs` waits indefinitely by default. Set
`OPENCLAW_TSGO_TIMEOUT_MS` to bound a run on hosts where a wedged
compiler would otherwise block its caller forever; on expiry the whole
tsgo process tree is killed and the run fails. Values above Node's
timer ceiling saturate instead of collapsing to a 1ms deadline.
- `scripts/run-tsgo.mjs` terminates a tsgo run after 30 minutes, so a
wedged compiler fails loudly instead of blocking its caller forever.
Hosted tsgo lanes finish in 1-2 minutes; raise
`OPENCLAW_TSGO_TIMEOUT_MS` on a slower host. On expiry the whole tsgo
process tree is killed and the run fails. Values above Node's timer
ceiling saturate instead of collapsing to a 1ms deadline.
</Accordion>
+10 -8
View File
@@ -16,6 +16,12 @@ import {
shouldSkipSparseTsgoGuardError,
} from "./lib/tsgo-sparse-guard.mts";
/**
* Hosted tsgo lanes finish in 1-2 minutes and their CI jobs cap at 15-20, so 30
* leaves headroom for a far slower local host while still bounding a wedge that
* would otherwise never report. Raise OPENCLAW_TSGO_TIMEOUT_MS for slower hosts.
*/
const DEFAULT_TSGO_TIMEOUT_MS = 30 * 60 * 1000;
/** Node's timer ceiling: a longer delay silently becomes 1ms, so a raised override must saturate. */
const MAX_TSGO_TIMEOUT_MS = 2_147_483_647;
@@ -49,14 +55,10 @@ async function main(): Promise<void> {
}
ensureRepoToolNodeModulesLink(tsgoPath);
// Opt-in deadline: no supported duration contract covers every host and project,
// so an unset value keeps the pre-existing unbounded wait rather than guessing one.
const timeoutMs = env.OPENCLAW_TSGO_TIMEOUT_MS?.trim()
? Math.min(
readPositiveEnvInt("OPENCLAW_TSGO_TIMEOUT_MS", env, MAX_TSGO_TIMEOUT_MS),
MAX_TSGO_TIMEOUT_MS,
)
: undefined;
const timeoutMs = Math.min(
readPositiveEnvInt("OPENCLAW_TSGO_TIMEOUT_MS", env, DEFAULT_TSGO_TIMEOUT_MS),
MAX_TSGO_TIMEOUT_MS,
);
try {
// Managed run owns the whole tsgo process tree: on timeout it SIGKILLs the
// process group, because a wedged checker ignores SIGTERM and would otherwise
+1 -1
View File
@@ -277,7 +277,7 @@ describe.skipIf(process.platform === "win32")("run-tsgo watchdog", () => {
expect(result.stderr.trim().split("\n").at(-1)).toBe("[tsgo] FAILED (exit 1)");
}, 30_000);
it("arms no watchdog until an operator opts in", () => {
it("leaves a healthy run alone under the default deadline", () => {
const cwd = createTempDir("openclaw-run-tsgo-watchdog-");
writeFakeTsgo(cwd, "#!/bin/sh\nsleep 2\nexit 0\n");