From 7d3bc4d944cd635789d4dd19f4d6cb1ff74d7604 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 22 Jun 2026 14:05:40 +0800 Subject: [PATCH] fix(ci): bundle test shards and right-size runners Bundles only isolated low-risk Node shards, keeps stateful suites isolated, and right-sizes Blacksmith runners to reduce runner-registration bursts. Exact-head CI run 27932220655 passed the changed CI planning lanes; its two remaining agent test reds match latest main baseline run 27929063460 and are unrelated to this CI-only diff. --- .github/workflows/ci.yml | 31 +++-- docs/ci.md | 20 ++-- scripts/lib/ci-node-test-plan.mjs | 112 ++++++++++++++++++ test/scripts/ci-node-test-plan.test.ts | 45 ++++++- test/scripts/ci-workflow-guards.test.ts | 30 +++++ .../plugin-prerelease-test-plan.test.ts | 2 +- 6 files changed, 220 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd2ce7310793..2018bd1f37fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -197,7 +197,7 @@ jobs: node --input-type=module <<'EOF' import { appendFileSync } from "node:fs"; import { - createNodeTestShards, + createNodeTestShardBundles, } from "./scripts/lib/ci-node-test-plan.mjs"; import { createChannelContractTestShards, @@ -273,7 +273,7 @@ jobs: } const nodeTestShards = runNodeFull - ? createNodeTestShards({ + ? createNodeTestShardBundles({ includeReleaseOnlyPluginShards: false, }).map((shard) => ({ check_name: shard.checkName, @@ -320,7 +320,14 @@ jobs: run_checks_windows: runWindows, checks_windows_matrix: createMatrix( runWindows - ? [{ check_name: "checks-windows-node-test", runtime: "node", task: "test" }] + ? [ + { + check_name: "checks-windows-node-test", + runtime: "node", + task: "test", + runner: "blacksmith-8vcpu-windows-2025", + }, + ] : [], ), run_macos_node: runMacos, @@ -558,7 +565,7 @@ jobs: contents: read needs: [preflight] if: needs.preflight.outputs.run_build_artifacts == 'true' - runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-32vcpu-ubuntu-2404' || 'ubuntu-24.04') }} + runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-16vcpu-ubuntu-2404' || 'ubuntu-24.04') }} timeout-minutes: 20 outputs: channels-result: ${{ steps.built_artifact_checks.outputs['channels-result'] }} @@ -1139,7 +1146,7 @@ jobs: name: ${{ matrix.check_name }} needs: [preflight] if: needs.preflight.outputs.run_checks_node_core_nondist == 'true' - runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-8vcpu-ubuntu-2404') || 'ubuntu-24.04') }} + runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }} timeout-minutes: 60 strategy: fail-fast: false @@ -1269,7 +1276,7 @@ jobs: runner: blacksmith-16vcpu-ubuntu-2404 - check_name: check-dependencies task: dependencies - runner: blacksmith-8vcpu-ubuntu-2404 + runner: blacksmith-4vcpu-ubuntu-2404 - check_name: check-test-types task: test-types runner: blacksmith-4vcpu-ubuntu-2404 @@ -1390,7 +1397,7 @@ jobs: name: ${{ matrix.check_name }} needs: [preflight] if: ${{ !cancelled() && always() && needs.preflight.outputs.run_check_additional == 'true' }} - runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04') }} + runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-24.04' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-4vcpu-ubuntu-2404') || 'ubuntu-24.04') }} timeout-minutes: 20 strategy: fail-fast: false @@ -1400,21 +1407,29 @@ jobs: - check_name: check-additional-boundaries-a group: boundaries boundary_shard: 1/4 + runner: blacksmith-8vcpu-ubuntu-2404 - check_name: check-additional-boundaries-bcd group: boundaries boundary_shard: 2/4,3/4,4/4 + runner: blacksmith-8vcpu-ubuntu-2404 - check_name: check-session-accessor-boundary group: session-accessor-boundary + runner: blacksmith-4vcpu-ubuntu-2404 - check_name: check-session-transcript-reader-boundary group: session-transcript-reader-boundary + runner: blacksmith-4vcpu-ubuntu-2404 - check_name: check-additional-extension-channels group: extension-channels + runner: blacksmith-8vcpu-ubuntu-2404 - check_name: check-additional-extension-bundled group: extension-bundled + runner: blacksmith-8vcpu-ubuntu-2404 - check_name: check-additional-extension-package-boundary group: extension-package-boundary + runner: blacksmith-8vcpu-ubuntu-2404 - check_name: check-additional-runtime-topology-architecture group: runtime-topology-architecture + runner: blacksmith-4vcpu-ubuntu-2404 steps: - name: Checkout shell: bash @@ -1757,7 +1772,7 @@ jobs: name: ${{ matrix.check_name }} needs: [preflight] if: needs.preflight.outputs.run_checks_windows == 'true' - runs-on: ${{ github.event_name == 'workflow_dispatch' && 'windows-2025' || (github.repository == 'openclaw/openclaw' && 'blacksmith-16vcpu-windows-2025' || 'windows-2025') }} + runs-on: ${{ github.event_name == 'workflow_dispatch' && 'windows-2025' || (github.repository == 'openclaw/openclaw' && (matrix.runner || 'blacksmith-8vcpu-windows-2025') || 'windows-2025') }} timeout-minutes: 60 env: NODE_OPTIONS: --max-old-space-size=8192 diff --git a/docs/ci.md b/docs/ci.md index 8080a72dbf5e..c950e71249ce 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -74,7 +74,7 @@ Scope logic lives in `scripts/ci-changed-scope.mjs` and is covered by unit tests - **CI routing-only edits, selected cheap core-test fixture edits, and narrow plugin contract helper/test-routing edits** use a fast Node-only manifest path: `preflight`, security, and a single `checks-fast-core` task. That path skips build artifacts, Node 22 compatibility, channel contracts, full core shards, bundled-plugin shards, and additional guard matrices when the change is limited to the routing or helper surfaces the fast task exercises directly. - **Windows Node checks** are scoped to Windows-specific process/path wrappers, npm/pnpm/UI runner helpers, package manager config, and the CI workflow surfaces that execute that lane; unrelated source, plugin, install-smoke, and test-only changes stay on the Linux Node lanes. -The slowest Node test families are split or balanced so each job stays small without over-reserving runners: plugin contracts and channel contracts each run as two weighted Blacksmith-backed shards with the standard GitHub runner fallback, core unit fast/support lanes run separately, core runtime infra is split between state, process/config, shared, and three cron domain shards, auto-reply runs as balanced workers (with the reply subtree split into agent-runner, dispatch, and commands/state-routing shards), and agentic gateway/server configs are split across chat/auth/model/http-plugin/runtime/startup lanes instead of waiting on built artifacts. 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. `check-additional-*` keeps package-boundary compile/canary work together and separates runtime topology architecture from gateway watch coverage; the boundary guard list is striped into one prompt-heavy shard and one combined shard for the remaining guard stripes, each running selected independent guards concurrently and printing per-check timings. The expensive Codex happy-path prompt snapshot drift check runs as its own additional job for manual CI and for prompt-affecting changes only, so normal unrelated Node changes do not wait behind cold prompt snapshot generation and the boundary shards stay balanced while prompt drift is still pinned to the PR that caused it; the same flag skips prompt snapshot Vitest generation inside the built-artifact core support-boundary shard. Gateway watch, channel tests, and the core support-boundary shard run concurrently inside `build-artifacts` after `dist/` and `dist-runtime/` are already built. +The slowest Node test families are split or balanced so each job stays small without over-reserving runners: plugin contracts and channel contracts each run as two weighted Blacksmith-backed shards with the standard GitHub runner fallback, core unit fast/support lanes run separately, core runtime infra is split between state, process/config, shared, and three cron domain shards, auto-reply runs as balanced workers (with the reply subtree split into agent-runner, dispatch, and commands/state-routing shards), and agentic gateway/server configs are split across chat/auth/model/http-plugin/runtime/startup lanes instead of waiting on built artifacts. Normal CI then 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. 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. `check-additional-*` keeps package-boundary compile/canary work together and separates runtime topology architecture from gateway watch coverage; the boundary guard list is striped into one prompt-heavy shard and one combined shard for the remaining guard stripes, each running selected independent guards concurrently and printing per-check timings. The expensive Codex happy-path prompt snapshot drift check runs as its own additional job for manual CI and for prompt-affecting changes only, so normal unrelated Node changes do not wait behind cold prompt snapshot generation and the boundary shards stay balanced while prompt drift is still pinned to the PR that caused it; the same flag skips prompt snapshot Vitest generation inside the built-artifact core support-boundary shard. Gateway watch, channel tests, and the core support-boundary shard run concurrently inside `build-artifacts` after `dist/` and `dist-runtime/` are already built. Android CI runs both `testPlayDebugUnitTest` and `testThirdPartyDebugUnitTest` and then builds the Play debug APK. The third-party flavor has no separate source set or manifest; its unit-test lane still compiles the flavor with the SMS/call-log BuildConfig flags, while avoiding a duplicate debug APK packaging job on every Android-relevant push. @@ -111,15 +111,15 @@ gh workflow run full-release-validation.yml --ref main -f ref= ## Runners -| Runner | Jobs | -| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ubuntu-24.04` | Manual CI dispatch and non-canonical repository fallbacks, workflow-sanity, labeler, auto-response, docs workflows outside CI, and install-smoke preflight so the Blacksmith matrix can queue earlier | -| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, `preflight`, `security-fast`, lower-weight extension shards, `checks-fast-core`, plugin/channel contract shards, `checks-node-compat-node22`, `check-guards`, `check-prod-types`, and `check-test-types` | -| `blacksmith-8vcpu-ubuntu-2404` | Linux Node test shards, bundled plugin test shards, `check-additional-*` shards, `check-dependencies`, and `android` | -| `blacksmith-16vcpu-ubuntu-2404` | `build-artifacts`, `check-lint` (CPU-sensitive enough that 8 vCPU cost more than they saved); install-smoke Docker builds (32-vCPU queue time cost more than it saved) | -| `blacksmith-16vcpu-windows-2025` | `checks-windows` | -| `blacksmith-6vcpu-macos-15` | `macos-node` on `openclaw/openclaw`; forks fall back to `macos-15` | -| `blacksmith-12vcpu-macos-26` | `macos-swift` on `openclaw/openclaw`; forks fall back to `macos-26` | +| Runner | Jobs | +| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ubuntu-24.04` | Manual CI dispatch and non-canonical repository fallbacks, workflow-sanity, labeler, auto-response, docs workflows outside CI, and install-smoke preflight so the Blacksmith matrix can queue earlier | +| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`, `preflight`, `security-fast`, lower-weight extension shards, `checks-fast-core`, plugin/channel contract shards, most bundled/lower-weight Linux Node shards, `check-guards`, `check-prod-types`, `check-test-types`, selected `check-additional-*` shards, and `check-dependencies` | +| `blacksmith-8vcpu-ubuntu-2404` | Retained heavy Linux Node suites, boundary/extension-heavy `check-additional-*` shards, and `android` | +| `blacksmith-16vcpu-ubuntu-2404` | `build-artifacts`, `check-lint` (CPU-sensitive enough that 8 vCPU cost more than they saved); install-smoke Docker builds (32-vCPU queue time cost more than it saved) | +| `blacksmith-8vcpu-windows-2025` | `checks-windows` | +| `blacksmith-6vcpu-macos-15` | `macos-node` on `openclaw/openclaw`; forks fall back to `macos-15` | +| `blacksmith-12vcpu-macos-26` | `macos-swift` on `openclaw/openclaw`; forks fall back to `macos-26` | Canonical-repo CI keeps Blacksmith as the default runner path for normal push and pull-request runs. `workflow_dispatch` and non-canonical repository runs use GitHub-hosted runners, but normal canonical runs do not currently probe Blacksmith queue health or automatically fall back to GitHub-hosted labels when Blacksmith is unavailable. diff --git a/scripts/lib/ci-node-test-plan.mjs b/scripts/lib/ci-node-test-plan.mjs index 8024393863ef..6fbf9c91199c 100644 --- a/scripts/lib/ci-node-test-plan.mjs +++ b/scripts/lib/ci-node-test-plan.mjs @@ -12,6 +12,26 @@ const EXCLUDED_FULL_SUITE_SHARDS = new Set([ const EXCLUDED_PROJECT_CONFIGS = new Set(["test/vitest/vitest.channels.config.ts"]); const DEFAULT_NODE_TEST_RUNNER = "blacksmith-8vcpu-ubuntu-2404"; +const BUNDLED_NODE_TEST_RUNNER = "blacksmith-4vcpu-ubuntu-2404"; +const MAX_BUNDLED_NODE_TEST_PATTERNS = 64; +// Commands and cron run non-isolated, so keep their split shards as separate +// processes. Combining their include lists can retain test state across groups. +const BUNDLEABLE_NODE_TEST_CONFIGS = new Set(["test/vitest/vitest.infra.config.ts"]); +const KEEP_LARGE_NODE_TEST_RUNNER = new Set([ + "agentic-agents-core-auth", + "agentic-agents-core-models", + "agentic-agents-core-runtime", + "agentic-agents-core-subagents", + "agentic-agents-embedded", + "agentic-agents-support", + "agentic-agents-core-runner", + "agentic-agents-core-tools", + "agentic-gateway-core", + "agentic-gateway-methods", + "auto-reply-reply-dispatch", + "core-runtime-media-ui", + "core-unit-fast", +]); const RELEASE_ONLY_PLUGIN_SHARDS = new Set(["agentic-plugins"]); function listTestFiles(rootDir) { return listTrackedTestFiles(rootDir); @@ -936,3 +956,95 @@ export function createNodeTestShards(options = {}) { ]; }); } + +function resolveCiNodeTestRunner(shard) { + if (shard.runner !== DEFAULT_NODE_TEST_RUNNER) { + return shard.runner; + } + return KEEP_LARGE_NODE_TEST_RUNNER.has(shard.shardName) + ? DEFAULT_NODE_TEST_RUNNER + : BUNDLED_NODE_TEST_RUNNER; +} + +function bundleNameForConfigs(configs) { + const config = configs[0] ?? "node"; + return config + .replace(/^test\/vitest\/vitest\./u, "") + .replace(/\.config\.ts$/u, "") + .replace(/[^a-z0-9-]+/giu, "-"); +} + +/** + * Collapse split include-pattern shards into bounded jobs for normal CI. + * The base plan remains unchanged for release and coverage consumers. + */ +export function createNodeTestShardBundles(options = {}) { + const shards = createNodeTestShards(options); + const unbundled = []; + const groups = new Map(); + + for (const shard of shards) { + const runner = resolveCiNodeTestRunner(shard); + if ( + shard.requiresDist || + shard.configs.length !== 1 || + !BUNDLEABLE_NODE_TEST_CONFIGS.has(shard.configs[0]) || + !Array.isArray(shard.includePatterns) || + shard.includePatterns.length === 0 + ) { + unbundled.push({ ...shard, runner }); + continue; + } + + const key = JSON.stringify([shard.configs, shard.requiresDist, runner]); + const group = groups.get(key) ?? { + configs: shard.configs, + requiresDist: shard.requiresDist, + runner, + shards: [], + }; + group.shards.push(shard); + groups.set(key, group); + } + + const bundled = []; + for (const group of groups.values()) { + const bins = []; + const sortedShards = group.shards.toSorted( + (a, b) => + (b.includePatterns?.length ?? 0) - (a.includePatterns?.length ?? 0) || + a.shardName.localeCompare(b.shardName), + ); + for (const shard of sortedShards) { + const patterns = shard.includePatterns ?? []; + for (let offset = 0; offset < patterns.length; offset += MAX_BUNDLED_NODE_TEST_PATTERNS) { + const chunk = patterns.slice(offset, offset + MAX_BUNDLED_NODE_TEST_PATTERNS); + const bin = bins.find( + (candidate) => + candidate.includePatterns.length + chunk.length <= MAX_BUNDLED_NODE_TEST_PATTERNS, + ); + if (bin) { + bin.includePatterns.push(...chunk); + } else { + bins.push({ includePatterns: [...chunk] }); + } + } + } + + const runnerClass = group.runner.includes("-8vcpu-") ? "large" : "small"; + const bundleName = `${bundleNameForConfigs(group.configs)}-${runnerClass}`; + for (const [index, bin] of bins.entries()) { + const shardName = `bundle-${bundleName}-${index + 1}`; + bundled.push({ + checkName: formatNodeTestShardCheckName(shardName), + shardName, + configs: group.configs, + includePatterns: bin.includePatterns.toSorted((a, b) => a.localeCompare(b)), + runner: group.runner, + requiresDist: group.requiresDist, + }); + } + } + + return [...unbundled, ...bundled].toSorted((a, b) => a.checkName.localeCompare(b.checkName)); +} diff --git a/test/scripts/ci-node-test-plan.test.ts b/test/scripts/ci-node-test-plan.test.ts index 145aaa19e058..f84924217f48 100644 --- a/test/scripts/ci-node-test-plan.test.ts +++ b/test/scripts/ci-node-test-plan.test.ts @@ -3,7 +3,10 @@ import { existsSync, readdirSync } from "node:fs"; import { join, relative, resolve } from "node:path"; import fg from "fast-glob"; import { describe, expect, it } from "vitest"; -import { createNodeTestShards } from "../../scripts/lib/ci-node-test-plan.mjs"; +import { + createNodeTestShardBundles, + createNodeTestShards, +} from "../../scripts/lib/ci-node-test-plan.mjs"; import { expectNoNodeFsScans } from "../../src/test-utils/fs-scan-assertions.js"; import { listGitTrackedFiles, sortRepoPaths, toRepoPath } from "../../src/test-utils/repo-files.js"; import { commandsLightTestFiles } from "../vitest/vitest.commands-light-paths.mjs"; @@ -107,6 +110,46 @@ describe("scripts/lib/ci-node-test-plan.mjs", () => { expect(payload.includePatterns).toBeGreaterThan(0); }); + it("bundles split shards deterministically without changing coverage", () => { + const base = createNodeTestShards({ includeReleaseOnlyPluginShards: false }); + const bundled = createNodeTestShardBundles({ includeReleaseOnlyPluginShards: false }); + const basePatterns = base + .flatMap((shard) => shard.includePatterns ?? []) + .toSorted((a, b) => a.localeCompare(b)); + const bundledPatterns = bundled + .flatMap((shard) => shard.includePatterns ?? []) + .toSorted((a, b) => a.localeCompare(b)); + + expect(bundled.length).toBeLessThan(base.length); + expect(bundledPatterns).toEqual(basePatterns); + expect( + bundled + .filter((shard) => shard.shardName.startsWith("bundle-")) + .every((shard) => (shard.includePatterns?.length ?? 0) <= 64), + ).toBe(true); + expect(bundled.every((shard) => shard.runner?.startsWith("blacksmith-"))).toBe(true); + expect(bundled).toEqual(createNodeTestShardBundles({ includeReleaseOnlyPluginShards: false })); + expect(bundled.find((shard) => shard.shardName === "core-unit-fast")?.runner).toBe( + DEFAULT_NODE_TEST_RUNNER, + ); + expect(bundled.find((shard) => shard.shardName === "bundle-infra-small-1")?.runner).toBe( + "blacksmith-4vcpu-ubuntu-2404", + ); + expect( + new Set( + bundled + .filter((shard) => shard.shardName.startsWith("bundle-")) + .flatMap((shard) => shard.configs), + ), + ).toEqual(new Set(["test/vitest/vitest.infra.config.ts"])); + expect(bundled.some((shard) => shard.shardName.startsWith("bundle-commands-"))).toBe(false); + expect(bundled.some((shard) => shard.shardName.startsWith("bundle-cron-"))).toBe(false); + expect(bundled.some((shard) => shard.shardName.startsWith("bundle-agents-core-"))).toBe(false); + expect(bundled.some((shard) => shard.shardName.startsWith("bundle-gateway-server-"))).toBe( + false, + ); + }); + it("splits the slow core unit shards while keeping paired source/security coverage", () => { const coreUnitShards = createNodeTestShards() .filter((shard) => shard.shardName.startsWith("core-unit-")) diff --git a/test/scripts/ci-workflow-guards.test.ts b/test/scripts/ci-workflow-guards.test.ts index 40d56b159e11..bf115164c6f1 100644 --- a/test/scripts/ci-workflow-guards.test.ts +++ b/test/scripts/ci-workflow-guards.test.ts @@ -104,6 +104,10 @@ describe("ci workflow guards", () => { it("bounds matrix fan-out for runner-registration pressure", () => { const workflow = readCiWorkflow(); + expect(workflow.concurrency.group).toContain("github.event.pull_request.number"); + expect(workflow.concurrency["cancel-in-progress"]).toContain( + "github.event_name == 'pull_request'", + ); expect(workflow.jobs["checks-fast-core"].strategy["max-parallel"]).toBe(4); expect(workflow.jobs["checks-node-core-test-nondist-shard"].strategy["max-parallel"]).toBe(6); expect(workflow.jobs["checks-fast-plugin-contracts-shard"].strategy["max-parallel"]).toBe(4); @@ -114,6 +118,30 @@ describe("ci workflow guards", () => { expect(workflow.jobs.android.strategy["max-parallel"]).toBe(2); }); + it("uses bundled Node shards and telemetry-backed runner sizes", () => { + const workflow = readCiWorkflow(); + const source = readFileSync(".github/workflows/ci.yml", "utf8"); + + expect(source).toContain("createNodeTestShardBundles"); + expect(workflow.jobs["build-artifacts"]["runs-on"]).toContain("blacksmith-16vcpu-ubuntu-2404"); + expect(workflow.jobs["checks-node-core-test-nondist-shard"]["runs-on"]).toContain( + "blacksmith-4vcpu-ubuntu-2404", + ); + expect(workflow.jobs["check-shard"].strategy.matrix.include).toContainEqual({ + check_name: "check-dependencies", + task: "dependencies", + runner: "blacksmith-4vcpu-ubuntu-2404", + }); + expect(workflow.jobs["check-additional-shard"]["runs-on"]).toContain("matrix.runner"); + expect(workflow.jobs["check-additional-shard"].strategy.matrix.include).toContainEqual({ + check_name: "check-session-accessor-boundary", + group: "session-accessor-boundary", + runner: "blacksmith-4vcpu-ubuntu-2404", + }); + expect(workflow.jobs["checks-windows"]["runs-on"]).toContain("matrix.runner"); + expect(source).toContain("blacksmith-8vcpu-windows-2025"); + }); + it("runs the session accessor ratchet as a visible additional check", () => { const workflow = readCiWorkflow(); const additionalJob = workflow.jobs["check-additional-shard"]; @@ -121,6 +149,7 @@ describe("ci workflow guards", () => { expect(matrixRows).toContainEqual({ check_name: "check-session-accessor-boundary", group: "session-accessor-boundary", + runner: "blacksmith-4vcpu-ubuntu-2404", }); const runStep = additionalJob.steps.find((step) => step.name === "Run additional check shard"); @@ -137,6 +166,7 @@ describe("ci workflow guards", () => { expect(matrixRows).toContainEqual({ check_name: "check-session-transcript-reader-boundary", group: "session-transcript-reader-boundary", + runner: "blacksmith-4vcpu-ubuntu-2404", }); const runStep = additionalJob.steps.find((step) => step.name === "Run additional check shard"); diff --git a/test/scripts/plugin-prerelease-test-plan.test.ts b/test/scripts/plugin-prerelease-test-plan.test.ts index 3f9430965e2b..be557875826e 100644 --- a/test/scripts/plugin-prerelease-test-plan.test.ts +++ b/test/scripts/plugin-prerelease-test-plan.test.ts @@ -364,7 +364,7 @@ describe("scripts/lib/plugin-prerelease-test-plan.mjs", () => { ).toEqual({ check_name: "check-dependencies", task: "dependencies", - runner: "blacksmith-8vcpu-ubuntu-2404", + runner: "blacksmith-4vcpu-ubuntu-2404", }); expect( workflow.jobs["check-shard"].steps.find((step) => step.name === "Run check shard").run,