Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/agents/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,5 @@ There is no unit-test retry layer—fix or remove flakes.
- Keep Vitest isolation enabled and the pool on forks. Both alternatives were measured and did not
improve the suite; importing the module under test rather than a platform barrel is the useful
optimization.
- Raise the two-worker local cap only for a solo run: `AGENT_DEVICE_VITEST_MAX_WORKERS=<n>`,
clamped to host CPUs, ignored in CI.
30 changes: 29 additions & 1 deletion scripts/lib/vitest-concurrency.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
import os from 'node:os';

/**
* Keep one Vitest invocation modest enough to coexist with two other Codex
* worktrees on a 12-core development host: 3 agents + (3 suites * 2 workers)
* leaves roughly 3 cores for runners, subprocesses, simulators, and the OS.
*/
export const DEFAULT_VITEST_MAX_WORKERS = 2;

/**
* Opt-in escape hatch for a solo local run that owns the whole machine (see
* docs/agents/testing.md). Ignored in CI, which already derives its own
* worker count from the isolated runner's CPU pool.
*/
export const VITEST_MAX_WORKERS_OVERRIDE_ENV = 'AGENT_DEVICE_VITEST_MAX_WORKERS';

export function resolveVitestMaxWorkers(env: NodeJS.ProcessEnv = process.env): number | undefined {
return env.CI === 'true' ? undefined : DEFAULT_VITEST_MAX_WORKERS;
if (env.CI === 'true') return undefined;

const override = parsePositiveInt(env[VITEST_MAX_WORKERS_OVERRIDE_ENV]);
// Clamp rather than trust the override literally: a typo like `999` must not
// oversubscribe the host the way the default cap above exists to prevent.
// availableParallelism(), not cpus().length: Node documents the latter as
// unfit for sizing parallelism because it ignores CPU affinity and cgroup
// limits, which would inflate the ceiling this clamp exists to enforce.
if (override !== undefined) return Math.min(override, os.availableParallelism());

return DEFAULT_VITEST_MAX_WORKERS;
}

// A missing, blank, non-numeric, non-integer, or non-positive value falls
// through to the default cap instead of throwing or coercing to something
// surprising (e.g. `Number('')` is 0, not NaN).
function parsePositiveInt(value: string | undefined): number | undefined {
if (value === undefined || value.trim() === '') return undefined;
const parsed = Number(value);
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
}
30 changes: 30 additions & 0 deletions src/__tests__/hermetic-env-setup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import assert from 'node:assert/strict';
import {
DEFAULT_VITEST_MAX_WORKERS,
resolveVitestMaxWorkers,
VITEST_MAX_WORKERS_OVERRIDE_ENV,
} from '../../scripts/lib/vitest-concurrency.ts';
import vitestConfig from '../../vitest.config.ts';

Expand All @@ -23,6 +24,35 @@ test('vitest caps aggregate worker concurrency for parallel worktrees', () => {
assert.equal(resolveVitestMaxWorkers({ CI: 'true' }), undefined);
});

// The opt-in solo-run escape hatch (#1962). These live here rather than beside the
// resolver so the mutation lane's `vitest related` graph is not widened by a new
// test file: this one is already in the unit-core suite and already imports it.
test('a solo run may raise the local worker cap, clamped and CI-ignored', () => {
// Clamped to availableParallelism(), never honored literally: cpus().length would
// ignore CPU affinity and cgroup limits and inflate the ceiling this enforces.
assert.equal(
resolveVitestMaxWorkers({ [VITEST_MAX_WORKERS_OVERRIDE_ENV]: '999' }),
os.availableParallelism(),
);
// 1 is <= availableParallelism() on every host, so this takes the override branch.
assert.equal(resolveVitestMaxWorkers({ [VITEST_MAX_WORKERS_OVERRIDE_ENV]: '1' }), 1);
// CI derives its own count, so the override is inert there even when both are set.
assert.equal(
resolveVitestMaxWorkers({ CI: 'true', [VITEST_MAX_WORKERS_OVERRIDE_ENV]: '8' }),
undefined,
);
});

test('an unusable worker override falls through to the default cap', () => {
for (const value of ['not-a-number', '0', '-4', '2.5', '', ' ']) {
assert.equal(
resolveVitestMaxWorkers({ [VITEST_MAX_WORKERS_OVERRIDE_ENV]: value }),
DEFAULT_VITEST_MAX_WORKERS,
`${JSON.stringify(value)} must degrade to the default cap rather than throw`,
);
}
});

// Wiring: the scrub only helps if every project loads it as a setup file. CI runs with the
// vars unset, so a dropped wiring is otherwise invisible — assert it structurally instead.
test('every vitest project wires the hermetic-env setup', () => {
Expand Down
Loading