Skip to content

test(coding-agent): format SDK host usage statistics (#2626) #4

test(coding-agent): format SDK host usage statistics (#2626)

test(coding-agent): format SDK host usage statistics (#2626) #4

Workflow file for this run

name: Dev CI
on:
push:
branches: [dev]
pull_request:
branches: [dev]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Planner: resolve changed-path relevance and the affected task plan once, then
# fan the plan out into per-task shards. Emits the matrix, has_tasks/has_native
# flags, and the resolved changed paths so every downstream job reuses this
# exact diff via CI_DEV_CHANGED_PATHS instead of re-resolving the base ref.
affected-plan:
name: Affected path validation / plan
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
relevant: ${{ steps.relevance.outputs.relevant }}
matrix: ${{ steps.plan.outputs.matrix }}
has_tasks: ${{ steps.plan.outputs.has_tasks }}
has_native: ${{ steps.plan.outputs.has_native }}
changed_paths: ${{ steps.plan.outputs.changed_paths }}
plan_mode: ${{ steps.plan.outputs.plan_mode }}
plan_digest: ${{ steps.plan.outputs.plan_digest }}
plan_source_sha: ${{ steps.plan.outputs.plan_source_sha }}
env:
GITHUB_EVENT_BEFORE: ${{ github.event.before }}
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
CI_DEV_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Verify checked-out source head
shell: bash
run: |
head="$(git rev-parse HEAD)"
test "$head" = "$CI_DEV_SOURCE_SHA" || { echo "Checked-out SHA $head does not match $CI_DEV_SOURCE_SHA"; exit 1; }
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3"
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
with:
toolchain: nightly-2026-04-29
- name: Compute changed-path relevance
id: relevance
run: bun scripts/ci-job-relevance.ts
- name: Compute affected task matrix
id: plan
run: bun scripts/ci-dev-affected.ts --matrix-json
- name: Upload canonical affected plan
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: dev-affected-plan-${{ github.run_id }}
path: .ci-dev-affected-plan.json
include-hidden-files: true
if-no-files-found: error
retention-days: 1
overwrite: true
windows-dev-doctor:
name: Windows dev:doctor
needs: [affected-plan]
if: ${{ needs.affected-plan.outputs.relevant == 'true' && contains(needs.affected-plan.outputs.changed_paths, 'scripts/dev-link') }}
runs-on: windows-latest
timeout-minutes: 60
env:
CI_DEV_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Verify checked-out source head
shell: pwsh
run: |
$head = (git rev-parse HEAD).Trim()
if ($head -ne $env:CI_DEV_SOURCE_SHA) { throw "Checked-out SHA $head does not match $env:CI_DEV_SOURCE_SHA" }
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3"
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
with:
toolchain: nightly-2026-04-29
- name: Prepend rustup toolchain bin to PATH
shell: bash
run: |
toolchain_bin="$(dirname "$(rustup which cargo)")"
echo "$toolchain_bin" >> "$GITHUB_PATH"
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: windows-dev-doctor-win32-x64
cache-on-failure: true
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/dev' }}
cache-workspace-crates: true
- name: Cache bun dependencies
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- run: bun install --frozen-lockfile
- name: Build native addon (win32-x64 baseline)
env:
TARGET_PLATFORM: win32
TARGET_ARCH: x64
TARGET_VARIANTS: baseline
run: bun run ci:build:native
- name: Verify Windows workspace shim and doctor
shell: pwsh
run: |
bun test scripts/dev-link.test.ts
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
bun run dev:doctor
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
# Native addon build runs once per run and publishes the built `.node` files as
# an artifact the runtime-dependent shards download. It is skipped when the
# plan needs no native build at all.
affected-native:
name: Affected path validation / native-build
needs: [affected-plan]
if: ${{ needs.affected-plan.outputs.has_native == 'true' }}
runs-on: ubuntu-22.04
timeout-minutes: 30
env:
CI_DEV_CHANGED_PATHS: ${{ needs.affected-plan.outputs.changed_paths }}
CI_DEV_PLAN_MODE: ${{ needs.affected-plan.outputs.plan_mode }}
CI_DEV_AFFECTED_PLAN: .ci-dev-affected-plan.json
CI_DEV_PLAN_DIGEST: ${{ needs.affected-plan.outputs.plan_digest }}
CI_DEV_PLAN_SOURCE_SHA: ${{ needs.affected-plan.outputs.plan_source_sha }}
CI_DEV_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Verify checked-out source head
shell: bash
run: |
head="$(git rev-parse HEAD)"
test "$head" = "$CI_DEV_SOURCE_SHA" || { echo "Checked-out SHA $head does not match $CI_DEV_SOURCE_SHA"; exit 1; }
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3"
- name: Download and validate canonical affected plan
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: dev-affected-plan-${{ github.run_id }}
path: .
- run: bun scripts/ci-dev-affected.ts --validate-plan
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
with:
toolchain: nightly-2026-04-29
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: dev-affected-native-linux-x64
cache-on-failure: true
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/dev' }}
cache-workspace-crates: true
- name: Cache bun dependencies
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- name: Install system deps
run: bash scripts/ci-install-system-deps.sh
- run: bun install --frozen-lockfile
- name: Build affected native addon(s)
run: bun scripts/ci-dev-affected.ts --native-build
- name: Verify required native addon variants
run: |
test -f packages/natives/native/pi_natives.linux-x64-baseline.node
test -f packages/natives/native/pi_natives.linux-x64-modern.node
- name: Upload native addon(s)
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: dev-affected-native-${{ github.run_id }}
path: |
packages/natives/native/pi_natives.linux-x64-baseline.node
packages/natives/native/pi_natives.linux-x64-modern.node
if-no-files-found: error
retention-days: 1
overwrite: true
# One shard per planned task on the broad runner. Native build tasks are
# excluded (they run in affected-native); shards that load the native addon at
# runtime download the prebuilt artifact instead of rebuilding it.
affected-shards:
name: Affected path validation / ${{ matrix.key }}
needs: [affected-plan, affected-native]
if: ${{ always() && needs.affected-plan.outputs.has_tasks == 'true' && needs.affected-native.result != 'failure' && needs.affected-native.result != 'cancelled' }}
runs-on: ubuntu-22.04
# Broad push-mode coding-agent/root test shards can need up to 90 minutes, but
# the bounded root-check must retain the same 30-minute fail-fast contract as
# Main CI. SDK closure remains outside that CI command.
timeout-minutes: ${{ matrix.key == 'root-check' && 30 || 90 }}
strategy:
fail-fast: false
max-parallel: 8
matrix: ${{ fromJSON(needs.affected-plan.outputs.matrix) }}
env:
CI_DEV_CHANGED_PATHS: ${{ needs.affected-plan.outputs.changed_paths }}
CI_DEV_PLAN_MODE: ${{ needs.affected-plan.outputs.plan_mode }}
CI_DEV_AFFECTED_PLAN: .ci-dev-affected-plan.json
CI_DEV_PLAN_DIGEST: ${{ needs.affected-plan.outputs.plan_digest }}
CI_DEV_PLAN_SOURCE_SHA: ${{ needs.affected-plan.outputs.plan_source_sha }}
CI_DEV_MATRIX_KEY: ${{ matrix.key }}
CI_DEV_MATRIX_IDENTITY: ${{ matrix.identity }}
CI_DEV_SHARD_INDEX: ${{ strategy.job-index }}
CI_DEV_MATRIX_RUST: ${{ matrix.rust }}
CI_DEV_MATRIX_NEXTEST: ${{ matrix.nextest }}
CI_DEV_MATRIX_NATIVE: ${{ matrix.native }}
CI_DEV_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 0
- name: Verify checked-out source head
shell: bash
run: |
head="$(git rev-parse HEAD)"
test "$head" = "$CI_DEV_SOURCE_SHA" || { echo "Checked-out SHA $head does not match $CI_DEV_SOURCE_SHA"; exit 1; }
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3"
- name: Download and validate canonical affected plan
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: dev-affected-plan-${{ github.run_id }}
path: .
- run: bun scripts/ci-dev-affected.ts --validate-plan
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
if: ${{ startsWith(matrix.key, 'python-') }}
with:
python-version: "3.11"
- uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
if: ${{ matrix.rust }}
with:
toolchain: nightly-2026-04-29
- uses: taiki-e/install-action@56545b37b57562edd73171cb6c62cc509db4c34e # v2
if: ${{ matrix.nextest }}
with:
tool: nextest
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
if: ${{ matrix.rust }}
with:
shared-key: dev-affected-rust-linux-x64
cache-on-failure: true
save-if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/dev' }}
cache-workspace-crates: true
- name: Cache bun dependencies
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
- name: Install system deps
run: bash scripts/ci-install-system-deps.sh
- run: bun install --frozen-lockfile
- name: Download native addon(s)
if: ${{ matrix.native }}
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: dev-affected-native-${{ github.run_id }}
path: packages/natives/native
- name: Run affected task shard
env:
AFFECTED_TASK_KEY: ${{ matrix.key }}
GITHUB_EVENT_BEFORE: ${{ github.event.before }}
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: bun scripts/ci-dev-affected.ts --task="$AFFECTED_TASK_KEY"
- name: Write shard completion receipt
run: |
bun -e 'await Bun.write(`.ci-dev-shard-receipts/${process.env.CI_DEV_SHARD_INDEX}.json`, JSON.stringify({ key: process.env.AFFECTED_TASK_KEY, identity: process.env.CI_DEV_MATRIX_IDENTITY }))'
env:
AFFECTED_TASK_KEY: ${{ matrix.key }}
- name: Upload shard completion receipt
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: dev-affected-shard-${{ github.run_id }}-${{ strategy.job-index }}
path: .ci-dev-shard-receipts/${{ strategy.job-index }}.json
include-hidden-files: true
if-no-files-found: error
retention-days: 1
overwrite: true
# This producer is deliberately not the protected status: the downstream job
# validates the finalized bundle downloaded by its immutable artifact ID.
affected-evidence-producer:
name: Affected path validation / evidence producer
if: ${{ always() }}
needs: [affected-plan, affected-native, affected-shards, windows-dev-doctor]
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
artifact_id: ${{ steps.upload-evidence.outputs.artifact-id }}
artifact_digest: ${{ steps.upload-evidence.outputs.artifact-digest }}
env:
CI_DEV_AFFECTED_PLAN: .ci-dev-affected-plan.json
CI_DEV_PLAN_DIGEST: ${{ needs.affected-plan.outputs.plan_digest }}
CI_DEV_PLAN_SOURCE_SHA: ${{ needs.affected-plan.outputs.plan_source_sha }}
CI_DEV_PLAN_MODE: ${{ needs.affected-plan.outputs.plan_mode }}
CI_DEV_SHARD_RECEIPTS: .ci-dev-shard-receipts
CI_DEV_EVIDENCE_ROOT: .
CI_DEV_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Verify checked-out source head
shell: bash
run: |
head="$(git rev-parse HEAD)"
test "$head" = "$CI_DEV_SOURCE_SHA" || { echo "Checked-out SHA $head does not match $CI_DEV_SOURCE_SHA"; exit 1; }
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3"
- name: Download canonical affected plan
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: dev-affected-plan-${{ github.run_id }}
path: .
- name: Download shard completion receipts
if: ${{ needs.affected-plan.result == 'success' && needs.affected-plan.outputs.has_tasks == 'true' && needs.affected-shards.result == 'success' }}
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: dev-affected-shard-${{ github.run_id }}-*
path: .ci-dev-shard-receipts
merge-multiple: true
- name: Produce affected evidence
env:
CI_DEV_PLAN_RESULT: ${{ needs.affected-plan.result }}
CI_DEV_NATIVE_RESULT: ${{ needs.affected-native.result }}
CI_DEV_SHARDS_RESULT: ${{ needs.affected-shards.result }}
CI_DEV_HAS_NATIVE: ${{ needs.affected-plan.outputs.has_native }}
CI_DEV_HAS_TASKS: ${{ needs.affected-plan.outputs.has_tasks }}
CI_DEV_WINDOWS_DOCTOR_RESULT: ${{ needs.windows-dev-doctor.result }}
CI_DEV_WINDOWS_DOCTOR_REQUIRED: ${{ contains(needs.affected-plan.outputs.changed_paths, 'scripts/dev-link') }}
run: bun scripts/ci-dev-affected.ts --write-affected-evidence
- name: Upload affected evidence
id: upload-evidence
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: dev-affected-evidence-${{ github.run_id }}
path: |
.ci-dev-affected-evidence.json
.ci-dev-affected-evidence.receipt.json
.ci-dev-affected-plan.json
.ci-dev-shard-receipts
include-hidden-files: true
if-no-files-found: error
retention-days: 1
overwrite: true
affected:
name: Affected path validation
if: ${{ always() }}
needs: [affected-evidence-producer, affected-plan, affected-native, affected-shards, windows-dev-doctor]
runs-on: ubuntu-22.04
timeout-minutes: 5
env:
CI_DEV_PLAN_DIGEST: ${{ needs.affected-plan.outputs.plan_digest }}
CI_DEV_PLAN_SOURCE_SHA: ${{ needs.affected-plan.outputs.plan_source_sha }}
CI_DEV_PLAN_MODE: ${{ needs.affected-plan.outputs.plan_mode }}
CI_DEV_SOURCE_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
CI_DEV_PLAN_RESULT: ${{ needs.affected-plan.result }}
CI_DEV_NATIVE_RESULT: ${{ needs.affected-native.result }}
CI_DEV_SHARDS_RESULT: ${{ needs.affected-shards.result }}
CI_DEV_HAS_NATIVE: ${{ needs.affected-plan.outputs.has_native }}
CI_DEV_HAS_TASKS: ${{ needs.affected-plan.outputs.has_tasks }}
CI_DEV_WINDOWS_DOCTOR_RESULT: ${{ needs.windows-dev-doctor.result }}
CI_DEV_WINDOWS_DOCTOR_REQUIRED: ${{ contains(needs.affected-plan.outputs.changed_paths, 'scripts/dev-link') }}
steps:
- name: Fail closed on producer and live dependency results
env:
CI_DEV_EVIDENCE_ROOT: ${{ runner.temp }}/ci-dev-affected-evidence
shell: bash
run: |
test '${{ needs.affected-evidence-producer.result }}' = success
test '${{ needs.affected-plan.result }}' = success
test '${{ needs.affected-evidence-producer.outputs.artifact_id }}' != ''
test '${{ needs.affected-evidence-producer.outputs.artifact_digest }}' != ''
test "$CI_DEV_EVIDENCE_ROOT" != "$GITHUB_WORKSPACE"
case "$CI_DEV_EVIDENCE_ROOT" in "$GITHUB_WORKSPACE"/*) exit 1;; esac
rm -rf "$CI_DEV_EVIDENCE_ROOT"
mkdir -p "$CI_DEV_EVIDENCE_ROOT"
- name: Download finalized affected evidence
# download-artifact selects the immutable upload by artifact ID; the pinned
# action exposes no downloaded digest output to compare, so artifact_digest
# remains a required producer audit binding rather than a path selector.
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
artifact-ids: ${{ needs.affected-evidence-producer.outputs.artifact_id }}
path: ${{ runner.temp }}/ci-dev-affected-evidence
merge-multiple: true
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Verify checked-out source head
shell: bash
run: |
head="$(git rev-parse HEAD)"
test "$head" = "$CI_DEV_SOURCE_SHA" || { echo "Checked-out SHA $head does not match $CI_DEV_SOURCE_SHA"; exit 1; }
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3"
- name: Validate finalized affected evidence
env:
CI_DEV_EVIDENCE_ROOT: ${{ runner.temp }}/ci-dev-affected-evidence
run: bun scripts/ci-dev-affected.ts --validate-affected-evidence
gjc-state-gates-matrix:
name: gjc-state-gates / ${{ matrix.group }}
runs-on: ubuntu-22.04
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
group: [static, runtime, integrity, read]
env:
GITHUB_EVENT_BEFORE: ${{ github.event.before }}
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3"
- name: Restore bun dependency cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.bun/install/cache
key: bun-${{ runner.os }}-${{ hashFiles('**/bun.lock') }}
restore-keys: |
bun-${{ runner.os }}-
- run: bun install --frozen-lockfile
- name: Run GJC state gate shard
run: bun scripts/ci-gjc-state-gates.ts --group=${{ matrix.group }}
# Branch protection must keep requiring this stable aggregate status.
gjc-state-gates:
name: gjc-state-gates
if: ${{ always() }}
needs: [gjc-state-gates-matrix]
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Aggregate GJC state gate shards
run: |
result='${{ needs.gjc-state-gates-matrix.result }}'
echo "gjc-state-gates shard result: $result"
test "$result" = success