Batch 14 of the ad hoc timeout literal migration (epic #4445). Replaces every bare numeric timeout/timeoutMs object-literal property in tests/gsd-statusline.test.cjs and tests/teams-status.test.cjs with a named constant, per eslint-rules/no-adhoc-timeout-literal.cjs. Removes these 2 files from the rule's allowlist. Issue #4525 cautions against forcing either file onto PROBE_TIMEOUT_MS without checking, since both invoke a "long-lived status renderer." Checking each file's actual production handler separately found the caution applies to one file and not the other: gsd-statusline.test.cjs's 7 sites all spawn hooks/gsd-statusline.js, which does real rendering work (context-window, git, teams state) -- two new file-local constants (STATUSLINE_HOOK_TIMEOUT_MS=4000, 6 sites; STATUSLINE_HOOK_GIT_SHIM_TIMEOUT_MS =5000, 1 site for a heavier git-shim test). teams-status.test.cjs's 5 sites spawn `gsd-tools.cjs query teams-status`, whose handler (gsd-core/bin/lib/teams-status.cjs's cmdTeamsStatus) is a lightweight env-truthiness check with no rendering or fan-out -- genuinely matching PROBE_TIMEOUT_MS's class, confirmed by reading the handler directly rather than assumed from the matching value. No new shared-helper constant is needed 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:
@@ -7,7 +7,6 @@
|
|||||||
"tests/code-review.test.cjs",
|
"tests/code-review.test.cjs",
|
||||||
"tests/dispatcher.test.cjs",
|
"tests/dispatcher.test.cjs",
|
||||||
"tests/gate-predicate-evaluator.test.cjs",
|
"tests/gate-predicate-evaluator.test.cjs",
|
||||||
"tests/gsd-statusline.test.cjs",
|
|
||||||
"tests/phase6-capstone-conformance.test.cjs",
|
"tests/phase6-capstone-conformance.test.cjs",
|
||||||
"tests/plan-phase-stall-detection.test.cjs",
|
"tests/plan-phase-stall-detection.test.cjs",
|
||||||
"tests/plan-review-convergence.test.cjs",
|
"tests/plan-review-convergence.test.cjs",
|
||||||
@@ -17,6 +16,5 @@
|
|||||||
"tests/reviewer-manifest-body.test.cjs",
|
"tests/reviewer-manifest-body.test.cjs",
|
||||||
"tests/reviewer-trust-disclosure.test.cjs",
|
"tests/reviewer-trust-disclosure.test.cjs",
|
||||||
"tests/run-tests-temp-root.test.cjs",
|
"tests/run-tests-temp-root.test.cjs",
|
||||||
"tests/shell-command-projection-dispatch.test.cjs",
|
"tests/shell-command-projection-dispatch.test.cjs"
|
||||||
"tests/teams-status.test.cjs"
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -24,6 +24,26 @@ const {
|
|||||||
} = require('../hooks/gsd-statusline.js');
|
} = require('../hooks/gsd-statusline.js');
|
||||||
const { cleanup, saveSessionEnv, restoreSessionEnv, clearSessionEnv } = require('./helpers.cjs');
|
const { cleanup, saveSessionEnv, restoreSessionEnv, clearSessionEnv } = require('./helpers.cjs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single hooks/gsd-statusline.js spawn, no fan-out -- the "long-lived
|
||||||
|
* status renderer" class (renders context-window percentage, git
|
||||||
|
* branch/status, active-teams state), a distinct and heavier operation
|
||||||
|
* than a trivial CLI query despite this file's own PROBE_TIMEOUT_MS-sized
|
||||||
|
* sibling class norm elsewhere in the suite.
|
||||||
|
*/
|
||||||
|
const STATUSLINE_HOOK_TIMEOUT_MS = 4000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The same hooks/gsd-statusline.js hook as STATUSLINE_HOOK_TIMEOUT_MS, but
|
||||||
|
* this one test rigs a custom PATH (a git shim directory) and
|
||||||
|
* CLAUDE_CONFIG_DIR override -- a heavier setup than the plain invocation,
|
||||||
|
* hence the larger pre-existing bound. Coincides numerically with
|
||||||
|
* tests/helpers/timeouts.cjs's SCAN_USAGE_ERROR_TIMEOUT_MS and
|
||||||
|
* MALFORMED_INPUT_HOOK_TIMEOUT_MS (both 5000ms) but describes neither of
|
||||||
|
* those operations -- kept local.
|
||||||
|
*/
|
||||||
|
const STATUSLINE_HOOK_GIT_SHIM_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
// ─── parseStateMd ───────────────────────────────────────────────────────────
|
// ─── parseStateMd ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
describe('parseStateMd', () => {
|
describe('parseStateMd', () => {
|
||||||
@@ -639,7 +659,7 @@ describe('context meter respects CLAUDE_CODE_AUTO_COMPACT_WINDOW (#2219)', () =>
|
|||||||
delete env.CLAUDE_CODE_AUTO_COMPACT_WINDOW;
|
delete env.CLAUDE_CODE_AUTO_COMPACT_WINDOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
const r = runHookSeam(hookPath, [], { input: payload, env, timeoutMs: 4000 });
|
const r = runHookSeam(hookPath, [], { input: payload, env, timeoutMs: STATUSLINE_HOOK_TIMEOUT_MS });
|
||||||
const stdout = r.stdout;
|
const stdout = r.stdout;
|
||||||
|
|
||||||
// Parse normalized used% from the statusline bar output (e.g. "60%")
|
// Parse normalized used% from the statusline bar output (e.g. "60%")
|
||||||
@@ -736,7 +756,7 @@ describe('context meter boundary: acw at/near totalCtx does not pin used at 100%
|
|||||||
input: payload,
|
input: payload,
|
||||||
env,
|
env,
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
timeout: 4000,
|
timeout: STATUSLINE_HOOK_TIMEOUT_MS,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
stdout = e.stdout || '';
|
stdout = e.stdout || '';
|
||||||
@@ -878,7 +898,7 @@ describe('todo-resolution: resolves in_progress task from the newest matching to
|
|||||||
input: payload,
|
input: payload,
|
||||||
env,
|
env,
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
timeout: 4000,
|
timeout: STATUSLINE_HOOK_TIMEOUT_MS,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
stdout = e.stdout || '';
|
stdout = e.stdout || '';
|
||||||
@@ -1656,7 +1676,7 @@ test('config-set statusline.show_context_tokens yes → rejected', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const r = runHookSeam(hookPath, [], { input: payload, timeoutMs: 4000 });
|
const r = runHookSeam(hookPath, [], { input: payload, timeoutMs: STATUSLINE_HOOK_TIMEOUT_MS });
|
||||||
// eslint-disable-next-line no-control-regex -- stripping ANSI SGR sequences from captured CLI output
|
// eslint-disable-next-line no-control-regex -- stripping ANSI SGR sequences from captured CLI output
|
||||||
return r.stdout.replace(/\x1b\[[0-9;]*m/g, '');
|
return r.stdout.replace(/\x1b\[[0-9;]*m/g, '');
|
||||||
}
|
}
|
||||||
@@ -2254,7 +2274,7 @@ test('config-set statusline.show_context_tokens yes → rejected', () => {
|
|||||||
workspace: { current_dir: dir },
|
workspace: { current_dir: dir },
|
||||||
session_id: `test-git-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
session_id: `test-git-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
||||||
});
|
});
|
||||||
const r = runHookSeam(hookPath, [], { input: payload, timeoutMs: 4000 });
|
const r = runHookSeam(hookPath, [], { input: payload, timeoutMs: STATUSLINE_HOOK_TIMEOUT_MS });
|
||||||
// eslint-disable-next-line no-control-regex -- stripping ANSI SGR sequences from captured CLI output
|
// eslint-disable-next-line no-control-regex -- stripping ANSI SGR sequences from captured CLI output
|
||||||
return r.stdout.replace(/\x1b\[[0-9;]*m/g, '');
|
return r.stdout.replace(/\x1b\[[0-9;]*m/g, '');
|
||||||
}
|
}
|
||||||
@@ -2514,7 +2534,7 @@ describe('evaluateUpdateCache lineage guard', () => {
|
|||||||
});
|
});
|
||||||
const r = runHookSeam(path.join(cold.hooksDir, 'gsd-statusline.js'), [], {
|
const r = runHookSeam(path.join(cold.hooksDir, 'gsd-statusline.js'), [], {
|
||||||
input: payload,
|
input: payload,
|
||||||
timeoutMs: 4000,
|
timeoutMs: STATUSLINE_HOOK_TIMEOUT_MS,
|
||||||
});
|
});
|
||||||
assert.equal(r.exitCode, 0, `must exit 0 on a build failure; stdout: ${r.stdout} stderr: ${r.stderr}`);
|
assert.equal(r.exitCode, 0, `must exit 0 on a build failure; stdout: ${r.stdout} stderr: ${r.stderr}`);
|
||||||
assert.equal(r.stdout, '', 'must degrade to empty output, not throw a stack trace to stdout');
|
assert.equal(r.stdout, '', 'must degrade to empty output, not throw a stack trace to stdout');
|
||||||
@@ -3056,7 +3076,7 @@ describe('evaluateUpdateCache lineage guard', () => {
|
|||||||
const r = runHookSeam(hookPath, [], {
|
const r = runHookSeam(hookPath, [], {
|
||||||
input: payload,
|
input: payload,
|
||||||
env: { ...process.env, PATH: `${shimDir}${path.delimiter}${process.env.PATH}`, CLAUDE_CONFIG_DIR: claudeDir },
|
env: { ...process.env, PATH: `${shimDir}${path.delimiter}${process.env.PATH}`, CLAUDE_CONFIG_DIR: claudeDir },
|
||||||
timeoutMs: 5000,
|
timeoutMs: STATUSLINE_HOOK_GIT_SHIM_TIMEOUT_MS,
|
||||||
});
|
});
|
||||||
assert.equal(r.outcome, OUTCOME.EXITED, `expected clean exit, got outcome=${r.outcome}`);
|
assert.equal(r.outcome, OUTCOME.EXITED, `expected clean exit, got outcome=${r.outcome}`);
|
||||||
assert.equal(r.exitCode, 0);
|
assert.equal(r.exitCode, 0);
|
||||||
|
|||||||
@@ -15,6 +15,20 @@ const path = require('node:path');
|
|||||||
const { spawnSync } = require('node:child_process');
|
const { spawnSync } = require('node:child_process');
|
||||||
|
|
||||||
const { resolveTeamsStatus } = require('../gsd-core/bin/lib/teams-status.cjs');
|
const { resolveTeamsStatus } = require('../gsd-core/bin/lib/teams-status.cjs');
|
||||||
|
/**
|
||||||
|
* Reuses the existing PROBE_TIMEOUT_MS constant rather than declaring a
|
||||||
|
* new one, despite this batch's own issue (#4525, epic #4445) cautioning
|
||||||
|
* against forcing a "long-lived status renderer" onto PROBE_TIMEOUT_MS
|
||||||
|
* without checking. Checked directly: gsd-core/bin/lib/teams-status.cjs's
|
||||||
|
* cmdTeamsStatus (what these 5 sites spawn via `gsd-tools.cjs query
|
||||||
|
* teams-status`) is a lightweight env-truthiness check plus one fast
|
||||||
|
* synchronous runtime resolution -- no rendering, no subprocess fan-out --
|
||||||
|
* genuinely matching PROBE_TIMEOUT_MS's class, not the heavier
|
||||||
|
* "long-lived renderer" class the issue's caution targets (that class is
|
||||||
|
* hooks/gsd-statusline.js, correctly kept off PROBE_TIMEOUT_MS in this
|
||||||
|
* same batch's sibling file, tests/gsd-statusline.test.cjs).
|
||||||
|
*/
|
||||||
|
const { PROBE_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
|
||||||
|
|
||||||
const gsdToolsPath = path.resolve(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
|
const gsdToolsPath = path.resolve(__dirname, '..', 'gsd-core', 'bin', 'gsd-tools.cjs');
|
||||||
|
|
||||||
@@ -120,7 +134,7 @@ describe('gsd-tools query teams-status — CLI subprocess tests', () => {
|
|||||||
[gsdToolsPath, 'query', 'teams-status'],
|
[gsdToolsPath, 'query', 'teams-status'],
|
||||||
{
|
{
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
timeout: 15000,
|
timeout: PROBE_TIMEOUT_MS,
|
||||||
env: makeEnv({ runtime: 'claude', teamsFlag: '1' }),
|
env: makeEnv({ runtime: 'claude', teamsFlag: '1' }),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -142,7 +156,7 @@ describe('gsd-tools query teams-status — CLI subprocess tests', () => {
|
|||||||
[gsdToolsPath, 'query', 'teams-status'],
|
[gsdToolsPath, 'query', 'teams-status'],
|
||||||
{
|
{
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
timeout: 15000,
|
timeout: PROBE_TIMEOUT_MS,
|
||||||
env: makeEnv({ runtime: 'claude' }),
|
env: makeEnv({ runtime: 'claude' }),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -158,7 +172,7 @@ describe('gsd-tools query teams-status — CLI subprocess tests', () => {
|
|||||||
[gsdToolsPath, 'query', 'teams-status', '--active'],
|
[gsdToolsPath, 'query', 'teams-status', '--active'],
|
||||||
{
|
{
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
timeout: 15000,
|
timeout: PROBE_TIMEOUT_MS,
|
||||||
env: makeEnv({ runtime: 'claude', teamsFlag: '1' }),
|
env: makeEnv({ runtime: 'claude', teamsFlag: '1' }),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -173,7 +187,7 @@ describe('gsd-tools query teams-status — CLI subprocess tests', () => {
|
|||||||
[gsdToolsPath, 'query', 'teams-status', '--active'],
|
[gsdToolsPath, 'query', 'teams-status', '--active'],
|
||||||
{
|
{
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
timeout: 15000,
|
timeout: PROBE_TIMEOUT_MS,
|
||||||
env: makeEnv({ runtime: 'claude' }),
|
env: makeEnv({ runtime: 'claude' }),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -186,7 +200,7 @@ describe('gsd-tools query teams-status — CLI subprocess tests', () => {
|
|||||||
[gsdToolsPath, 'query', 'teams-status', '--active'],
|
[gsdToolsPath, 'query', 'teams-status', '--active'],
|
||||||
{
|
{
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
timeout: 15000,
|
timeout: PROBE_TIMEOUT_MS,
|
||||||
env: makeEnv({ runtime: 'codex', teamsFlag: '1' }),
|
env: makeEnv({ runtime: 'codex', teamsFlag: '1' }),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user