diff --git a/eslint-rules/no-adhoc-timeout-literal.allowlist.json b/eslint-rules/no-adhoc-timeout-literal.allowlist.json index 0733f60d2..47efb5bee 100644 --- a/eslint-rules/no-adhoc-timeout-literal.allowlist.json +++ b/eslint-rules/no-adhoc-timeout-literal.allowlist.json @@ -1,10 +1,7 @@ [ "tests/adr-612-bracket-coherence.test.cjs", "tests/adr-612-bracket-read-tolerance.test.cjs", - "tests/adr-index-gate.test.cjs", "tests/adr857-core-without-capabilities.test.cjs", - "tests/api-coverage-gate-e2e.test.cjs", - "tests/api-coverage.test.cjs", "tests/assumption-delta-checkpoint-e2e.test.cjs", "tests/assumption-delta.test.cjs", "tests/capability-cli.test.cjs", @@ -13,9 +10,7 @@ "tests/capability-trust.test.cjs", "tests/capability-validator-task-content-resolver.test.cjs", "tests/capability-writer.test.cjs", - "tests/changeset-new.test.cjs", "tests/check-env.test.cjs", - "tests/check-glossary-refs.test.cjs", "tests/check-predicate.test.cjs", "tests/cjs-command-router-adapter.test.cjs", "tests/code-review-pipeline-regression.test.cjs", @@ -24,24 +19,16 @@ "tests/config-get-default.test.cjs", "tests/dispatcher.test.cjs", "tests/effort-surface-axis.test.cjs", - "tests/emitted-ack-trailer.test.cjs", - "tests/emitted-attribution.test.cjs", "tests/federated-config.test.cjs", "tests/gate-predicate-evaluator.test.cjs", - "tests/gen-context-index.test.cjs", - "tests/gen-health-docs.test.cjs", - "tests/gen-section-manifest.test.cjs", - "tests/gen-state-md-docs.test.cjs", "tests/graphify.test.cjs", "tests/gsd-check-update-worker-platform-gate.test.cjs", "tests/gsd-mcp-server-bin.test.cjs", "tests/gsd-statusline.test.cjs", "tests/health-validation.test.cjs", "tests/init.test.cjs", - "tests/lint-docs-command-form.test.cjs", "tests/locking-bugs-1909-1916-1925-1927.test.cjs", "tests/milestone-lock.test.cjs", - "tests/no-pending-3212-markers.test.cjs", "tests/pattern.test.cjs", "tests/perf-316-state-lock-buffer-alloc.test.cjs", "tests/perf-317-context-monitor-fs.test.cjs", @@ -53,7 +40,6 @@ "tests/policy-160-route0-resume.test.cjs", "tests/prohibition-enforcement.test.cjs", "tests/quick-batch.test.cjs", - "tests/representative-corpus.test.cjs", "tests/review-lane-invocation.test.cjs", "tests/reviewer-manifest-body.test.cjs", "tests/reviewer-trust-disclosure.test.cjs", diff --git a/tests/adr-index-gate.test.cjs b/tests/adr-index-gate.test.cjs index 9a7a2caf7..6a80268ed 100644 --- a/tests/adr-index-gate.test.cjs +++ b/tests/adr-index-gate.test.cjs @@ -18,6 +18,7 @@ const { spawnSync } = require('node:child_process'); const { createTempDir, cleanup } = require('./helpers.cjs'); const { copyScriptWithDeps } = require('./helpers/copy-script-fixture.cjs'); const { findTableWithColumns } = require('../gsd-core/bin/lib/markdown-table.cjs'); +const { GENERATOR_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const REPO_ROOT = path.resolve(__dirname, '..'); const SCRIPT_REL = path.join('scripts', 'gen-adr-index.cjs'); @@ -61,7 +62,7 @@ function run(root, args = []) { const res = spawnSync(process.execPath, [path.join(root, SCRIPT_REL), ...args], { cwd: root, encoding: 'utf8', - timeout: 30_000, + timeout: GENERATOR_SCRIPT_TIMEOUT_MS, }); if (res.error) throw res.error; return { status: res.status, stdout: res.stdout || '', stderr: res.stderr || '' }; diff --git a/tests/api-coverage-gate-e2e.test.cjs b/tests/api-coverage-gate-e2e.test.cjs index 809912728..f9061bce4 100644 --- a/tests/api-coverage-gate-e2e.test.cjs +++ b/tests/api-coverage-gate-e2e.test.cjs @@ -23,6 +23,7 @@ const path = require('node:path'); const { cleanup, TEST_ENV_BASE } = require('./helpers.cjs'); const { runNode, OUTCOME } = require('./helpers/process-seam.cjs'); +const { LOOP_HOOK_POINT_CLI_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); // In-process seam for the fail-closed read-injection tests at the bottom of this // file (#2365 review): readPhaseScope is the pure phase-scope reader behind the // gate. Those tests monkeypatch fs rather than drive a subprocess. @@ -39,7 +40,7 @@ function runTools(args, cwd) { const r = runNode([TOOLS_PATH, ...argv], { cwd, env: { ...process.env, ...TEST_ENV_BASE }, - timeoutMs: 60000, + timeoutMs: LOOP_HOOK_POINT_CLI_TIMEOUT_MS, }); if (r.outcome === OUTCOME.EXITED && r.exitCode === 0) { return { success: true, output: r.stdout.trim(), exitCode: 0, error: '' }; diff --git a/tests/api-coverage.test.cjs b/tests/api-coverage.test.cjs index bbc9058ba..67bf049d6 100644 --- a/tests/api-coverage.test.cjs +++ b/tests/api-coverage.test.cjs @@ -17,6 +17,7 @@ const assert = require('node:assert/strict'); const { spawnSync } = require('node:child_process'); const path = require('node:path'); const fc = require('fast-check'); +const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const MODULE_PATH = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'api-coverage.cjs'); @@ -985,7 +986,7 @@ describe('api-coverage CLI — STDIN + exit codes', () => { const r = spawnSync(process.execPath, [CLI, '--json'], { input: stdin, encoding: 'utf-8', - timeout: 15000, + timeout: PROBE_TIMEOUT_MS, }); return { exitCode: r.status, stdout: r.stdout, stderr: r.stderr }; } @@ -1016,7 +1017,6 @@ describe('api-coverage CLI — NO_INPUT / UNAVAILABLE (ADR-3889 Phase 3, #3907)' const INJECT_STDIN_ERROR = path.join(__dirname, 'helpers', 'inject-stdin-error.cjs'); const { exitCodeFor } = require('../gsd-core/bin/lib/exit-code-registry.cjs'); const { runNode } = require('./helpers/process-seam.cjs'); - const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); function runCliJson(stdin, extraArgs = [], extraEnv = {}) { const r = runNode([CLI, '--json', ...extraArgs], { diff --git a/tests/changeset-new.test.cjs b/tests/changeset-new.test.cjs index 2d72d3f13..be7e7c659 100644 --- a/tests/changeset-new.test.cjs +++ b/tests/changeset-new.test.cjs @@ -16,6 +16,7 @@ const { generateFragmentName, scaffoldFragment, parseFragment, parseArgs } = (() })(); const { FRAGMENT_ERROR } = require(path.join(ROOT, 'scripts', 'changeset', 'parse.cjs')); const { cleanup } = require('./helpers.cjs'); +const { QUICK_SPAWN_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const NEW_CJS = path.join(ROOT, 'scripts', 'changeset', 'new.cjs'); @@ -114,7 +115,7 @@ describe('changeset new: --pr 0 placeholder acceptance (bug #1224)', () => { const result = spawnSync( process.execPath, [NEW_CJS, '--type', 'Fixed', '--pr', '0', '--body', 'placeholder for pr-zero.', '--repo', isolatedDir], - { encoding: 'utf8', timeout: 10000 }, + { encoding: 'utf8', timeout: QUICK_SPAWN_TIMEOUT_MS }, ); // The bug: old main() did `if (!opts.pr)` → exit 2. Fixed: exit 0. diff --git a/tests/check-glossary-refs.test.cjs b/tests/check-glossary-refs.test.cjs index fdf586419..e2a0aeb82 100644 --- a/tests/check-glossary-refs.test.cjs +++ b/tests/check-glossary-refs.test.cjs @@ -17,6 +17,7 @@ const { spawnSync } = require('node:child_process'); const { createTempDir, cleanup } = require('./helpers.cjs'); const { copyScriptWithDeps } = require('./helpers/copy-script-fixture.cjs'); +const { GENERATOR_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const REPO_ROOT = path.resolve(__dirname, '..'); const SCRIPT_REL = path.join('scripts', 'check-glossary-refs.cjs'); @@ -67,7 +68,7 @@ function run(root, args = []) { const res = spawnSync(process.execPath, [path.join(root, SCRIPT_REL), ...args], { cwd: root, encoding: 'utf8', - timeout: 30_000, + timeout: GENERATOR_SCRIPT_TIMEOUT_MS, }); if (res.error) throw res.error; return { status: res.status, stdout: res.stdout || '', stderr: res.stderr || '' }; @@ -227,7 +228,7 @@ test('the real script runs cleanly against the real repo without crashing', () = const res = spawnSync(process.execPath, [path.join(REPO_ROOT, SCRIPT_REL), '--check'], { cwd: REPO_ROOT, encoding: 'utf8', - timeout: 30_000, + timeout: GENERATOR_SCRIPT_TIMEOUT_MS, }); assert.equal(res.error, undefined, `spawn must not error: ${res.error}`); assert.ok(res.status === 0 || res.status === 1, `expected exit 0 or 1, got ${res.status} (stderr: ${res.stderr})`); diff --git a/tests/emitted-ack-trailer.test.cjs b/tests/emitted-ack-trailer.test.cjs index 039bd5f16..d58774156 100644 --- a/tests/emitted-ack-trailer.test.cjs +++ b/tests/emitted-ack-trailer.test.cjs @@ -794,6 +794,17 @@ describe('hostile IO: uncomputable range, subprocess failure, timeout', () => { ); }); + /** + * Deliberately, impossibly tiny -- NOT a generous-headroom bound like every + * other timeout constant in this test suite. Used to FORCE a TIMED_OUT + * outcome against an artificially huge git history (see + * growHistoryFastImport above), proving "an unreadable-in-time git call + * must throw a timeout, never hang." Named and commented distinctly so a + * future reader never mistakes this for a real operation-duration budget + * and "fixes" it by raising it. + */ + const IMPOSSIBLY_SHORT_GIT_TIMEOUT_MS = 20; + test('git log is bounded by a timeout — row 24', (t) => { const dir = makeTempRepo('gsd-ack-trailer-24-'); withCleanup(t, dir); @@ -801,7 +812,9 @@ describe('hostile IO: uncomputable range, subprocess failure, timeout', () => { const start = Date.now(); assert.throws( - () => readAckTrailers({ baseRef: rootSha, headRef: 'HEAD', cwd: dir, timeoutMs: 20 }), + () => readAckTrailers({ + baseRef: rootSha, headRef: 'HEAD', cwd: dir, timeoutMs: IMPOSSIBLY_SHORT_GIT_TIMEOUT_MS, + }), /time/i, 'an unreadable-in-time git call must throw a timeout, never hang', ); diff --git a/tests/emitted-attribution.test.cjs b/tests/emitted-attribution.test.cjs index 494438e05..dade76387 100644 --- a/tests/emitted-attribution.test.cjs +++ b/tests/emitted-attribution.test.cjs @@ -90,6 +90,56 @@ const { resolveBaseline, } = require('./helpers/emitted-baseline.cjs'); +/** + * git plumbing via a scratch index against this repo's REAL object + * database (never a throwaway fixture) -- run through this file's own + * hand-rolled git-spawn helper (never the shared + * tests/helpers/git-fixture.cjs). Shares the REAL_REPO_GIT_TIMEOUT_MS class + * with tests/no-pending-3212-markers.test.cjs's `git ls-files` call -- + * promoted to tests/helpers/timeouts.cjs rather than kept file-local once a + * second file was found sharing the exact same value and shape. + */ +const { REAL_REPO_GIT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); + +/** + * git fixture CONSTRUCTION (init/config/add/commit) against a genuinely + * fresh temp repo, via this file's own hand-rolled git-spawn helper -- + * correction from an earlier pass that conflated this with + * REAL_REPO_GIT_TIMEOUT_MS's real-repo-tree class; a Standards-axis review + * caught that this site's `repo` is a throwaway mkdtemp fixture + * (createTempDir + git init), not the real repo tree. Distinct from the + * SHARED tests/helpers/git-fixture.cjs's own GIT_FIXTURE_TIMEOUT_MS + * (60000ms, a six-spawn construction sequence): this site rolls its own, + * lighter five-spawn sequence at a genuinely different pre-existing bound, + * so reusing that shared constant would silently double this site's + * budget. No fresh bench data justifies a different number, so the + * pre-existing 30000ms literal is preserved exactly under this name. + */ +const FRESH_FIXTURE_GIT_TIMEOUT_MS = 30_000; + +/** + * node:test's own per-test timeout option (NOT a subprocess spawn bound) -- + * bounds the whole test body for this file's two heaviest tests: a real + * worktree checkout, `npm run build:lib`, a full multi-runtime install + * pass, and real git resolution. A completely different mechanism from + * every spawnSync/execFileSync timeout in this file or in + * tests/helpers/timeouts.cjs. No fresh bench data justifies a different + * number, so the pre-existing 480000ms literal is preserved exactly. + */ +const HEAVY_REAL_TREE_TEST_TIMEOUT_MS = 480_000; + +/** + * Runs the exact same script as the shared BUILD_TIMEOUT_MS constant + * (scripts/build-hooks.js) but at 4x that constant's bound. This site + * sits inside "differential attribution over the real tree", the single + * heaviest test in the suite, where elevated system load plausibly + * justifies the wider margin -- not equalized to the lighter shared norm + * without bench data. Coincides numerically with INSTALL_TIMEOUT_MS (a + * full installer run, an unrelated operation) -- kept separate. No fresh + * bench data justifies a different number, so the pre-existing 120000ms + * literal is preserved exactly. + */ +const BUILD_HOOKS_UNDER_LOAD_TIMEOUT_MS = 120_000; const SHA_A = 'a'.repeat(40); const SHA_B = 'b'.repeat(40); @@ -1425,7 +1475,7 @@ test('an unreadable baseline surfaces an error', () => { test( 'buildBaselineAtRef resolves a baseline via the in-job build even when the generator ' + 'script is absent at the ref (#2767 regression)', - { timeout: 480_000 }, + { timeout: HEAVY_REAL_TREE_TEST_TIMEOUT_MS }, (t) => { // Mirrors "differential attribution over the real tree": install output is // platform-specific on Windows, and this drives the same heavy worktree + @@ -1476,7 +1526,7 @@ test( // closed. Reusing the SAME helper `buildBaselineAtRef` now uses (below) rather than // hand-rolling the flag here keeps the fix from silently diverging per call site. const run = (...args) => execFileSync('git', [...safeDirArgs(REPO_ROOT), ...args], { - cwd: REPO_ROOT, encoding: 'utf8', timeout: 30_000, env: gitEnv, stdio: ['ignore', 'pipe', 'pipe'], + cwd: REPO_ROOT, encoding: 'utf8', timeout: REAL_REPO_GIT_TIMEOUT_MS, env: gitEnv, stdio: ['ignore', 'pipe', 'pipe'], }).trim(); const headSha = run('rev-parse', 'HEAD'); @@ -1492,7 +1542,7 @@ test( // otherwise this test would prove nothing. assert.throws( () => execFileSync('git', [...safeDirArgs(REPO_ROOT), 'cat-file', '-e', `${syntheticSha}:scripts/gen-emitted-baseline.cjs`], { - cwd: REPO_ROOT, encoding: 'utf8', timeout: 30_000, stdio: 'pipe', + cwd: REPO_ROOT, encoding: 'utf8', timeout: REAL_REPO_GIT_TIMEOUT_MS, stdio: 'pipe', }), /./, 'the synthetic ref must genuinely lack the generator script for this test to prove anything', @@ -1936,7 +1986,7 @@ test('baseline families are enumerated from the ref, not from the current regist // this same process just created with `mkdtempSync` + `git init`, so its owner is // always the uid running the test regardless of container — it is never the // externally-mounted repo path the dubious-ownership check reacts to. - const run = (...args) => execFileSync('git', args, { cwd: repo, encoding: 'utf8', timeout: 30_000 }); + const run = (...args) => execFileSync('git', args, { cwd: repo, encoding: 'utf8', timeout: FRESH_FIXTURE_GIT_TIMEOUT_MS }); run('init', '--quiet', '-b', 'main'); run('config', 'user.email', 'test@example.invalid'); @@ -2050,7 +2100,7 @@ test('property: reported added/dropped are exactly the set differences', () => { // the working-tree fixtures, which would be whatever this PR's author regenerated; // comparing against those would be vacuous. -test('differential attribution over the real tree', { timeout: 480_000 }, async (t) => { +test('differential attribution over the real tree', { timeout: HEAVY_REAL_TREE_TEST_TIMEOUT_MS }, async (t) => { if (process.platform === 'win32') { // Mirrors the golden harness: install output is platform-specific on Windows // (backslash paths), so parity is asserted on macOS + Linux. An explicit t.skip, @@ -2062,7 +2112,7 @@ test('differential attribution over the real tree', { timeout: 480_000 }, async // hooks/dist is gitignored and built (DEFECT.HOOKS-DIST-SCOPED-CI): the scoped CI // lane does not run build:hooks, so a real install there would emit no hooks/ dir. // Build idempotently, exactly as the golden harness does. - execFileSync(process.execPath, [BUILD_SCRIPT], { encoding: 'utf-8', stdio: 'pipe', timeout: 120_000 }); + execFileSync(process.execPath, [BUILD_SCRIPT], { encoding: 'utf-8', stdio: 'pipe', timeout: BUILD_HOOKS_UNDER_LOAD_TIMEOUT_MS }); // The base ref is not universally available. The gsd-test runner shallow-clones and // merges base+head, so no `origin/*` remote-tracking ref exists in the container — diff --git a/tests/gen-context-index.test.cjs b/tests/gen-context-index.test.cjs index cbd856620..b8001fc51 100644 --- a/tests/gen-context-index.test.cjs +++ b/tests/gen-context-index.test.cjs @@ -44,6 +44,7 @@ const { execFileSync } = require('node:child_process'); const { createTempDir, cleanup } = require('./helpers.cjs'); const { serializeIndex, buildFreshIndex, checkReport, REASON } = require('../scripts/gen-context-index.cjs'); +const { GENERATOR_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const ROOT = path.resolve(__dirname, '..'); const SCRIPT = path.join(ROOT, 'scripts', 'gen-context-index.cjs'); @@ -71,7 +72,7 @@ function runGenContextIndex(args, paths = {}) { cwd: ROOT, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], - timeout: 30000, + timeout: GENERATOR_SCRIPT_TIMEOUT_MS, }); return { code: 0, stdout, stderr: '' }; } catch (err) { diff --git a/tests/gen-health-docs.test.cjs b/tests/gen-health-docs.test.cjs index 24b6c474f..21e095c1a 100644 --- a/tests/gen-health-docs.test.cjs +++ b/tests/gen-health-docs.test.cjs @@ -18,6 +18,7 @@ const path = require('node:path'); const { execFileSync } = require('node:child_process'); const { createTempDir, cleanup } = require('./helpers.cjs'); +const { GENERATOR_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const { buildErrorCodeRows, renderErrorCodesRegion, @@ -54,7 +55,7 @@ function runGenHealthDocs(args, cwd = ROOT) { cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], - timeout: 30000, + timeout: GENERATOR_SCRIPT_TIMEOUT_MS, }); return { code: 0, stdout, stderr: '' }; } catch (err) { diff --git a/tests/gen-section-manifest.test.cjs b/tests/gen-section-manifest.test.cjs index 5e33c9612..e773a539f 100644 --- a/tests/gen-section-manifest.test.cjs +++ b/tests/gen-section-manifest.test.cjs @@ -22,6 +22,7 @@ const path = require('node:path'); const { execFileSync } = require('node:child_process'); const { createTempDir, cleanup } = require('./helpers.cjs'); +const { GENERATOR_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const { buildFreshManifest, writeManifestAtomically, @@ -90,7 +91,7 @@ function runGenSectionManifest(args, cwd = ROOT) { cwd, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], - timeout: 30000, + timeout: GENERATOR_SCRIPT_TIMEOUT_MS, }); return { code: 0, stdout, stderr: '' }; } catch (err) { diff --git a/tests/gen-state-md-docs.test.cjs b/tests/gen-state-md-docs.test.cjs index aef7c3ac6..dc813ef6d 100644 --- a/tests/gen-state-md-docs.test.cjs +++ b/tests/gen-state-md-docs.test.cjs @@ -27,6 +27,7 @@ const path = require('node:path'); const { createTempDir, cleanup } = require('./helpers.cjs'); const { runNode } = require('./helpers/process-seam.cjs'); +const { GENERATOR_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const gen = require('../scripts/gen-state-md-docs.cjs'); const { splitLines, detectEol, joinLines } = require('../gsd-core/bin/lib/text-lines.cjs'); @@ -46,7 +47,7 @@ function seedCleanTree(dir) { function runGen(args, root) { const fullArgs = [SCRIPT, ...args]; if (root !== undefined) fullArgs.push('--root', root); - const r = runNode(fullArgs, { timeoutMs: 30000 }); + const r = runNode(fullArgs, { timeoutMs: GENERATOR_SCRIPT_TIMEOUT_MS }); return { code: r.exitCode, stdout: r.stdout, stderr: r.stderr }; } diff --git a/tests/helpers/timeouts.cjs b/tests/helpers/timeouts.cjs index 2133b616e..ac07fd47b 100644 --- a/tests/helpers/timeouts.cjs +++ b/tests/helpers/timeouts.cjs @@ -224,6 +224,47 @@ const SCAN_USAGE_ERROR_TIMEOUT_MS = 5000; */ const MALFORMED_INPUT_HOOK_TIMEOUT_MS = 5000; +/** + * A single `scripts/*.cjs` generator or lint script (gen-adr-index.cjs, + * check-glossary-refs.cjs, gen-context-index.cjs, and siblings), spawned + * directly and once against a small temp fixture repo -- no fan-out. + * + * Deliberately NOT `BUILD_TIMEOUT_MS`, despite the coincidentally-matching + * value: that constant's own doc comment scopes it specifically to + * `scripts/build-hooks.js` ("not a full project build"), and none of this + * norm's sites run that script. Reusing a constant for its number while + * ignoring what its comment actually describes is exactly the trap this + * migration exists to avoid -- see `SEAM_DEFAULT_TIMEOUT_MS` and + * `SCAN_USAGE_ERROR_TIMEOUT_MS` for the same reasoning applied elsewhere in + * this file. + * + * Shared across 7 files in batch #4520 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 GENERATOR_SCRIPT_TIMEOUT_MS = 30000; + +/** + * A git plumbing command (or a short scratch-index sequence of them) run + * against the REAL, current repo tree -- never a throwaway mkdtemp fixture. + * Distinct from `GIT_TIMEOUT_MS` (15000ms, plumbing reads against a small + * fixture repo) and `GIT_FIXTURE_TIMEOUT_MS` (60000ms, the shared helper's + * own multi-spawn fixture-CONSTRUCTION sequence) -- this norm's sites + * either read the real object database directly (`git ls-files`) or build a + * synthetic commit on a scratch index against it, which is heavier than a + * tiny-fixture read but not the shared helper's own six-spawn construction + * class. Explicitly NOT for fixture-repo CONSTRUCTION (init/config/add/commit + * against a throwaway mkdtemp repo) -- tests/emitted-attribution.test.cjs's + * own file-local `FRESH_FIXTURE_GIT_TIMEOUT_MS` covers that shape instead, + * after an earlier pass conflated the two and a Standards-axis review caught + * it. + * + * Shared across 2 files in batch #4520 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 REAL_REPO_GIT_TIMEOUT_MS = 30000; + module.exports = { PROBE_TIMEOUT_MS, HOOK_FANOUT_TIMEOUT_MS, @@ -238,4 +279,6 @@ module.exports = { LOOP_HOOK_POINT_CLI_TIMEOUT_MS, SCAN_USAGE_ERROR_TIMEOUT_MS, MALFORMED_INPUT_HOOK_TIMEOUT_MS, + GENERATOR_SCRIPT_TIMEOUT_MS, + REAL_REPO_GIT_TIMEOUT_MS, }; diff --git a/tests/lint-docs-command-form.test.cjs b/tests/lint-docs-command-form.test.cjs index 072475fb2..5517e838f 100644 --- a/tests/lint-docs-command-form.test.cjs +++ b/tests/lint-docs-command-form.test.cjs @@ -19,6 +19,7 @@ const os = require('node:os'); const path = require('node:path'); const { runNode } = require('./helpers/process-seam.cjs'); const { gitOrThrow } = require('./helpers/git-fixture.cjs'); +const { GENERATOR_SCRIPT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const GUARD_SCRIPT = path.resolve(__dirname, '..', 'scripts', 'lint-docs-command-form.cjs'); @@ -60,7 +61,7 @@ function runGuard(cwd) { const r = runNode([GUARD_SCRIPT], { cwd, env: { ...process.env, GSD_LINT_DOCS_COMMAND_FORM_REPO_ROOT: cwd }, - timeoutMs: 30_000, + timeoutMs: GENERATOR_SCRIPT_TIMEOUT_MS, }); return { status: r.exitCode, stdout: r.stdout, stderr: r.stderr }; } diff --git a/tests/no-pending-3212-markers.test.cjs b/tests/no-pending-3212-markers.test.cjs index 4e0a4df43..e4c966435 100644 --- a/tests/no-pending-3212-markers.test.cjs +++ b/tests/no-pending-3212-markers.test.cjs @@ -12,6 +12,7 @@ const { test } = require('node:test'); const assert = require('node:assert/strict'); const path = require('node:path'); const { execFileSync } = require('node:child_process'); +const { REAL_REPO_GIT_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const ROOT = path.resolve(__dirname, '..'); const MARKER = 'pending #3212'; @@ -38,7 +39,7 @@ function listTrackedFiles() { const stdout = execFileSync('git', ['-c', 'safe.directory=*', 'ls-files'], { cwd: ROOT, encoding: 'utf8', - timeout: 30000, + timeout: REAL_REPO_GIT_TIMEOUT_MS, }); return stdout .split(/\r?\n/) diff --git a/tests/representative-corpus.test.cjs b/tests/representative-corpus.test.cjs index 1bc6cf587..bea77e276 100644 --- a/tests/representative-corpus.test.cjs +++ b/tests/representative-corpus.test.cjs @@ -49,6 +49,7 @@ const path = require('node:path'); const { execFileSync } = require('node:child_process'); const { cleanup, TEST_ENV_BASE } = require('./helpers.cjs'); +const { LOOP_HOOK_POINT_CLI_TIMEOUT_MS } = require('./helpers/timeouts.cjs'); const TOOLS_PATH = path.join(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs'); const FIXTURES_ROOT = path.join(__dirname, 'fixtures', 'representative'); @@ -59,7 +60,7 @@ function runTools(args, cwd) { cwd, encoding: 'utf-8', env: { ...process.env, ...TEST_ENV_BASE }, - timeout: 60000, + timeout: LOOP_HOOK_POINT_CLI_TIMEOUT_MS, }); return { success: true, output: stdout.trim(), error: '' }; } catch (err) {