test(#4522): migrate core CLI/domain state batch to named timeout constants (#4662)

Batch 11 of the ad hoc timeout literal migration (epic #4445). Replaces
every bare numeric timeout/timeoutMs object-literal property in
tests/state-document.test.cjs, tests/phase.test.cjs, tests/commands.test.cjs,
tests/pattern.test.cjs, tests/adr-612-bracket-coherence.test.cjs,
tests/adr-612-bracket-read-tolerance.test.cjs, tests/milestone-lock.test.cjs,
tests/init.test.cjs, tests/state-todos-render.test.cjs,
tests/quick-batch.test.cjs, tests/graphify.test.cjs, and
tests/effort-surface-axis.test.cjs with a named constant, per
eslint-rules/no-adhoc-timeout-literal.cjs. Removes these 12 files from the
rule's allowlist.

Ground truth via eslint found 25 sites, not the issue's stated 24 (phase.test.cjs
has 5, not 4) -- disclosed in the PR body.

Reuses PROBE_TIMEOUT_MS, GIT_TIMEOUT_MS, and LOOP_HOOK_POINT_CLI_TIMEOUT_MS
across 8 files. Adds two new shared constants to tests/helpers/timeouts.cjs
(each independently arrived at by 2 files in this batch, crossing the
promotion bar): PATHOLOGICAL_INPUT_TEST_TIMEOUT_MS (node:test's own per-test
timeout option, not a subprocess bound) and GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS
(a single gsd-tools.cjs CLI subcommand spawn, distinct tier from
PROBE_TIMEOUT_MS/LOOP_HOOK_POINT_CLI_TIMEOUT_MS). Adds 3 file-local constants
for values used by only 1 file in this batch. No src/bin file touched, no
numeric value changed anywhere.

Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-09-12 09:12:31 -04:00
committed by GitHub
parent 241646a43a
commit c99d7bb2be
14 changed files with 103 additions and 38 deletions

View File

@@ -24,6 +24,7 @@ const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const { PATHOLOGICAL_INPUT_TEST_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
let tmpDir;
@@ -526,7 +527,7 @@ ${BROKEN_HEADINGS.map(([, h]) => `${h}\n**Goal:** x\n`).join('\n')}
// hang backstop, not an assertion: it turns a runaway into a deterministic
// failure instead of a suite that never returns.
for (const width of [4000, 16000]) {
test(`a pathological unclosed bracket (${width} chars) validates correctly`, { timeout: 60_000 }, () => {
test(`a pathological unclosed bracket (${width} chars) validates correctly`, { timeout: PATHOLOGICAL_INPUT_TEST_TIMEOUT_MS }, () => {
writeProject({ roadmap: `# Roadmap
## [GSD.02] v2.0 — Expansion

View File

@@ -28,6 +28,7 @@ const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const { PATHOLOGICAL_INPUT_TEST_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
let tmpDir;
@@ -1032,7 +1033,7 @@ ${MALFORMED.map(([, h]) => `${h}\n**Goal:** x\n`).join('\n')}`, 'bracket');
};
};
test('pathological bracket input reads correctly at 1x and 4x length', { timeout: 60_000 }, () => {
test('pathological bracket input reads correctly at 1x and 4x length', { timeout: PATHOLOGICAL_INPUT_TEST_TIMEOUT_MS }, () => {
for (const [label, doc, expectedPhases] of ATTACKS) {
const readings = [5000, 20000].map((n) => [n, readAll(doc(n))]);
for (const [n, r] of readings) {

View File

@@ -18,6 +18,7 @@ const { splitLines } = require('../gsd-core/bin/lib/text-lines.cjs');
const fc = require('./helpers/fast-check-setup.cjs');
const { gitOrThrow, throwIfFailed } = require('./helpers/git-fixture.cjs');
const { runNode } = require('./helpers/process-seam.cjs');
const { GIT_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
describe('history-digest command', () => {
let tmpDir;
@@ -3199,7 +3200,7 @@ describe('commit-docs-guard hook script (#3588 A1-A5)', () => {
const probe = spawnSync('git', ['config', '--get', 'core.hooksPath'], {
cwd: tmpDir,
encoding: 'utf-8',
timeout: 15_000,
timeout: GIT_TIMEOUT_MS,
});
assert.notEqual(probe.status, 0, `a child git must not see a host core.hooksPath; got: ${probe.stdout}`);
assert.ok(fs.existsSync(hookPath), 'the beforeEach enable installed the hook at the repo-local default path');
@@ -4322,6 +4323,7 @@ const os = require('node:os');
const path = require('path');
const { spawnSync } = require('node:child_process');
const { cleanup } = require('./helpers.cjs');
const { GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
const REPO_ROOT = path.join(__dirname, '..');
const COMMAND_ALIASES_FILE = path.join(
@@ -4450,7 +4452,7 @@ function runGsdTools(args, projectDir) {
return spawnSync(process.execPath, [GSD_TOOLS, ...args], {
cwd: projectDir,
encoding: 'utf8',
timeout: 30000,
timeout: GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS,
killSignal: 'SIGKILL',
});
}

View File

@@ -24,6 +24,7 @@ const cp = require('node:child_process');
const fc = require('fast-check');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const { LOOP_HOOK_POINT_CLI_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
const REPO_ROOT = path.resolve(__dirname, '..');
const {
@@ -663,7 +664,7 @@ describe('#2481 review workflow resolves effort per reviewer', () => {
{
cwd: projectDir,
encoding: 'utf8',
timeout: 60000,
timeout: LOOP_HOOK_POINT_CLI_TIMEOUT_MS,
killSignal: 'SIGKILL',
env: { ...process.env, PATH: `${bin}${path.delimiter}${process.env.PATH}` },
},

View File

@@ -100,6 +100,15 @@ function saveSurfacedEnv() {
// Require capability-state to assert gate parity in regression tests below.
const { isCapabilityActive } = require('../gsd-core/bin/lib/capability-state.cjs');
/**
* NOT a real subprocess timeout. spawnSync is fully mocked in this test --
* this is test-input/fixture data proving an explicit timeout override is
* correctly forwarded from execGraphify's options into the (fake) spawnSync
* call. Renamed at BOTH the call site and the assertion site so the
* override-forwarding check keeps its teeth.
*/
const MOCK_TIMEOUT_OVERRIDE_FIXTURE_MS = 60000;
describe('status', () => {
// ─── Tri-state gate (Phase 3 cutover from isGraphifyEnabled → isCapabilityActive) ──
//
@@ -535,8 +544,8 @@ describe('build', () => {
return { status: 0, stdout: '', stderr: '', error: undefined, signal: null };
});
execGraphify('/tmp', ['build'], { timeout: 60000 });
assert.strictEqual(captured.timeout, 60000);
execGraphify('/tmp', ['build'], { timeout: MOCK_TIMEOUT_OVERRIDE_FIXTURE_MS });
assert.strictEqual(captured.timeout, MOCK_TIMEOUT_OVERRIDE_FIXTURE_MS);
});
test('trims stdout and stderr whitespace', () => {

View File

@@ -265,6 +265,41 @@ const GENERATOR_SCRIPT_TIMEOUT_MS = 30000;
*/
const REAL_REPO_GIT_TIMEOUT_MS = 30000;
/**
* NOT a subprocess spawn timeout. This is `node:test`'s own per-test
* `{ timeout }` option (the second positional argument to `test(name,
* options, fn)`), used as a hang BACKSTOP -- not an assertion -- for tests
* that exercise a pathological, adversarially-large input against an
* algorithmic bound (ADR-612 bracket-coherence and read-tolerance) rather
* than a wall-clock ceiling. If the bound holds, the test finishes in
* milliseconds; this only turns a genuine runaway into a deterministic
* failure instead of a suite that never returns.
*
* Shared across 2 files in batch #4522 of the ad hoc timeout literal
* migration, epic #4445 -- every site independently arrived at this exact
* value -- that is why it lives here rather than as a file-local constant.
*/
const PATHOLOGICAL_INPUT_TEST_TIMEOUT_MS = 60000;
/**
* A single `gsd-tools.cjs` CLI subcommand invocation, spawned directly
* (execFileSync/spawnSync, or the process seam's runNode wrapping the same
* shape -- never via an intermediate shell script), with no confirmed
* nested-subprocess fan-out. A distinct, heavier tier than
* `PROBE_TIMEOUT_MS` (15000ms, the lighter CLI-query/probe class) but half
* of `LOOP_HOOK_POINT_CLI_TIMEOUT_MS` (60000ms) -- not equalized to either
* without bench data. Coincides numerically with `BUILD_TIMEOUT_MS`,
* `GENERATOR_SCRIPT_TIMEOUT_MS`, and `REAL_REPO_GIT_TIMEOUT_MS`, none of
* which describe this call shape (a `build-hooks.js` bundle, a
* `scripts/*.cjs` generator, and real-repo git plumbing respectively) --
* disclosed, not merged.
*
* Shared across 2 files in batch #4522 of the ad hoc timeout literal
* migration, epic #4445 -- every site independently arrived at this exact
* value -- that is why it lives here rather than as a file-local constant.
*/
const GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS = 30000;
module.exports = {
PROBE_TIMEOUT_MS,
HOOK_FANOUT_TIMEOUT_MS,
@@ -281,4 +316,6 @@ module.exports = {
MALFORMED_INPUT_HOOK_TIMEOUT_MS,
GENERATOR_SCRIPT_TIMEOUT_MS,
REAL_REPO_GIT_TIMEOUT_MS,
PATHOLOGICAL_INPUT_TEST_TIMEOUT_MS,
GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS,
};

View File

@@ -12,6 +12,7 @@ const { createFixture, seedPhase } = require('./fixtures/index.cjs');
const { createTempProject, createTempDir } = require('./helpers.cjs');
const { executionContextRefs } = require('../scripts/command-contract-helpers.cjs');
const { escapeRegex } = require('../gsd-core/bin/lib/pattern.cjs');
const { GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
/**
* #3188: write the canonical flat planning docs so an init-query "present" test
@@ -3711,7 +3712,7 @@ describe('init section manifest', () => {
cwd,
encoding: 'utf8',
env: { ...process.env, GSD_JSON_ERRORS: '1', ...env },
timeout: 30000,
timeout: GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS,
});
let stdout = result.stdout || '';
// output() spills payloads over 50KB to a tmpfile and prints "@file:<path>"

View File

@@ -34,6 +34,7 @@ const helpers = require('./helpers.cjs');
const { runGsdTools, createTempProject, cleanup, TOOLS_PATH, captureFdSync } = helpers;
const processSeam = require('./helpers/process-seam.cjs');
const { collectSection } = require('../gsd-core/bin/lib/markdown-sectionizer.cjs');
const { LOOP_HOOK_POINT_CLI_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
// runGsdTools's legacy shape drops stderr on success, but the #3311 contract
// is exactly that a conflict is VISIBLE — these tests must see stderr. Drive
@@ -43,7 +44,7 @@ function runToolsWithStderr(args, cwd, env = {}) {
return processSeam.runNode([TOOLS_PATH, ...args], {
cwd,
env: { ...process.env, ...helpers.TEST_ENV_BASE, ...env },
timeoutMs: 60000,
timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS,
});
}

View File

@@ -26,6 +26,15 @@ const fc = require('./helpers/fast-check-setup.cjs');
const { escapeRegex, literalPattern, compileUserPattern, MAX_USER_PATTERN_LEN } = require('../gsd-core/bin/lib/pattern.cjs');
/**
* A single `node -e` inline probe script testing RegExp.escape fallback
* semantics -- one subprocess, no fan-out. Coincides numerically with
* tests/helpers/timeouts.cjs's GSD_TOOLS_CLI_MODERATE_TIMEOUT_MS but
* describes a different operation (an inline node -e probe, not a
* gsd-tools.cjs CLI subcommand spawn) -- kept local.
*/
const REGEXP_ESCAPE_PROBE_TIMEOUT_MS = 30_000;
// ─── Section 1: escapeRegex — rows 1-10 ───────────────────────────────────
describe('escapeRegex', () => {
@@ -231,7 +240,7 @@ describe('escapeRegex without RegExp.escape (#3498 Node-22 fallback)', () => {
].join('\n');
test('builds and escapes correctly when RegExp.escape is absent (Node 22 semantics)', () => {
const r = runNode(['-e', PROBE], { timeoutMs: 30_000 });
const r = runNode(['-e', PROBE], { timeoutMs: REGEXP_ESCAPE_PROBE_TIMEOUT_MS });
assert.strictEqual(r.outcome, OUTCOME.EXITED, `probe must run: ${r.stderr}`);
assert.strictEqual(r.exitCode, 0, `fallback path failed: ${r.stdout}\n${r.stderr}`);
assert.match(r.stdout, /fallback-ok/);
@@ -244,7 +253,7 @@ describe('escapeRegex without RegExp.escape (#3498 Node-22 fallback)', () => {
"if (!new RegExp(escapeRegex('a.b')).test('a.b')) { console.error('post-load neuter broke escaping'); process.exit(1); }",
"console.log('capture-ok');",
].join('\n');
const r = runNode(['-e', PROBE2], { timeoutMs: 30_000 });
const r = runNode(['-e', PROBE2], { timeoutMs: REGEXP_ESCAPE_PROBE_TIMEOUT_MS });
assert.strictEqual(r.outcome, OUTCOME.EXITED, `probe must run: ${r.stderr}`);
assert.strictEqual(r.exitCode, 0, `post-load capture failed: ${r.stdout}\n${r.stderr}`);
});

View File

@@ -19,6 +19,11 @@ const os = require('node:os');
const { execFileSync } = require('node:child_process');
const { runNode } = require('./helpers/process-seam.cjs');
const { toLegacyResult } = require('./helpers/git-fixture.cjs');
const {
GIT_TIMEOUT_MS,
LOOP_HOOK_POINT_CLI_TIMEOUT_MS,
PROBE_TIMEOUT_MS,
} = require('./helpers/timeouts.cjs');
// `phase complete` against a real STATE.md rewrite; matches the 60000ms bound
// already used for the same CLI call elsewhere in this file (runPhaseComplete
@@ -2528,7 +2533,7 @@ describe('phase add allocation vs sibling git worktrees (#3849)', () => {
const activeDirs = [];
function git(args, cwd) {
return execFileSync('git', args, { cwd, encoding: 'utf-8', timeout: 15_000 });
return execFileSync('git', args, { cwd, encoding: 'utf-8', timeout: GIT_TIMEOUT_MS });
}
function initRepo(repoDir) {
@@ -2700,7 +2705,7 @@ describe('phase add --ws workstream-scoped allocation vs sibling git worktrees (
const activeDirs = [];
function git(args, cwd) {
return execFileSync('git', args, { cwd, encoding: 'utf-8', timeout: 15_000 });
return execFileSync('git', args, { cwd, encoding: 'utf-8', timeout: GIT_TIMEOUT_MS });
}
/**
@@ -6577,7 +6582,7 @@ function runPhaseComplete(tmpDir, { phase = '1', tolerateExit = false } = {}) {
try {
return execFileSync('node', [GSD_TOOLS_BIN, 'phase', 'complete', phase], {
cwd: tmpDir,
timeout: 60000,
timeout: LOOP_HOOK_POINT_CLI_TIMEOUT_MS,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe'],
});
@@ -9379,7 +9384,7 @@ function run(args, cwd) {
return {
stdout: execFileSync('node', [gsdTools, ...args], {
cwd,
timeout: 15000,
timeout: PROBE_TIMEOUT_MS,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe'],
}),
@@ -9749,7 +9754,7 @@ function run2853(args, cwd) {
try {
return {
stdout: execFileSync('node', [gsdTools2853, ...args], {
cwd, timeout: 15000, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],
cwd, timeout: PROBE_TIMEOUT_MS, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'],
}),
ok: true,
};

View File

@@ -51,6 +51,14 @@ const { filterAlreadyExecuted } = require('../gsd-core/bin/lib/quick-batch-dispa
const { generateSlugInternal } = require('../gsd-core/bin/lib/core-utils.cjs');
const { planningPaths } = require('../gsd-core/bin/lib/planning-workspace.cjs');
/**
* A single `mkfifo` subprocess call, near-instant. Distinct from
* tests/capability-cli.test.cjs's mkfifo call (epic #4445 batch 10, which
* reuses PROBE_TIMEOUT_MS at 15000ms) -- this site's genuinely different
* pre-existing bound is preserved rather than equalized without bench data.
*/
const MKFIFO_PROBE_TIMEOUT_MS = 5000;
// ─── Shared fixtures ────────────────────────────────────────────────────────────
function mkTmpProject() {
@@ -188,7 +196,7 @@ describe('quick-batch: task-list parsing', () => {
try {
const fifoPath = path.join(dir, '.planning', 'a-fifo');
try {
execFileSync('mkfifo', [fifoPath], { stdio: 'ignore', timeout: 5000 });
execFileSync('mkfifo', [fifoPath], { stdio: 'ignore', timeout: MKFIFO_PROBE_TIMEOUT_MS });
} catch (err) {
// Documented skip: mkfifo unavailable on this CI platform (e.g. Windows).
t.skip(`mkfifo unavailable: ${err instanceof Error ? err.message : String(err)}`);

View File

@@ -15,6 +15,7 @@
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fc = require('fast-check');
const { LOOP_HOOK_POINT_CLI_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
const {
stateReplaceField,
@@ -1100,7 +1101,7 @@ describe('#3204 buildStateFrontmatter total_phases — negative space / boundari
const { TOOLS_PATH, TEST_ENV_BASE } = require('./helpers.cjs');
const rec = runNode(
[TOOLS_PATH, 'state', 'json', '--raw'],
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: 60000 },
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS },
);
assert.ok(rec.exitCode === 0, `state json --raw failed: ${rec.stderr}`);
assert.ok(
@@ -1658,7 +1659,7 @@ describe('#3355 phase-dir dedup — collision tie-break must not consult mtime',
// (runGsdTools discards stderr on success, so drive the seam directly).
const rec = runNode(
[TOOLS_PATH, 'state', 'json', '--raw'],
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: 60000 },
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS },
);
assert.ok(rec.exitCode === 0, `state json --raw failed: ${rec.stderr}`);
assert.ok(
@@ -1726,7 +1727,7 @@ describe('#3354 buildStateFrontmatter total_phases — milestoned-but-unbounded
// stderr on success). The warning is asserted on THIS invocation.
const rec = runNode(
[TOOLS_PATH, 'state', 'record-session', '--stopped-at', 'Phase 1, Plan 1', '--resume-file', 'none'],
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: 60000 },
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS },
);
assert.ok(rec.exitCode === 0, `state record-session failed: ${rec.stderr}`);
@@ -1823,7 +1824,7 @@ describe('#3573 total_phases — roadmap absent with an asserted milestone', ()
function recordSession(dir, stoppedAt = 'Phase 1, Plan 1') {
return runNode(
[TOOLS_PATH, 'state', 'record-session', '--stopped-at', stoppedAt, '--resume-file', 'none'],
{ cwd: dir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: 60000 },
{ cwd: dir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS },
);
}
@@ -1867,7 +1868,7 @@ describe('#3573 total_phases — roadmap absent with an asserted milestone', ()
// about total_phases surviving the resync.
const rec = runNode(
[TOOLS_PATH, 'state', 'begin-phase', '--phase', '2'],
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: 60000 },
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS },
);
assert.ok(rec.exitCode === 0, `state begin-phase failed: ${rec.stderr}`);
assert.strictEqual(
@@ -1935,7 +1936,7 @@ describe('#3573 total_phases — roadmap absent with an asserted milestone', ()
// about total_phases surviving the resync.
const rec = runNode(
[TOOLS_PATH, 'state', 'planned-phase', '--phase', '2', '--name', 'Core'],
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: 60000 },
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS },
);
assert.ok(rec.exitCode === 0, `state planned-phase failed: ${rec.stderr}`);
assert.strictEqual(
@@ -2072,7 +2073,7 @@ describe('#4094 milestone-unbounded withhold — all four progress counters', ()
function recordSession(dir, stoppedAt = 'Phase 1, Plan 1') {
return runNode(
[TOOLS_PATH, 'state', 'record-session', '--stopped-at', stoppedAt, '--resume-file', 'none'],
{ cwd: dir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: 60000 },
{ cwd: dir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS },
);
}
@@ -2288,7 +2289,7 @@ describe('#4094 milestone-unbounded withhold — all four progress counters', ()
const rec = runNode(
[TOOLS_PATH, 'state', 'sync'],
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: 60000 },
{ cwd: tmpDir, env: { ...process.env, ...TEST_ENV_BASE }, timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS },
);
assert.ok(rec.exitCode === 0, `state sync failed: ${rec.stderr}`);

View File

@@ -15,6 +15,7 @@ const initLib = require('../gsd-core/bin/lib/init.cjs');
const { renderPendingTodosMarkdown } = initLib;
const { cleanup } = require('./helpers.cjs');
const { escapeRegex } = require('../gsd-core/bin/lib/pattern.cjs');
const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
const MAX = 240;
@@ -293,7 +294,7 @@ function runQueryInitTodos(cwd) {
const result = spawnSync(process.execPath, [gsdTools, 'query', 'init.todos'], {
cwd,
encoding: 'utf8',
timeout: 15000,
timeout: PROBE_TIMEOUT_MS,
});
assert.equal(result.status, 0, `gsd_run query init.todos failed: ${result.stderr}`);
return JSON.parse(result.stdout);