diff --git a/.github/workflows/continuum-rust-tests.yml b/.github/workflows/continuum-rust-tests.yml index 14f67980b3..4fd88777aa 100644 --- a/.github/workflows/continuum-rust-tests.yml +++ b/.github/workflows/continuum-rust-tests.yml @@ -26,6 +26,9 @@ on: - 'Cargo.lock' - 'rust-toolchain.toml' - 'core/**' + # ts-rs export root: the binding-drift gate below diffs it, so an edit + # to a generated .ts alone must still run this job. + - 'protocol/typescript/**' - '.github/workflows/continuum-rust-tests.yml' push: branches: [canary, main] @@ -121,6 +124,37 @@ jobs: --skip 'modules::persona_allocator::' \ --skip 'persona::allocator::tests::test_allocate' + # ts-rs binding-drift gate (was its own workflow until 2026-08-16). + # + # Rust types carry `#[derive(TS)]` + `#[ts(export_to = "…/protocol/typescript/…")]`. + # The per-type `export_bindings_*` tests WRITE those .ts files as a side effect, + # so a Rust type change with an uncommitted .ts regeneration leaves the wire + # shape silently stale — no compile-time guard fires for the TS consumer. + # (Near-miss on #1624: TargetSilicon gained a variant, TargetSilicon.ts wasn't + # in the push.) + # + # This used to be a SECOND ubuntu job that re-compiled continuum-core from the + # same shared cache just to run `cargo test … export_bindings` — a strict subset + # of the step above, which already regenerated every binding. ~9 min of duplicate + # compile for one `git diff`. The check is the diff, not the build, so it belongs + # here where the build already happened. + - name: Verify protocol/typescript/ in sync with Rust source + run: | + if ! git diff --exit-code protocol/typescript/; then + echo "::error::ts-rs binding drift detected. Some Rust types" + echo "were modified but their regenerated TypeScript bindings" + echo "(in protocol/typescript/) were not committed." + echo "" + echo "Fix: run cargo test locally to regenerate, then:" + echo " git add protocol/typescript/" + echo " git commit --amend --no-edit" + echo " git push --force-with-lease" + echo "" + echo "Or: include the regenerated .ts files in a follow-up commit." + exit 1 + fi + echo "✓ protocol/typescript/ is in sync with Rust source" + # windows-msvc BUILD gate (#304). Glass-boxed 2026-08-02: the Windows grid # node (the CUDA lane) could not run ANY core test locally — un-gated unix # imports (std::os::unix FileExt/MetadataExt/symlink, unix-socket test diff --git a/.github/workflows/ts-rs-binding-drift-guard.yml b/.github/workflows/ts-rs-binding-drift-guard.yml deleted file mode 100644 index 482a35d1c6..0000000000 --- a/.github/workflows/ts-rs-binding-drift-guard.yml +++ /dev/null @@ -1,115 +0,0 @@ -# ts-rs binding-drift guard. -# -# Why this exists: the substrate ships Rust types with `#[derive(TS)]` -# annotations and a `#[ts(export_to = "../../../protocol/typescript/...")]` -# attribute. `cargo test` regenerates those .ts files as a side effect -# of running the per-type `export_bindings_*` tests. If an author adds -# a new field or variant to a Rust type but forgets to commit the -# regenerated .ts file, the TypeScript wire shape drifts silently: -# -# - Mac/Linux dev: cargo test regenerates the .ts file locally, -# looks fine, ships PR without the .ts in the diff. -# - Reviewer: sees only the Rust change, approves. -# - Downstream TS consumer at runtime: hits the new variant / -# missing field, no compile-time guard fires (the .ts file is -# stale). -# -# This workflow protects against that. After `cargo test`, it runs -# `git diff --exit-code` over `protocol/typescript/` (the ts-rs export -# root). Non-empty diff = the test run regenerated bindings that the -# PR didn't commit. Fail with a message telling the author what to do. -# -# Caught by today's session: a near-miss on continuum #1624 (Mac Intel -# classify_silicon fix) where TargetSilicon gained a variant but the -# regenerated `protocol/typescript/governor/TargetSilicon.ts` was not -# in the initial push. Had to amend. This guard makes that mistake -# impossible to land. -name: ts-rs Binding Drift Guard - -on: - pull_request: - paths: - - 'Cargo.toml' - - 'Cargo.lock' - - 'rust-toolchain.toml' - - 'core/**' - - 'protocol/typescript/**' - - '.github/workflows/ts-rs-binding-drift-guard.yml' - push: - branches: [canary, main] - -concurrency: - group: ts-rs-drift-${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - ts-rs-drift: - name: ts-rs binding drift detector - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Rust toolchain from rust-toolchain.toml - run: | - rustup show active-toolchain || rustup show - rustc --version - cargo --version - - - name: System deps (mirrors continuum-core.Dockerfile builder) - run: | - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - cmake pkg-config libssl-dev libpq-dev protobuf-compiler \ - libclang-dev clang build-essential \ - libglib2.0-dev libasound2-dev libva-dev - - # Shares the rust-cache `shared-key` with continuum-rust-tests so the two - # workflows warm each other — but via Swatinem/rust-cache, which prunes the - # workspace crates' own (multi-GB) target output instead of caching all of - # `target/`. The old raw actions/cache of the full `target/` dir grew - # unboundedly until it overflowed the runner disk on restore. - - name: Cache cargo state - uses: Swatinem/rust-cache@v2 - with: - shared-key: continuum-rust-1.95 - cache-on-failure: true - - # The export_bindings_* tests are the ts-rs side effect: each runs - # `TS::export()` on a type, writing the .ts file to its - # `#[ts(export_to = ...)]` path. We filter by name pattern so this - # workflow doesn't pay the cost of running the full unit-test - # suite — that's #1616's job. Same `--skip` shape as #1616 so a - # GPU/env-var-required test doesn't fail this run. - - name: cargo test (regenerate ts-rs bindings only) - run: | - cargo test -p continuum-core --lib export_bindings -- \ - --skip 'gpu::memory_manager::' \ - --skip 'modules::gpu::' \ - --skip 'modules::persona_allocator::' \ - --skip 'persona::allocator::tests::test_allocate' - - # The actual gate. After regenerating, the working tree's - # ts-rs export dir MUST match what was committed. Any diff means - # the PR author edited a Rust type and forgot to commit the - # regenerated .ts. The error message names the fix verbatim so - # the author can re-run + re-commit + push without spelunking - # CI logs. - - name: Verify protocol/typescript/ in sync with Rust source - run: | - if ! git diff --exit-code protocol/typescript/; then - echo "::error::ts-rs binding drift detected. Some Rust types" - echo "were modified but their regenerated TypeScript bindings" - echo "(in protocol/typescript/) were not committed." - echo "" - echo "Fix: run cargo test locally to regenerate, then:" - echo " git add protocol/typescript/" - echo " git commit --amend --no-edit" - echo " git push --force-with-lease" - echo "" - echo "Or: include the regenerated .ts files in a follow-up commit." - exit 1 - fi - echo "✓ protocol/typescript/ is in sync with Rust source"