improve: cut CI critical path without more workers (#121807)

* test(ci): remove redundant builds from critical path

Amp-Thread-ID: https://ampcode.com/threads/T-019fee8d-665d-707b-a380-23f2a6a1ce03
Co-authored-by: Peter Steinberger <steipete@gmail.com>

* docs(ci): format runner table

Amp-Thread-ID: https://ampcode.com/threads/T-019fee8d-665d-707b-a380-23f2a6a1ce03
Co-authored-by: Peter Steinberger <steipete@gmail.com>

---------

Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Peter Steinberger
2026-08-10 20:21:20 -07:00
committed by GitHub
parent efe5d8d76e
commit ebfd3ba154
16 changed files with 77 additions and 147 deletions
+9 -2
View File
@@ -209,8 +209,8 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
compact: true,
});
expect(compact.length).toBeGreaterThanOrEqual(12);
expect(compact.length).toBeLessThanOrEqual(28);
// Rebalancing may change ownership but must not add CI workers.
expect(compact).toHaveLength(24);
expect(compact.every((shard) => Array.isArray(shard.groups))).toBe(true);
expect(compact.every((shard) => shard.groups.length <= 10)).toBe(true);
expect(compact.some((shard) => shard.requiresDist)).toBe(true);
@@ -231,6 +231,13 @@ describe("scripts/lib/ci-node-test-plan.mts", () => {
// Cheap stripes may legally co-locate in one bin; only existence matters.
expect(jobOf("core-unit-fast-1")).toBeGreaterThanOrEqual(0);
expect(jobOf("core-unit-fast-2")).toBeGreaterThanOrEqual(0);
const refreshedOutliers = [
"agentic-agents-core-runtime",
"agentic-agents-support",
"auto-reply-reply-commands-2",
"core-unit-fast-2",
];
expect(new Set(refreshedOutliers.map(jobOf)).size).toBe(refreshedOutliers.length);
// Spawn/signal-timing suites never mix with regular groups, and every
// compact bin runs serially: overlapping Vitest runs flake timing-
// sensitive tests on both runner classes.
+5 -4
View File
@@ -5478,8 +5478,8 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
"needs.preflight.outputs.run_ui_tests == 'true' && needs.preflight.outputs.compatibility_target != 'true'",
);
expect(uiE2e["runs-on"]).not.toBe(ui["runs-on"]);
// Each Chromium worker keeps serial file ownership while all four shards
// together remain required by the aggregate CI gate.
// Three serial workers own Control UI files while the fourth owns browser
// extension E2E; all four remain required by the aggregate CI gate.
expect(uiE2e["timeout-minutes"]).toBe(25);
expect(uiE2e.env).toEqual({ OPENCLAW_UI_E2E_SKIP_REAL_GATEWAY: "1" });
expect(uiE2e.strategy).toEqual({
@@ -5624,8 +5624,9 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
uiE2e.steps.find((step: WorkflowStep) => step.name === "Test Control UI end-to-end"),
"Control UI E2E suite",
);
expect(scenario.if).toBe("matrix.shard != 4");
expect(scenario.run).toBe(
"node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner --shard ${{ matrix.shard }}/4",
"node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner --shard ${{ matrix.shard }}/3",
);
const browserExtension = expectDefined(
uiE2e.steps.find(
@@ -5633,7 +5634,7 @@ printf '%s\n' "\${CURL_SUCCESS_IP:-203.0.113.7}"
),
"browser extension bootstrap E2E suite",
);
expect(browserExtension.if).toBe("matrix.shard == 1");
expect(browserExtension.if).toBe("matrix.shard == 4");
expect(browserExtension.run).toBe("pnpm test:e2e:browser-extension");
for (const { job } of routedUiE2eJobs) {
const jobContract = JSON.stringify(job);