Skip to content

Commit f506070

Browse files
authored
improve(ci): shorten compact PR test critical path (#104508)
* perf(ci): rebalance compact PR test jobs * fix(ci): preserve compact whole-job timeout
1 parent b313685 commit f506070

3 files changed

Lines changed: 32 additions & 3 deletions

File tree

docs/ci.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ The slowest Node test families are split or balanced so each job stays small wit
9797
- Auto-reply runs as balanced workers, with the reply subtree split into agent-runner, commands, dispatch, session, and state-routing shards.
9898
- Agentic gateway/server (control-plane) configs split across chat, auth, model, HTTP/plugin, runtime, and startup lanes instead of waiting on built artifacts.
9999
- Normal CI packs only isolated infra include-pattern shards into deterministic bundles of at most 64 test files, reducing the Node matrix without merging non-isolated command/cron, stateful agents-core, or gateway/server suites. Heavy fixed suites stay on 8 vCPU while the bundled and lower-weight lanes use 4 vCPU.
100-
- Pull requests on the canonical repository use a compact admission plan: the same per-config groups run in isolated subprocesses, currently 20 Node test jobs instead of the 74-job full matrix. The serial tooling config is striped across three PR-only groups; `main` pushes, manual dispatches, and release gates retain the full matrix.
100+
- Pull requests on the canonical repository use a compact admission plan: the same per-config groups run in isolated subprocesses, currently 19 Node test jobs instead of the 74-job full matrix. A single whole-config batch is spread across existing same-runner compact jobs while retaining its 120-minute timeout, and the serial tooling config is striped across three PR-only groups; `main` pushes, manual dispatches, and release gates retain the full matrix.
101101
- Broad browser, QA, media, and miscellaneous plugin tests use their dedicated Vitest configs instead of the shared plugin catch-all. Include-pattern shards record timing entries using the CI shard name, so `.artifacts/vitest-shard-timings.json` can distinguish a whole config from a filtered shard.
102102
- `check-additional-*` stripes the supplemental boundary guard list (`scripts/run-additional-boundary-checks.mjs`) into one prompt-heavy shard (`check-additional-boundaries-a`, which includes the Codex prompt snapshot drift check) and one combined shard for the remaining stripes (`check-additional-boundaries-bcd`), each running independent guards concurrently and printing per-check timings. Package-boundary compile/canary work stays together, and runtime topology architecture runs separately from the gateway watch coverage embedded in `build-artifacts`.
103103
- Gateway watch, channel tests, and the core support-boundary shard run concurrently inside `build-artifacts` after `dist/` and `dist-runtime/` are already built.

scripts/lib/ci-node-test-plan.mjs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1190,7 +1190,26 @@ function createCompactNodeTestShardBundles(options = {}) {
11901190

11911191
const wholeGroups = sortedGroups.filter((candidate) => !candidate.includePatterns);
11921192
const wholeJobCount = Math.ceil(wholeGroups.length / COMPACT_WHOLE_NODE_TEST_JOB_GROUPS);
1193-
const wholeGroupBatches = createStripedBatches(wholeGroups, wholeJobCount);
1193+
// A lone whole-config job serializes every fixed suite and owns PR wall time.
1194+
// Fold it into same-runner jobs when caps allow, retaining the whole-config timeout.
1195+
const canSpreadWholeGroups =
1196+
wholeJobCount === 1 &&
1197+
bins.length > 1 &&
1198+
bins.every(
1199+
(bin) =>
1200+
bin.groups.length + Math.ceil(wholeGroups.length / bins.length) <=
1201+
COMPACT_NODE_TEST_JOB_GROUPS,
1202+
);
1203+
const wholeGroupBatches = canSpreadWholeGroups
1204+
? []
1205+
: createStripedBatches(wholeGroups, wholeJobCount);
1206+
if (canSpreadWholeGroups) {
1207+
for (const [index, group] of wholeGroups.entries()) {
1208+
const bin = bins[index % bins.length];
1209+
bin.groups.push(group);
1210+
bin.timeoutMinutes = COMPACT_WHOLE_NODE_TEST_TIMEOUT_MINUTES;
1211+
}
1212+
}
11941213
for (const [index, groupBatch] of wholeGroupBatches.entries()) {
11951214
const runnerClass = groupBatch[0].runner.includes("-8vcpu-") ? "large" : "small";
11961215
const distSuffix = groupBatch[0].requiresDist ? "-dist" : "";
@@ -1213,6 +1232,7 @@ function createCompactNodeTestShardBundles(options = {}) {
12131232
requiresDist: bin.groups[0].requiresDist,
12141233
runner: bin.groups[0].runner,
12151234
shardName: `compact-${runnerClass}-${index + 1}`,
1235+
...(bin.timeoutMinutes ? { timeoutMinutes: bin.timeoutMinutes } : {}),
12161236
});
12171237
}
12181238
}

test/scripts/ci-node-test-plan.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
180180
compact: true,
181181
});
182182

183-
expect(compact).toHaveLength(20);
183+
expect(compact).toHaveLength(19);
184184
expect(compact.every((shard) => Array.isArray(shard.groups))).toBe(true);
185185
expect(compact.some((shard) => shard.requiresDist)).toBe(true);
186186
expect(
@@ -228,6 +228,15 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => {
228228
.filter((shard) => shard.groups.some((group) => !group.includePatterns))
229229
.every((shard) => shard.timeoutMinutes === 120),
230230
).toBe(true);
231+
const largeJobs = compact.filter((shard) =>
232+
shard.checkName.startsWith("checks-node-compact-large-"),
233+
);
234+
expect(
235+
largeJobs.map((shard) => shard.groups.filter((group) => !group.includePatterns).length),
236+
).toEqual([2, 2, 2]);
237+
expect(
238+
compact.some((shard) => shard.checkName.startsWith("checks-node-compact-large-whole-")),
239+
).toBe(false);
231240
const smallWholeJobs = compact.filter((shard) =>
232241
shard.checkName.startsWith("checks-node-compact-small-whole-"),
233242
);

0 commit comments

Comments
 (0)