diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5c9f483db5..de0a70a6f7 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -270,18 +270,25 @@ jobs: fail-fast: false matrix: include: + # A successful PR run on 2026-08-04 (30876682788) spent 256s in + # serialized shard 2/4, making its 305s job the run's slowest check. + # Five shards reduce the measured 739s suite total to about 148s per + # runner before setup overhead. - shard_index: 0 - shard_count: 4 - shard_label: 1/4 + shard_count: 5 + shard_label: 1/5 - shard_index: 1 - shard_count: 4 - shard_label: 2/4 + shard_count: 5 + shard_label: 2/5 - shard_index: 2 - shard_count: 4 - shard_label: 3/4 + shard_count: 5 + shard_label: 3/5 - shard_index: 3 - shard_count: 4 - shard_label: 4/4 + shard_count: 5 + shard_label: 4/5 + - shard_index: 4 + shard_count: 5 + shard_label: 5/5 steps: - name: Checkout repository diff --git a/.github/workflows/release-verify.yml b/.github/workflows/release-verify.yml index 890dd4aea4..cac52d75b5 100644 --- a/.github/workflows/release-verify.yml +++ b/.github/workflows/release-verify.yml @@ -109,17 +109,20 @@ jobs: matrix: include: - shard_index: 0 - shard_count: 4 - shard_label: 1/4 + shard_count: 5 + shard_label: 1/5 - shard_index: 1 - shard_count: 4 - shard_label: 2/4 + shard_count: 5 + shard_label: 2/5 - shard_index: 2 - shard_count: 4 - shard_label: 3/4 + shard_count: 5 + shard_label: 3/5 - shard_index: 3 - shard_count: 4 - shard_label: 4/4 + shard_count: 5 + shard_label: 4/5 + - shard_index: 4 + shard_count: 5 + shard_label: 5/5 steps: - name: Checkout repository diff --git a/scripts/__tests__/release-verify-workflow.test.mjs b/scripts/__tests__/release-verify-workflow.test.mjs index 3bd0a616a8..b5911ab4e8 100644 --- a/scripts/__tests__/release-verify-workflow.test.mjs +++ b/scripts/__tests__/release-verify-workflow.test.mjs @@ -43,8 +43,8 @@ test("release verify workflow covers the same split test surface as stable PR ve ); } - for (const shardIndex of [0, 1, 2, 3]) { - assert.match(verifyWorkflow, new RegExp(`shard_index: ${shardIndex}[\\s\\S]*?shard_count: 4`)); + for (const shardIndex of [0, 1, 2, 3, 4]) { + assert.match(verifyWorkflow, new RegExp(`shard_index: ${shardIndex}[\\s\\S]*?shard_count: 5`)); } assert.match(verifyWorkflow, /pnpm test:run:general -- --group/); diff --git a/scripts/__tests__/run-vitest-stable-shard.test.mjs b/scripts/__tests__/run-vitest-stable-shard.test.mjs index 9b69130527..252629bc06 100644 --- a/scripts/__tests__/run-vitest-stable-shard.test.mjs +++ b/scripts/__tests__/run-vitest-stable-shard.test.mjs @@ -29,6 +29,18 @@ function dryRunJson(args) { } const SHARD_COUNT = 4; +const SERIALIZED_SHARD_COUNT = 5; + +test("the serialized shards form a complete, non-overlapping partition", () => { + const shards = Array.from({ length: SERIALIZED_SHARD_COUNT }, (_, index) => + dryRunJson(["--mode", "serialized", "--shard-index", String(index), "--shard-count", String(SERIALIZED_SHARD_COUNT)]), + ); + + const total = shards[0].serializedSuiteCount; + const selected = shards.flatMap((shard) => shard.selectedSerializedSuites); + assert.equal(selected.length, total, "every serialized suite must be selected exactly once"); + assert.equal(new Set(selected).size, total, "serialized shards must not overlap"); +}); test("the general-server shards form a complete, non-overlapping partition", () => { const shards = Array.from({ length: SHARD_COUNT }, (_, index) =>