Files
deepseek-harness/.github/workflows/ci.yml
T
Tianyi Cui cff614d37d ci: run the pull-request Windows blocking gates under Wine on hosted Linux
The required windows job moves from windows-2025 to ubuntu-latest, running
checksum-verified Windows Node under Wine at Linux-job wall clock (2m46s
warm vs 7-9min); master's serial-windows native-kernel reference is
untouched, and a new master-only wine-apt-cache job seeds the apt cache
every pull request restores. The experiment workflow folds into ci.yml,
the Agent Note moves to implemented with measured results, and the two CI
topology notes update to the shipped facts.
2026-07-27 13:17:12 +08:00

891 lines
33 KiB
YAML

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.
node-24:
if: github.event_name == 'pull_request'
runs-on: 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
# Pull requests consume the default-branch cache but do not put cache
# compression and upload on the paid latency-critical path.
- uses: actions/cache/restore@v4
with:
path: /home/runner/.local/share/pnpm/store/v11
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Enable corepack and install dependencies
run: |
corepack enable
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 packages/*/*/lib vendor/*/lib
- uses: actions/upload-artifact@v6
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: dsh-enterprise-ubuntu-24-04-32core-test
name: node 24 / coverage
env:
DSH_COVERAGE_MAX_WORKERS: '24'
DSH_GATE_CONCURRENCY: '8'
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/cache/restore@v4
with:
path: /home/runner/.local/share/pnpm/store/v11
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Enable corepack, install dependencies, and prepare bubblewrap
run: |
corepack enable
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: dsh-enterprise-ubuntu-latest-32core-test
name: node 24 / snapshots and artifacts
env:
DSH_ESLINT_CACHE: '1'
DSH_ESLINT_CONCURRENCY: '8'
DSH_GATE_CONCURRENCY: '8'
DSH_NODE_COMPAT_SKIP_TYPECHECK: '1'
DSH_PUBLINT_CONCURRENCY: '8'
DSH_SNAPSHOT_MAX_CONCURRENCY: '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: actions/cache/restore@v4
with:
path: /home/runner/.local/share/pnpm/store/v11
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-pnpm-
- uses: actions/cache/restore@v4
with:
path: .cache/eslint
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Enable corepack, install dependencies, and prepare bubblewrap
run: |
corepack enable
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 compatibility, snapshot, and artifact gates
run: |
pnpm run check:ci:lint &
lint_pid=$!
pnpm run check:node-compat &
compat_pid=$!
DSH_EXAMPLE_MODE=lib pnpm run test:snapshot &
snapshot_pid=$!
pnpm run publint &
publint_pid=$!
pnpm run verify-node-next-types &
node_next_pid=$!
pnpm run verify-built-package-invariants &
built_invariants_pid=$!
DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts \
examples/headless-agent/tests/keyless-smoke.e2e.ts \
examples/tui-agent/tests/tui-keyless-smoke.e2e.ts \
packages/examples/cli-demo/tests/built-bin.e2e.ts \
packages/examples/acp-demo/tests/built-bin.e2e.ts \
packages/ui/jsonrpc/tests/built-scope-carrier.e2e.ts \
packages/workflow/workflow-workerthread/tests/built-worker.e2e.ts \
packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts &
built_bin_pid=$!
final_status=0
capture_status() {
local child_status=0
wait "$1" || child_status=$?
if (( final_status == 0 && child_status != 0 )); then
final_status=$child_status
fi
}
for child_pid in \
"$lint_pid" "$compat_pid" "$snapshot_pid" \
"$publint_pid" "$node_next_pid" "$built_invariants_pid" "$built_bin_pid"
do
capture_status "$child_pid"
done
exit "$final_status"
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: actions/setup-node@v6
with:
node-version: ${{ matrix.node }}
- name: Enable corepack and resolve pnpm store path
id: pnpm-store
run: |
corepack enable
echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-store.outputs.path }}
key: ${{ runner.os }}-node-${{ matrix.node }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.node }}-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
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. Direct tool entrypoints stand in for pnpm's cmd
# shims, which a Linux-side install does not create; 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
env:
WINEDEBUG: '-all'
WINEARCH: win64
# Skip Wine Mono / Gecko installers: Node needs neither.
WINEDLLOVERRIDES: 'mscoree,mshtml='
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: /home/runner/.local/share/pnpm/store/v11
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 }}
- name: Install dependencies and provision Wine concurrently
run: |
corepack enable
# Windows-lane install-time overrides. supportedArchitectures
# additionally materializes the win32-x64 platform packages
# (@esbuild/win32-x64, rolldown and rollup MSVC bindings) the
# Windows toolchain resolves at runtime; nodeLinker: hoisted lays
# node_modules out flat with real files because Windows Node under
# Wine does not realpath pnpm's isolated-layout symlinks. Neither
# override is recorded in the lockfile, so --frozen-lockfile stays
# valid. --ignore-scripts skips Linux lifecycle scripts no gate in
# this lane loads; the win32 binaries ship prebuilt.
cat >> pnpm-workspace.yaml <<'EOF'
nodeLinker: hoisted
supportedArchitectures:
os: [current, win32]
cpu: [current, x64]
EOF
pnpm install --frozen-lockfile --ignore-scripts &
install_pid=$!
provision_wine() {
set -euo pipefail
# 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.
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
WINE_BIN=''
for candidate in "$(command -v wine || true)" "$(command -v wine64 || true)" /usr/lib/wine/wine64; do
if [ -n "$candidate" ] && [ -x "$candidate" ]; then WINE_BIN="$candidate"; break; fi
done
[ -n "$WINE_BIN" ] || { echo '::error::no wine binary found after install'; exit 1; }
echo "WINE_BIN=$WINE_BIN" >> "$GITHUB_ENV"
# Windows Node for the repo's primary line, checksum-verified
# against the same dist directory.
version=$(curl -fsSL https://nodejs.org/dist/index.json \
| jq -r --arg p "v${PRIMARY_NODE_VERSION}." '[.[] | select(.version | startswith($p))][0].version')
echo "Windows Node: $version"
curl -fsSL -o "$RUNNER_TEMP/node-win.zip" \
"https://nodejs.org/dist/${version}/node-${version}-win-x64.zip"
curl -fsSL "https://nodejs.org/dist/${version}/SHASUMS256.txt" \
| awk -v a="node-${version}-win-x64.zip" '$2 == a { print $1 " '"$RUNNER_TEMP"'/node-win.zip" }' \
| sha256sum --check -
unzip -q "$RUNNER_TEMP/node-win.zip" -d "$RUNNER_TEMP/node-win"
echo "NODE_WIN=$RUNNER_TEMP/node-win/node-${version}-win-x64/node.exe" >> "$GITHUB_ENV"
"$WINE_BIN" wineboot --init || true
wineserver -w || true
}
provision_wine &
wine_pid=$!
install_status=0
wait "$install_pid" || install_status=$?
wine_status=0
wait "$wine_pid" || wine_status=$?
if (( install_status != 0 )); then exit "$install_status"; fi
exit "$wine_status"
- name: Resolve entrypoints, link vue, smoke Windows Node
run: |
# Node under Wine cannot attach stdio to the Actions runner's pipes
# (Socket open EBADF at bootstrap), so every invocation runs through
# this wrapper: stdio to a regular file, replayed after exit.
cat > "$RUNNER_TEMP/wine-node.sh" <<'SH'
#!/usr/bin/env bash
set -u
log="$1"; shift
"$WINE_BIN" "$NODE_WIN" "$@" < /dev/null > "$log" 2>&1
status=$?
tail -n 300 "$log"
exit "$status"
SH
chmod +x "$RUNNER_TEMP/wine-node.sh"
resolve() {
local name="$1"; shift
for p in "$@"; do
if [ -f "$p" ]; then echo "$name=$PWD/$p" >> "$GITHUB_ENV"; return 0; fi
done
echo "::error::$name not found at any of: $*"; return 1
}
resolve TSC_JS node_modules/typescript/bin/tsc
resolve TSDOWN_JS node_modules/tsdown/dist/run.mjs
resolve VITEPRESS_JS website/node_modules/vitepress/bin/vitepress.js node_modules/vitepress/bin/vitepress.js
# VitePress links vue into the site's node_modules at build time;
# Wine cannot CREATE Windows symlinks (ENOTSUP) but follows
# pre-existing Unix ones, so lay the link down host-side.
if [ -d node_modules/vue ] && [ ! -e website/node_modules/vue ]; then
mkdir -p website/node_modules
ln -s ../../node_modules/vue website/node_modules/vue
fi
"$RUNNER_TEMP/wine-node.sh" "$RUNNER_TEMP/smoke.log" -p "'smoke: ' + process.platform + ' ' + process.arch + ' ' + process.version"
# The two blocking surfaces run concurrently, the same shape run-gates
# gives ci-windows-blocking on native Windows: `build` = tsc -b then
# tsdown, `production site` = the VitePress build. Both statuses are
# captured so one failure cannot hide the other's result.
- name: Run blocking Windows gates concurrently under Wine
run: |
build_gate() {
"$RUNNER_TEMP/wine-node.sh" "$RUNNER_TEMP/tsc.log" "$TSC_JS" -b --pretty false || return $?
"$RUNNER_TEMP/wine-node.sh" "$RUNNER_TEMP/tsdown.log" "$TSDOWN_JS"
}
site_gate() {
cd website
"$RUNNER_TEMP/wine-node.sh" "$RUNNER_TEMP/site.log" "$VITEPRESS_JS" build .
}
start=$SECONDS
build_gate > "$RUNNER_TEMP/build-gate.out" 2>&1 &
build_pid=$!
site_gate > "$RUNNER_TEMP/site-gate.out" 2>&1 &
site_pid=$!
build_status=0
wait "$build_pid" || build_status=$?
site_status=0
wait "$site_pid" || site_status=$?
echo "== build gate (exit $build_status, $((SECONDS - start))s elapsed) =="
tail -n 120 "$RUNNER_TEMP/build-gate.out"
echo "== production site gate (exit $site_status, $((SECONDS - start))s elapsed) =="
tail -n 120 "$RUNNER_TEMP/site-gate.out"
if (( build_status != 0 )); then exit "$build_status"; fi
exit "$site_status"
- 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: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Enable corepack and resolve pnpm store path
id: pnpm-store
run: |
corepack enable
echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
# Master refreshes the caches that pull requests restore without saving.
- 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-
- uses: actions/cache@v4
with:
path: .cache/eslint
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
- name: Install (immutable)
run: pnpm install --frozen-lockfile
- 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_ESLINT_CACHE: '1'
DSH_GATE_CONCURRENCY: '1'
DSH_PUBLINT_CONCURRENCY: '1'
DSH_SNAPSHOT_MAX_CONCURRENCY: '1'
run: pnpm run check:ci
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: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Enable corepack (pnpm)
run: corepack enable
- 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: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- name: Enable corepack (pnpm)
shell: pwsh
run: corepack enable
# Master refreshes the small cache that pull requests restore without
# putting package-store extraction back on the Windows critical path.
- uses: actions/cache@v4
with:
path: .cache/eslint
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
- 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_ESLINT_CACHE: '1'
DSH_GATE_CONCURRENCY: '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: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- 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: Enable corepack (pnpm)
run: corepack enable
- name: Resolve pnpm store path
if: matrix.platform == 'linux'
id: pnpm-store
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v4
if: matrix.platform == 'linux'
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 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: actions/setup-node@v6
with:
node-version: ${{ env.PRIMARY_NODE_VERSION }}
- 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: Enable corepack (pnpm)
run: corepack enable
- name: Resolve pnpm store path (Linux)
if: matrix.platform == 'linux'
id: pnpm-store-linux
run: echo "path=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
- name: Resolve pnpm store path (Windows)
if: matrix.platform == 'windows'
id: pnpm-store-windows
shell: pwsh
run: '"path=$(pnpm store path --silent)" >> $env:GITHUB_OUTPUT'
- uses: actions/cache@v4
with:
path: ${{ steps.pnpm-store-linux.outputs.path || steps.pnpm-store-windows.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-
- uses: actions/cache@v4
if: matrix.platform == 'linux'
with:
path: .cache/eslint
key: ${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-${{ hashFiles('pnpm-lock.yaml', 'eslint.config.mjs', 'tsconfig.json', 'tsconfig.base.json', 'tsconfig.base.client.json', 'tsconfig.host.json', 'tsconfig.client.json', 'packages/*/*/tsconfig.json', 'examples/*/tsconfig.json') }}
restore-keys: |
${{ runner.os }}-node-${{ env.PRIMARY_NODE_VERSION }}-eslint-full-
- 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_ESLINT_CACHE: '1'
DSH_ESLINT_CONCURRENCY: ${{ matrix.workers }}
DSH_GATE_CONCURRENCY: ${{ 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
# The required verdict must not add a separate standard-hosted billing dependency.
runs-on: dsh-enterprise-ubuntu-latest-32core-test
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, ', ') }})"