From d4e24ed5bb2d883f25d0ab62c2126d574e278e45 Mon Sep 17 00:00:00 2001 From: axisrow Date: Sun, 2 Aug 2026 15:09:02 +0800 Subject: [PATCH] fix: forward turnTimeoutMs to adversarial-review's runAppServerTurn call adversarial-review parses --turn-timeout-ms but never applied it, so long reviews silently fell back to the library's 600000ms default instead of the requested budget (or the 110000ms foreground default). The native review path and task path already forwarded turnTimeoutMs correctly; only the adversarial branch's runAppServerTurn call dropped it. Closes #38 Co-Authored-By: Claude Sonnet 5 --- plugins/codex/scripts/codex-companion.mjs | 1 + tests/runtime.test.mjs | 27 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/plugins/codex/scripts/codex-companion.mjs b/plugins/codex/scripts/codex-companion.mjs index f33c0e32..d88f603f 100644 --- a/plugins/codex/scripts/codex-companion.mjs +++ b/plugins/codex/scripts/codex-companion.mjs @@ -470,6 +470,7 @@ async function executeReviewRun(request) { outputSchema: readOutputSchema(REVIEW_SCHEMA), onProgress: request.onProgress, persistThread: true, + turnTimeoutMs: request.turnTimeoutMs, threadName: `Codex Companion Review: ${context.target.label}`.slice(0, 80) }); const parsed = parseStructuredOutput(result.finalMessage, { diff --git a/tests/runtime.test.mjs b/tests/runtime.test.mjs index 9cef5b53..591a0bd9 100644 --- a/tests/runtime.test.mjs +++ b/tests/runtime.test.mjs @@ -3254,3 +3254,30 @@ test("task with in-item output-delta progress longer than the budget does NOT ti const storedJob = readPersistedJob(repo); assert.equal(storedJob.status, "completed", "job must complete, not be killed mid-item"); }); + +test("adversarial review with stalled turn/start times out via --turn-timeout-ms instead of hanging on the 600s default", () => { + const repo = makeTempDir(); + const binDir = makeTempDir(); + installFakeCodex(binDir, "stalled-turn-start"); + initGitRepo(repo); + fs.writeFileSync(path.join(repo, "README.md"), "hello\n"); + run("git", ["add", "README.md"], { cwd: repo }); + run("git", ["commit", "-m", "init"], { cwd: repo }); + + const start = Date.now(); + // adversarial-review routes through runAppServerTurn (unlike native `review`, + // which uses runAppServerReview). turnTimeoutMs must reach that call too — + // without it, this hangs toward the library's 600000ms default instead of + // the 3s budget requested here. + const result = run("node", [SCRIPT, "adversarial-review", "--turn-timeout-ms", "3000"], { + cwd: repo, + env: buildEnv(binDir) + }); + const elapsedMs = Date.now() - start; + + assert.notEqual(result.status, 0, "must exit non-zero on timeout, not hang"); + assert.match(result.stderr, /turn budget/i, "error must mention the turn budget"); + assert.ok(elapsedMs < 15000, `must time out close to the requested budget, not the 600s default (took ${elapsedMs}ms)`); + const storedJob = readPersistedJob(repo); + assert.equal(storedJob.status, "failed", "job must be marked failed"); +});