Files
deepseek-harness/.github/workflows/ci.yml
T
2026-07-30 19:57:18 +08:00

859 lines
32 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: CI
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
inputs:
suite:
description: Manual CI suite to run
required: true
default: larger-runner-benchmark
type: choice
options:
- larger-runner-benchmark
- consolidated-runner-benchmark
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
PRIMARY_NODE_VERSION: '24'
jobs:
# Three enterprise jobs isolate coverage, static analysis, and the
# build-backed consumer tail. The static job publishes its exact build so
# consumers do not repeat the longest part of their critical path.
#
# FAILOVER: each Linux enterprise job resolves its pool through the
# DSH_CI_FAILOVER repository variable. Unset (normal), the expressions
# pick the hosted enterprise pools below. Setting the variable to
# 'selfhosted' (repo Settings → Actions → Variables; writer-manageable
# repository state — not PR-editable, no merge required) retargets all
# three onto the in-house
# vm-backup pool and re-running the failed jobs is the entire switch —
# see .agents/notes/implemented/process/2026-07-26-ci-failover-runbook.md. The
# in-house pool's readiness is re-proven on every master push by the
# serial-linux-selfhosted standby lane below.
node-24:
if: github.event_name == 'pull_request'
runs-on: >-
${{ vars.DSH_CI_FAILOVER == 'selfhosted'
&& github.event.pull_request.user.login != 'dependabot[bot]'
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|| 'dsh-enterprise-ubuntu-latest-32core-test' }}
name: node 24 / static
env:
DSH_GATE_CONCURRENCY: '8'
steps:
# Fetch complete history so the archive gate can read the trusted PR base from a reused shallow checkout.
- uses: actions/checkout@v6
with:
fetch-depth: 0
persist-credentials: false
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Configure pnpm store path
id: pnpm-store
run: |
store_root="$HOME/.local/share/pnpm/store"
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
echo "path=$store_path" >> "$GITHUB_OUTPUT"
# Pull requests consume the default-branch cache but do not put cache
# compression and upload on the paid latency-critical path. Skipped
# under failover — see the coverage lane's identical rationale.
- uses: actions/cache/restore@v4
if: vars.DSH_CI_FAILOVER != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
- name: Install (immutable)
run: pnpm install --frozen-lockfile
- name: Run static gates
env:
DSH_ARCHIVE_BASE_REF: ${{ github.event.pull_request.base.sha }}
run: pnpm run check:ci:static
- name: Pack built tree
run: >-
tar -czf "$RUNNER_TEMP/node-24-built-tree.tar.gz"
apps/*/lib apps/web/dist packages/*/*/lib vendor/*/lib
- uses: actions/upload-artifact@v7
with:
name: node-24-built-tree
path: ${{ runner.temp }}/node-24-built-tree.tar.gz
if-no-files-found: error
retention-days: 1
compression-level: 0
node-24-coverage:
if: github.event_name == 'pull_request'
runs-on: >-
${{ vars.DSH_CI_FAILOVER == 'selfhosted'
&& github.event.pull_request.user.login != 'dependabot[bot]'
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|| 'dsh-enterprise-ubuntu-24-04-32core-test' }}
name: node 24 / coverage
env:
# Failover shrinks the worker bound: the hosted 32-core runner is
# exclusive to one job, but the failover pool shares one 64-core VM
# across six always-on runner instances, and the timing-sensitive
# process suites have documented aggregate-contention failures.
# 8 × 6 instances = 48 workers worst case on 64 cores.
DSH_COVERAGE_MAX_WORKERS: ${{ vars.DSH_CI_FAILOVER == 'selfhosted' && github.event.pull_request.user.login != 'dependabot[bot]' && '8' || '12' }}
DSH_GATE_CONCURRENCY: '4'
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Configure pnpm store path
id: pnpm-store
run: |
store_root="$HOME/.local/share/pnpm/store"
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
echo "path=$store_path" >> "$GITHUB_OUTPUT"
# Skipped under failover: the self-hosted VM's persistent pnpm store
# already serves warm installs, while restoring the hosted archive
# would spend ~52 s pulling ~180 MB into that populated store.
- uses: actions/cache/restore@v4
if: vars.DSH_CI_FAILOVER != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
- name: Install dependencies and prepare bubblewrap
run: |
pnpm install --frozen-lockfile &
install_pid=$!
bash scripts/prepare-ci-bubblewrap.sh &
sandbox_pid=$!
install_status=0
wait "$install_pid" || install_status=$?
sandbox_status=0
wait "$sandbox_pid" || sandbox_status=$?
if (( install_status != 0 )); then exit "$install_status"; fi
exit "$sandbox_status"
- name: Run exhaustive coverage
run: pnpm run check:ci:coverage
node-24-consumers:
needs: node-24
if: github.event_name == 'pull_request'
runs-on: >-
${{ vars.DSH_CI_FAILOVER == 'selfhosted'
&& github.event.pull_request.user.login != 'dependabot[bot]'
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|| 'dsh-enterprise-ubuntu-latest-32core-test' }}
name: node 24 / snapshots and artifacts
env:
DSH_GATE_CONCURRENCY: '8'
DSH_NODE_COMPAT_SKIP_TYPECHECK: '1'
DSH_OXLINT_THREADS: '8'
DSH_PUBLINT_CONCURRENCY: '8'
# Failover halves snapshot concurrency for the shared 64-core VM.
DSH_SNAPSHOT_MAX_CONCURRENCY: ${{ vars.DSH_CI_FAILOVER == 'selfhosted' && github.event.pull_request.user.login != 'dependabot[bot]' && '12' || '32' }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/download-artifact@v8
with:
name: node-24-built-tree
path: ${{ runner.temp }}
- name: Restore built tree
run: tar -xzf "$RUNNER_TEMP/node-24-built-tree.tar.gz"
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Configure pnpm store path
id: pnpm-store
run: |
store_root="$HOME/.local/share/pnpm/store"
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
echo "path=$store_path" >> "$GITHUB_OUTPUT"
# Skipped under failover — see the coverage lane's identical rationale.
- uses: actions/cache/restore@v4
if: vars.DSH_CI_FAILOVER != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
# Pull requests restore the cache produced by serial-linux on master;
# they do not pay compression and upload on the required path.
- uses: actions/cache/restore@v4
if: vars.DSH_CI_FAILOVER != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install dependencies and prepare bubblewrap
run: |
pnpm install --frozen-lockfile &
install_pid=$!
bash scripts/prepare-ci-bubblewrap.sh &
sandbox_pid=$!
install_status=0
wait "$install_pid" || install_status=$?
sandbox_status=0
wait "$sandbox_pid" || sandbox_status=$?
if (( install_status != 0 )); then exit "$install_status"; fi
exit "$sandbox_status"
- name: Install Playwright Chromium and hosted dependencies
if: vars.DSH_CI_FAILOVER != 'selfhosted' || github.event.pull_request.user.login == 'dependabot[bot]'
run: pnpm --filter @deepseek-ai/dsh-frontend exec playwright install --with-deps chromium
# The persistent VM image owns Playwright's Linux system packages; do
# not mutate the shared host with apt on every failover run.
- name: Install Playwright Chromium on the failover VM
if: vars.DSH_CI_FAILOVER == 'selfhosted' && github.event.pull_request.user.login != 'dependabot[bot]'
run: pnpm --filter @deepseek-ai/dsh-frontend exec playwright install chromium
- name: Run compatibility, snapshot, and artifact gates
run: pnpm run check:ci:consumers
node-compat:
if: github.event_name == 'pull_request'
# Each compatibility contract receives an independent standard hosted job.
runs-on: ${{ matrix.runner }}
name: ${{ matrix.name }}
env:
DSH_GATE_CONCURRENCY: ${{ matrix.gate_concurrency }}
DSH_NODE_COMPAT_SKIP_TYPECHECK: '1'
strategy:
fail-fast: false
matrix:
include:
- node: '22.19'
name: node 22.19
runner: ubuntu-latest
gate_concurrency: '1'
- node: 26
name: node 26
runner: ubuntu-latest
gate_concurrency: '1'
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
cache: pnpm
- name: Install (immutable)
run: pnpm install --frozen-lockfile
- name: Run compatibility smokes
run: pnpm run check:node-compat
python-sdk:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
name: python 3.10 / keyless SDK
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6.3.0
with:
python-version: '3.10'
cache: pip
- name: Install uv
run: python -m pip install uv==0.11.23
- name: Run complete keyless Python suite
run: uv run --python 3.10 --group test --project python/sdk pytest
# The required pull-request Windows signal: the two blocking win32 surfaces
# (workspace build, production site) execute with real, checksum-verified
# Windows Node under Wine on standard hosted Linux. The master
# serial-windows job below keeps the complete native-kernel inventory —
# including the observational portability gates this lane does not run —
# on real windows-2025. This job only provisions runner state (caches,
# apt); scripts/wine-windows-gates.sh owns the gate logic and is the same
# script the optional local gate `pnpm run check:windows-wine` runs.
# Layout, fidelity limits, and measured timings live in
# .agents/notes/implemented/process/2026-07-27-wine-windows-gates-experiment.md
windows:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
name: windows node 24 / wine blocking
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Configure pnpm store path
id: pnpm-store
run: |
store_root="$HOME/.local/share/pnpm/store"
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
echo "path=$store_path" >> "$GITHUB_OUTPUT"
- uses: actions/cache/restore@v4
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
# Master's wine-apt-cache job seeds the default-branch scope every pull
# request can read; a save from this job only reaches reruns of the
# same merge ref.
- name: Compose Wine apt cache key
id: wine-cache-key
run: echo "key=wine-debs-${ImageOS:-linux}-${ImageVersion:-v0}" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v4
with:
path: ~/wine-debs
key: ${{ steps.wine-cache-key.outputs.key }}
# Runner provisioning only — a developer machine installs Wine through
# its own package manager; the gate script assumes a wine binary and
# fails loud without one. Wine from the apt cache when present; else
# download the full dependency closure once and keep it for the next
# run. The `wine` dispatcher package (not bare `wine64`) is what puts a
# binary on PATH.
- name: Install Wine
run: |
if compgen -G "$HOME/wine-debs/*.deb" > /dev/null; then
sudo apt-get install -y --no-install-recommends "$HOME"/wine-debs/*.deb
else
sudo apt-get update
sudo apt-get install -y --no-install-recommends --download-only wine
mkdir -p "$HOME/wine-debs"
cp /var/cache/apt/archives/*.deb "$HOME/wine-debs/" 2>/dev/null || true
sudo apt-get install -y --no-install-recommends wine
fi
- name: Run the Wine Windows gates
run: bash scripts/wine-windows-gates.sh
- name: Shut down wineserver
if: always()
run: wineserver -k 2>/dev/null || true
# Master seeds the Wine apt-archive cache in the default-branch scope,
# which every pull request's windows job can restore; saves from
# pull-request runs are scoped to their own merge ref and help nobody
# else. Runs in seconds when the image version already has a cache.
wine-apt-cache:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
name: wine apt cache
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Compose Wine apt cache key
id: wine-cache-key
run: echo "key=wine-debs-${ImageOS:-linux}-${ImageVersion:-v0}" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v4
id: wine-cache
with:
path: ~/wine-debs
key: ${{ steps.wine-cache-key.outputs.key }}
- name: Download the Wine dependency closure
if: steps.wine-cache.outputs.cache-hit != 'true'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends --download-only wine
mkdir -p "$HOME/wine-debs"
cp /var/cache/apt/archives/*.deb "$HOME/wine-debs/"
du -sh "$HOME/wine-debs"
# Master pushes run only the serial reference jobs below.
# Each host executes the complete, unsharded primary Node aggregate with one
# gate worker, giving reviewers a simple cross-platform oracle for completeness
# and timing.
serial-linux:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
name: serial / linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 2
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Configure pnpm store path
id: pnpm-store
run: |
store_root="$HOME/.local/share/pnpm/store"
echo "PNPM_CONFIG_STORE_DIR=$store_root" >> "$GITHUB_ENV"
store_path=$(PNPM_CONFIG_STORE_DIR="$store_root" pnpm store path --silent)
echo "path=$store_path" >> "$GITHUB_OUTPUT"
# Master refreshes the pnpm store cache that pull requests restore without saving.
# The store cache stays a hand-rolled actions/cache step rather than
# setup-node's `cache: pnpm`: the enterprise pull-request jobs above
# restore exactly this key and path, and setup-node's built-in cache
# uses its own key format — converting this producer would silently
# starve their documented restore-only optimization.
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
# Master produces the hosted Chromium cache restored by pull requests.
- uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install (immutable)
run: pnpm install --frozen-lockfile
- name: Install Playwright Chromium and system dependencies
run: pnpm --filter @deepseek-ai/dsh-frontend exec playwright install --with-deps chromium
- name: Prepare bubblewrap (unrestrict userns)
run: bash scripts/prepare-ci-bubblewrap.sh
- name: Run complete unsharded primary Node CI serially
env:
DSH_ARCHIVE_BASE_REF: ${{ github.event.before }}
DSH_COVERAGE_MAX_WORKERS: '1'
DSH_E2E_MAX_WORKERS: '1'
DSH_GATE_CONCURRENCY: '1'
DSH_OXLINT_THREADS: '1'
DSH_PUBLINT_CONCURRENCY: '1'
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
run: pnpm run check:ci:linux-primary
# Hot-standby drill for the in-house self-hosted pool: every master move
# re-runs the complete unsharded aggregate on the persistent 64-core VM,
# continuously proving that environment can take over a required lane if
# the hosted pools degrade (the switch is then setting the writer-manageable
# DSH_CI_FAILOVER variable — see the failover runbook, no merge required).
# Push-triggered, so this lane always executes the base branch's own
# workflow definition. (Under failover, pull_request jobs do reach these
# runners with the PR merge ref's workflow — the boundary there is
# repository membership: private, forking disabled, Dependabot excluded.)
# Non-blocking for
# pull requests; no cache steps because the VM's persistent pnpm store and
# tool caches make them redundant (and saving here would poison the hosted
# cache namespace with self-hosted paths).
serial-linux-selfhosted:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
name: serial / linux (self-hosted standby)
runs-on: [self-hosted, linux, x64, vm-backup]
steps:
# Full history + DSH_ARCHIVE_BASE_REF below: same frozen-archive
# comparison as serial-linux. Depth 2 would miss github.event.before
# on multi-commit or force pushes; full fetch is cheap here because
# checkout resolves against the VM's local mirror.
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Configure persistent pnpm store
run: echo "PNPM_CONFIG_STORE_DIR=$HOME/.local/share/pnpm/store" >> "$GITHUB_ENV"
- name: Install (immutable)
run: pnpm install --frozen-lockfile
# The persistent VM image owns Playwright's Linux system packages; this
# step also proves that browser provisioning remains usable for failover.
- name: Install Playwright Chromium
run: pnpm --filter @deepseek-ai/dsh-frontend exec playwright install chromium
- name: Prepare bubblewrap (unrestrict userns)
run: bash scripts/prepare-ci-bubblewrap.sh
- name: Run complete unsharded primary Node CI serially
env:
DSH_ARCHIVE_BASE_REF: ${{ github.event.before }}
DSH_COVERAGE_MAX_WORKERS: '1'
DSH_E2E_MAX_WORKERS: '1'
DSH_GATE_CONCURRENCY: '1'
DSH_OXLINT_THREADS: '1'
DSH_PUBLINT_CONCURRENCY: '1'
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
run: pnpm run check:ci:linux-primary
serial-macos:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
name: serial / macos
runs-on: macos-latest
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Install (immutable)
run: pnpm install --frozen-lockfile
- name: Run complete unsharded primary Node CI serially
env:
DSH_COVERAGE_MAX_WORKERS: '1'
DSH_E2E_MAX_WORKERS: '1'
DSH_GATE_CONCURRENCY: '1'
DSH_PUBLINT_CONCURRENCY: '1'
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
run: pnpm run check:ci
serial-windows:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
name: serial / windows
runs-on: windows-2025
steps:
- uses: actions/checkout@v6
- name: Enable Developer Mode (symlink support)
shell: pwsh
run: >-
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
/t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Install (immutable)
shell: pwsh
run: pnpm install --frozen-lockfile
- name: Run complete unsharded primary Node CI serially
shell: pwsh
env:
DSH_COVERAGE_MAX_WORKERS: '1'
DSH_E2E_MAX_WORKERS: '1'
DSH_GATE_CONCURRENCY: '1'
DSH_OXLINT_THREADS: '1'
DSH_PUBLINT_CONCURRENCY: '1'
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
run: pnpm run check:ci
# Manual, bounded comparison of the actual critical Linux and Windows lanes.
# The named pools are restricted at the organization level to this repository.
larger-runner-benchmark:
if: github.event_name == 'workflow_dispatch' && inputs.suite == 'larger-runner-benchmark'
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
strategy:
fail-fast: false
max-parallel: 12
matrix:
include:
- platform: linux
cores: '4'
runner: dsh-ubuntu-24-04-4core
workload: typecheck
- platform: linux
cores: '8'
runner: dsh-ubuntu-24-04-8core
workload: typecheck
- platform: linux
cores: '16'
runner: dsh-ubuntu-24-04-16core
workload: typecheck
- platform: linux
cores: '32'
runner: dsh-ubuntu-24-04-32core
workload: typecheck
- platform: linux
cores: '64'
runner: dsh-ubuntu-24-04-64core
workload: typecheck
- platform: linux
cores: '96'
runner: dsh-ubuntu-24-04-96core
workload: typecheck
- platform: windows
cores: '4'
runner: dsh-windows-2025-4core
workload: production-site
- platform: windows
cores: '8'
runner: dsh-windows-2025-8core
workload: production-site
- platform: windows
cores: '16'
runner: dsh-windows-2025-16core
workload: production-site
- platform: windows
cores: '32'
runner: dsh-windows-2025-32core
workload: production-site
- platform: windows
cores: '64'
runner: dsh-windows-2025-64core
workload: production-site
- platform: windows
cores: '96'
runner: dsh-windows-2025-96core
workload: production-site
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
# The Windows lanes deliberately skip the store cache like the required
# windows job; an empty cache input disables setup-node's caching.
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
cache: ${{ matrix.platform == 'linux' && 'pnpm' || '' }}
- name: Report runner capacity
run: >-
node -e "const os = require('node:os');
console.log(JSON.stringify({ arch: process.arch, cpus: os.cpus().length,
memoryGiB: Math.round(os.totalmem() / 2 ** 30) }))"
- name: Install (immutable)
run: pnpm install --frozen-lockfile
- name: Run critical Linux typecheck lane
if: matrix.platform == 'linux'
run: pnpm run typecheck
- name: Run critical Windows production-site lane
if: matrix.platform == 'windows'
run: pnpm run docs:build
# Manual comparison of the intended low-fanout topology. Linux runs the
# complete unsharded primary aggregate with bounded in-runner parallelism;
# Windows runs both blocking build surfaces concurrently through run-gates.
consolidated-runner-benchmark:
if: github.event_name == 'workflow_dispatch' && inputs.suite == 'consolidated-runner-benchmark'
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
strategy:
fail-fast: false
max-parallel: 12
matrix:
include:
- platform: linux
cores: '4'
runner: dsh-ubuntu-24-04-4core
workers: '4'
- platform: linux
cores: '8'
runner: dsh-ubuntu-24-04-8core
workers: '8'
- platform: linux
cores: '16'
runner: dsh-ubuntu-24-04-16core
workers: '16'
- platform: linux
cores: '32'
runner: dsh-ubuntu-24-04-32core
workers: '32'
- platform: linux
cores: '64'
runner: dsh-ubuntu-24-04-64core
workers: '32'
- platform: linux
cores: '96'
runner: dsh-ubuntu-24-04-96core
workers: '32'
- platform: windows
cores: '4'
runner: dsh-windows-2025-4core
workers: '2'
- platform: windows
cores: '8'
runner: dsh-windows-2025-8core
workers: '2'
- platform: windows
cores: '16'
runner: dsh-windows-2025-16core
workers: '2'
- platform: windows
cores: '32'
runner: dsh-windows-2025-32core
workers: '2'
- platform: windows
cores: '64'
runner: dsh-windows-2025-64core
workers: '2'
- platform: windows
cores: '96'
runner: dsh-windows-2025-96core
workers: '2'
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
with:
dest: ${{ runner.temp }}/setup-pnpm
# Unlike the larger-runner suite, both platforms cache the store here:
# the consolidated topology measures cache mechanics as workload.
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
cache: pnpm
- name: Report runner capacity
run: >-
node -e "const os = require('node:os');
console.log(JSON.stringify({ arch: process.arch, cpus: os.cpus().length,
memoryGiB: Math.round(os.totalmem() / 2 ** 30) }))"
- name: Install and prepare Linux
if: matrix.platform == 'linux'
run: |
pnpm install --frozen-lockfile &
install_pid=$!
bash scripts/prepare-ci-bubblewrap.sh &
sandbox_pid=$!
install_status=0
wait "$install_pid" || install_status=$?
sandbox_status=0
wait "$sandbox_pid" || sandbox_status=$?
if (( install_status != 0 )); then exit "$install_status"; fi
exit "$sandbox_status"
- name: Install (immutable)
if: matrix.platform == 'windows'
shell: pwsh
run: pnpm install --frozen-lockfile
- name: Run complete unsharded primary Node CI concurrently
if: matrix.platform == 'linux'
env:
DSH_COVERAGE_MAX_WORKERS: ${{ matrix.workers }}
DSH_GATE_CONCURRENCY: ${{ matrix.workers }}
DSH_OXLINT_THREADS: ${{ matrix.workers }}
DSH_PUBLINT_CONCURRENCY: ${{ matrix.workers }}
DSH_SNAPSHOT_MAX_CONCURRENCY: ${{ matrix.workers }}
run: pnpm run check:ci
- name: Run blocking Windows builds concurrently
if: matrix.platform == 'windows'
shell: pwsh
env:
DSH_GATE_CONCURRENCY: ${{ matrix.workers }}
run: pnpm run check:ci:windows-blocking
# Single stable required check for branch protection: require "all checks
# passed" instead of enumerating matrix legs whose names change as lanes and
# node versions evolve. Every blocking job in THIS workflow must be listed in
# `needs`; observational Windows gates share the required Windows job but are
# marked non-blocking inside run-gates. (`needs` cannot reach across workflow
# files; e2e.yml stays its own check.)
# `if: always()` is load-bearing: without it a failed dependency
# would SKIP this job, and GitHub counts a skipped required check as passing
# — so this job always runs and fails on any non-success result, including
# 'cancelled' and 'skipped'.
all-checks-passed:
name: all checks passed
# This bookkeeping-only verdict must not depend on custom-pool
# provisioning (master's #734 moved it to ubuntu-latest) — and under
# failover it follows the same selector as the worker jobs it
# aggregates, so a standard-hosted outage cannot strand the
# branch-protection verdict either (observed 2026-07-27).
runs-on: >-
${{ vars.DSH_CI_FAILOVER == 'selfhosted'
&& github.event.pull_request.user.login != 'dependabot[bot]'
&& fromJSON('["self-hosted", "linux", "x64", "vm-backup"]')
|| 'ubuntu-latest' }}
needs: [node-24, node-24-coverage, node-24-consumers, node-compat, python-sdk, windows]
if: always() && github.event_name == 'pull_request'
steps:
- name: Fail if any needed job did not succeed
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') || contains(needs.*.result, 'skipped')
run: |
echo "::error::Needed job results: ${{ join(needs.*.result, ', ') }}"
exit 1
- name: All checks passed
run: echo "All needed jobs succeeded (${{ join(needs.*.result, ', ') }})"