From e217d567715a12e51d29875dbed7983f465c7f08 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Thu, 20 Aug 2026 00:11:15 +0000 Subject: [PATCH 1/3] ci: keep the preview strictly Linux-only and off the shared caches The mac/win jobs and matrix legs existed to feed the unified size report and were repo-gated for forks; on the upstream repo they would have run as paid Blacksmith duplicates of the gating workflow. Deleted: the preview owns the Linux lanes only. rust-cache saves are off in the copy (the pinned env shifts every key, so saves would write a parallel lineage into the shared cache quota), and the reconcile wake trigger names the one workflow whose jobs run on ix instead of a glob. --- .../workflows/ix-cargo-tests.reusable.yaml | 173 ++----------- .github/workflows/ix-runners.yml | 2 +- .github/workflows/ix-size-gate.reusable.yaml | 230 +----------------- 3 files changed, 28 insertions(+), 377 deletions(-) diff --git a/.github/workflows/ix-cargo-tests.reusable.yaml b/.github/workflows/ix-cargo-tests.reusable.yaml index 71f93d83c4f..f3fa383d4db 100644 --- a/.github/workflows/ix-cargo-tests.reusable.yaml +++ b/.github/workflows/ix-cargo-tests.reusable.yaml @@ -18,11 +18,11 @@ # compete. # # Because `target/` is excluded, rust-cache's payload is small (registry + git, -# no build output). As on canary, only canary writes the cache -# (`save-if: ${{ github.ref == 'refs/heads/canary' }}`); PR branches read the -# shared entry instead of each saving a fresh one, so cache usage doesn't blow -# out. rust-cache keys are content-addressed on Cargo.lock, so jobs sharing a -# `shared-key` reuse the same entry. +# no build output). This copy never SAVES cache entries (save-if: false on +# every step): the env pins below shift rust-cache's keys, so saving here +# would write a parallel set of entries into the repo's shared cache quota +# and evict the gating workflow's. On ix, warmth comes from the seed disk, +# not the Actions cache. # # mise installs sccache and direnv, then each cargo job loads .envrc via # `direnv export gha` so CI uses the exact same sccache config as local shells: @@ -121,7 +121,7 @@ jobs: workspaces: "baml_language -> target" cache-all-crates: true cache-targets: false - save-if: ${{ github.ref == 'refs/heads/canary' }} + save-if: false shared-key: "linux-cargo" - name: "Load .envrc with direnv" @@ -196,10 +196,10 @@ jobs: timeout-minutes: 45 env: CARGO_BUILD_TARGET: x86_64-unknown-linux-musl - # The ix machine image ships musl-gcc (a real musl cross compiler); - # setup-musl-cross is skipped there, so wire the cargo linker - # explicitly. Identical to what the action exports on hosted runners. + # The ix machine image ships musl-gcc; setup-musl-cross is skipped + # there, so wire the same env the action would export. CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc + CC_x86_64_unknown_linux_musl: musl-gcc steps: - uses: actions/checkout@v6 with: @@ -236,7 +236,7 @@ jobs: workspaces: "baml_language -> target" cache-all-crates: true cache-targets: false - save-if: ${{ github.ref == 'refs/heads/canary' }} + save-if: false shared-key: "linux-cargo" - name: "Load .envrc with direnv" @@ -389,140 +389,6 @@ jobs: # path: baml_language/target/cargo-timings/cargo-timing-test-macos.html # if-no-files-found: ignore - cargo-test-windows: - name: "cargo test (x86_64-pc-windows-msvc)" - # Skip in the merge queue (windows already ran on the PR) and outside - # the upstream repo (forks have no Blacksmith Windows runners). - if: ${{ github.event_name != 'merge_group' && github.repository == 'BoundaryML/baml' }} - # 8-vCPU + CARGO_BUILD_JOBS=16 (2x cores) was the value sweet spot for the - # native Windows Rust builds (build-caching/04 Exp 7/9). - runs-on: blacksmith-8vcpu-windows-2025 - env: - CARGO_BUILD_JOBS: "16" - # Windows debug builds emit very large PDBs; full debuginfo across the - # whole `--all-features` test build overruns the runner's ~130 GB disk - # ("no space on device" during codegen, before any test runs). - # `line-tables-only` keeps file:line backtraces for test failures while - # dropping the bulk of the debug-info size (variable/type DIEs). Pinned on - # both `dev` (dependencies) and `test` (the `--test` binaries, which - # inherit `dev` but are pinned explicitly so the reduction is unambiguous). - # Drop to "0" if this is still too tight. - CARGO_PROFILE_DEV_DEBUG: "line-tables-only" - CARGO_PROFILE_TEST_DEBUG: "line-tables-only" - # TODO: Reduce this once our changes to aws-sdk-rust are upstreamed - # Right now it needs to download our repo every time which is very slow - timeout-minutes: 50 - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - - - name: "Install Rust toolchain" - run: rustup show - working-directory: baml_language - - - name: "Install sccache, direnv, and cargo-nextest" - uses: ./.github/actions/setup-mise - with: - install_args: "sccache direnv cargo:cargo-nextest" - - - name: "Verify sccache" - run: sccache --version - - - uses: Swatinem/rust-cache@v2 - with: - workspaces: "baml_language -> target" - cache-all-crates: true - cache-targets: false - save-if: ${{ github.ref == 'refs/heads/canary' }} - shared-key: "windows-cargo" - - - name: "Load .envrc with direnv" - run: | - set -euo pipefail - - direnv allow .envrc - direnv export gha >> "$GITHUB_ENV" - - # Separate step so if fetch is slow, build is fast. - - name: "Fetch cargo dependencies" - run: cargo fetch - working-directory: baml_language - - - name: "Build native sccache wrapper" - run: | - set -euo pipefail - # The native RUSTC_WRAPPER (tools_sccache crate) maps the R2 creds and - # execs sccache; cargo launches it via CreateProcess (32767-char - # limit), avoiding cmd.exe's ~8191-char limit that windows-sys' huge - # `--check-cfg cfg(feature, values(...))` line blows past. The binary - # lives in the build tree, so build it first — .envrc leaves - # RUSTC_WRAPPER unset until it exists, so this bootstrap compiles with - # plain rustc — then point RUSTC_WRAPPER at it for the cargo steps - # below. - cargo build -p tools_sccache - echo "RUSTC_WRAPPER=$(pwd -W)/target/debug/baml-sccache.exe" >> "$GITHUB_ENV" - working-directory: baml_language - - # Snapshot tests live in `baml_tests` and are covered by the dedicated - # `snapshot-tests` job. The `sdk_test_*` crates need uv and run in the - # dedicated `sdk-tests` matrix below. Skip both here — at the cargo - # level (`--exclude`), not a nextest `-E` filter, so their test binaries - # (the heaviest links, and on Windows the largest PDBs) aren't built. - - name: "Build tests with --timings" - run: cargo test --no-run --all-features --timings --workspace --exclude baml_tests --exclude "sdk_test_*" --exclude baml_bridge - working-directory: baml_language - - # Profiling-specific test binaries opt in explicitly; keeping - # BAML_PROFILE off for the general suite avoids filling the Windows - # runner with incidental `.bamlprof` files. Run the two binaries that - # need `baml-pack-host` separately so their process-global OnceLocks - # build and share it instead of relinking it for every nextest case. - - name: "Run tests" - run: cargo nextest run --all-features --workspace --exclude baml_tests --exclude "sdk_test_*" --exclude baml_bridge -E 'not binary(=pack_e2e) and not binary(=exit_code_e2e)' - working-directory: baml_language - env: - BAML_PROFILE: "0" - - - name: "Free disk for CLI binary e2e tests" - run: | - set -euo pipefail - mv target/cargo-timings/cargo-timing.html cargo-timing-test-windows.html - cp target/debug/baml-sccache.exe baml-sccache.exe - echo "RUSTC_WRAPPER=$(pwd -W)/baml-sccache.exe" >> "$GITHUB_ENV" - cargo clean - working-directory: baml_language - - - name: "Run CLI binary e2e tests (windows)" - run: cargo test -p baml_cli --test pack_e2e --test exit_code_e2e --all-features - working-directory: baml_language - env: - BAML_PROFILE: "0" - - - name: "Show sccache stats" - if: always() - run: sccache --show-stats - - - name: "Dump sccache stats (json)" - if: always() - run: sccache --show-stats --stats-format json > sccache-stats-test-windows.json - - - name: "Upload sccache stats" - if: always() - uses: actions/upload-artifact@v7 - with: - name: sccache-stats-test-windows - path: sccache-stats-test-windows.json - if-no-files-found: ignore - - - name: "Upload cargo timings" - if: always() - uses: actions/upload-artifact@v7 - with: - name: cargo-timings-test-windows - path: baml_language/cargo-timing-test-windows.html - if-no-files-found: ignore - sdk-test-matrix: name: "sdk test matrix" runs-on: ubuntu-latest @@ -864,13 +730,9 @@ jobs: // TODO(B-1545): Re-enable macOS SDK tests after the SIGABRT flakiness is fixed: https://linear.app/boundaryml2/issue/B-1545/investigate-flakiness-in-cargo-test-aarch64-apple-darwin-ci-job const enabledMatrix = baseMatrix.filter((entry) => entry["os-label"] !== "macos"); - // Linux-only in the merge queue (mac/win already ran on the PR) - // and on forks (no Blacksmith mac/win runners; the jobs would - // queue forever). Case-insensitive so a differently-cased - // repository name cannot silently drop the mac/win legs upstream. - const linuxOnly = - context.eventName === "merge_group" || - process.env.GITHUB_REPOSITORY.toLowerCase() !== "boundaryml/baml"; + // The preview covers the Linux lanes only; the gating + // workflow keeps sole ownership of the mac/win legs. + const linuxOnly = true; const matrix = linuxOnly ? enabledMatrix.filter((entry) => entry["os-label"] === "linux") : enabledMatrix; @@ -1081,7 +943,8 @@ jobs: working-directory: baml_language # Windows-only: swap the .cmd RUSTC_WRAPPER for the native tools_sccache - # .exe. See the matching step in `cargo-test-windows` for why. + # .exe. See the matching step in the gating cargo-tests.reusable.yaml + # for why. - name: "Build native sccache wrapper" if: matrix.os-label == 'windows' run: | @@ -1222,7 +1085,7 @@ jobs: workspaces: "baml_language -> target" cache-all-crates: true cache-targets: false - save-if: ${{ github.ref == 'refs/heads/canary' }} + save-if: false shared-key: "linux-wasm" - name: "Load .envrc with direnv" @@ -1333,7 +1196,7 @@ jobs: workspaces: "baml_language -> target" cache-all-crates: true cache-targets: false - save-if: ${{ github.ref == 'refs/heads/canary' }} + save-if: false shared-key: "linux-msrv" - name: "Load .envrc with direnv" @@ -1577,7 +1440,6 @@ jobs: needs: - cargo-test-linux - cargo-test-linux-musl - - cargo-test-windows - sdk-tests - cargo-test-wasm - cargo-build-msrv @@ -1596,7 +1458,6 @@ jobs: needs: - cargo-test-linux - cargo-test-linux-musl - - cargo-test-windows - sdk-tests - cargo-test-wasm - cargo-build-msrv diff --git a/.github/workflows/ix-runners.yml b/.github/workflows/ix-runners.yml index 2cc68a5f150..70eb80050e6 100644 --- a/.github/workflows/ix-runners.yml +++ b/.github/workflows/ix-runners.yml @@ -18,7 +18,7 @@ on: schedule: - cron: "*/15 * * * *" workflow_run: - workflows: ["**"] + workflows: ["CI on ix (preview)"] types: [requested] # Overlapping ticks can double-spawn; this group is the lock. diff --git a/.github/workflows/ix-size-gate.reusable.yaml b/.github/workflows/ix-size-gate.reusable.yaml index 2ab0e054fcf..6a699d1671c 100644 --- a/.github/workflows/ix-size-gate.reusable.yaml +++ b/.github/workflows/ix-size-gate.reusable.yaml @@ -1,8 +1,10 @@ -# ix preview copy of .github/workflows/size-gate.reusable.yaml - the -# same jobs pointed at the ix runner pool (runs-on labels and per-lane -# adjustments). It runs side by side with the original via ix-ci.yml, is -# never a required check, and changes nothing about how the original -# runs. Promote or delete after the trial; do not evolve both copies. +# ix preview copy of .github/workflows/size-gate.reusable.yaml, linux and +# wasm halves only - the mac/win halves stay exclusively in the gating +# workflow, so the preview never duplicates Blacksmith spend and the +# unified report here covers linux and wasm. It runs side by side with +# the original via ix-ci.yml, is never a required check, and changes +# nothing about how the original runs. Promote or delete after the +# trial; do not evolve both copies. # # sccache strategy # ================ @@ -145,204 +147,6 @@ jobs: path: baml_language/target/cargo-timings/ if-no-files-found: ignore - size-gate-macos: - name: "measure-baml-size (macos)" - # Forks have no Blacksmith mac/win runners; the job would queue forever. - if: ${{ github.repository == 'BoundaryML/baml' }} - runs-on: blacksmith-6vcpu-macos-latest - timeout-minutes: 20 - continue-on-error: true - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - - - name: "Install Rust toolchain" - run: rustup show - working-directory: baml_language - - - name: "Install sccache and direnv" - uses: ./.github/actions/setup-mise - with: - install_args: "sccache direnv" - - - name: "Verify sccache" - run: sccache --version - - - uses: Swatinem/rust-cache@v2 - with: - workspaces: "baml_language -> target" - cache-all-crates: true - cache-targets: false - shared-key: "macos-cargo" - # Read-only consumer. The canary saver lives in - # cargo-tests.reusable.yaml; see the cache strategy comment there. - save-if: false - - - name: "Load .envrc with direnv" - run: | - set -euo pipefail - - direnv allow .envrc - direnv export gha >> "$GITHUB_ENV" - - # Separate step so if fetch is slow, build is fast. - - name: "Fetch cargo dependencies" - run: cargo fetch - working-directory: baml_language - - - name: "Run size-gate check" - id: check - working-directory: baml_language - run: | - cargo run --timings -p cargo-size-gate -- size-gate check \ - --only baml-cli,packed-program \ - --format json > size-gate-macos.json 2> size-gate-stderr.txt || exit_code=$? - cat size-gate-stderr.txt >&2 - echo "exit_code=${exit_code:-0}" >> "$GITHUB_OUTPUT" - - - name: "Upload size-gate report" - if: always() - uses: actions/upload-artifact@v7 - with: - name: size-gate-macos - path: baml_language/size-gate-macos.json - if-no-files-found: ignore - - - name: "Show sccache stats" - if: always() - run: sccache --show-stats - - - name: "Dump sccache stats (json)" - if: always() - run: sccache --show-stats --stats-format json > sccache-stats-size-gate-macos.json - - - name: "Upload sccache stats" - if: always() - uses: actions/upload-artifact@v7 - with: - name: sccache-stats-size-gate-macos - path: sccache-stats-size-gate-macos.json - if-no-files-found: ignore - - - name: "Upload cargo timings" - if: always() - uses: actions/upload-artifact@v7 - with: - name: cargo-timings-size-gate-macos - path: baml_language/target/cargo-timings/ - if-no-files-found: ignore - - size-gate-windows: - name: "measure-baml-size (windows)" - # Forks have no Blacksmith mac/win runners; the job would queue forever. - if: ${{ github.repository == 'BoundaryML/baml' }} - runs-on: blacksmith-8vcpu-windows-2025 - # TODO: Reduce this once our changes to aws-sdk-rust are upstreamed - # Right now it needs to download our repo every time which is very slow - timeout-minutes: 45 - continue-on-error: true - env: - CARGO_BUILD_JOBS: "16" - steps: - - uses: actions/checkout@v6 - with: - persist-credentials: false - - - name: "Install Rust toolchain" - run: rustup show - working-directory: baml_language - - # Cargo linking uses rust-lld from the Rust toolchain on Windows. The - # extra clang tool is installed through mise for llvm-strip, replacing - # the previous Chocolatey LLVM install. - - name: "Install sccache, direnv, and clang" - uses: ./.github/actions/setup-mise - with: - install_args: "sccache direnv clang" - - - name: "Verify sccache" - run: sccache --version - - - uses: Swatinem/rust-cache@v2 - with: - workspaces: "baml_language -> target" - cache-all-crates: true - cache-targets: false - shared-key: "windows-cargo" - # Read-only consumer. The canary saver lives in - # cargo-tests.reusable.yaml; see the cache strategy comment there. - save-if: false - - - name: "Load .envrc with direnv" - run: | - set -euo pipefail - - direnv allow .envrc - direnv export gha >> "$GITHUB_ENV" - - # Separate step so if fetch is slow, build is fast. - - name: "Fetch cargo dependencies" - run: cargo fetch - working-directory: baml_language - - - name: "Build native sccache wrapper" - run: | - set -euo pipefail - # The native RUSTC_WRAPPER (tools_sccache crate) maps the R2 creds and - # execs sccache; cargo launches it via CreateProcess (32767-char - # limit), avoiding cmd.exe's ~8191-char limit that windows-sys' huge - # `--check-cfg cfg(feature, values(...))` line blows past. The binary - # lives in the build tree, so build it first — .envrc leaves - # RUSTC_WRAPPER unset until it exists, so this bootstrap compiles with - # plain rustc — then point RUSTC_WRAPPER at it for the cargo steps - # below. - cargo build -p tools_sccache - echo "RUSTC_WRAPPER=$(pwd -W)/target/debug/baml-sccache.exe" >> "$GITHUB_ENV" - working-directory: baml_language - - - name: "Run size-gate check" - id: check - working-directory: baml_language - run: | - cargo run --timings -p cargo-size-gate -- size-gate check \ - --only baml-cli,packed-program \ - --format json > size-gate-windows.json 2> size-gate-stderr.txt || exit_code=$? - cat size-gate-stderr.txt >&2 - echo "exit_code=${exit_code:-0}" >> "$GITHUB_OUTPUT" - - - name: "Upload size-gate report" - if: always() - uses: actions/upload-artifact@v7 - with: - name: size-gate-windows - path: baml_language/size-gate-windows.json - if-no-files-found: ignore - - - name: "Show sccache stats" - if: always() - run: sccache --show-stats - - - name: "Dump sccache stats (json)" - if: always() - run: sccache --show-stats --stats-format json > sccache-stats-size-gate-windows.json - - - name: "Upload sccache stats" - if: always() - uses: actions/upload-artifact@v7 - with: - name: sccache-stats-size-gate-windows - path: sccache-stats-size-gate-windows.json - if-no-files-found: ignore - - - name: "Upload cargo timings" - if: always() - uses: actions/upload-artifact@v7 - with: - name: cargo-timings-size-gate-windows - path: baml_language/target/cargo-timings/ - if-no-files-found: ignore - size-gate-wasm: name: "measure-baml-size (wasm)" runs-on: ${{ (((github.event_name != 'pull_request' && github.event_name != 'pull_request_target') || github.event.pull_request.head.repo.full_name == github.repository) && fromJSON('["ix", "ix-wasm"]')) || 'blacksmith-4vcpu-ubuntu-2404' }} @@ -438,7 +242,7 @@ jobs: name: "enforce-baml-size" runs-on: ${{ (((github.event_name != 'pull_request' && github.event_name != 'pull_request_target') || github.event.pull_request.head.repo.full_name == github.repository) && fromJSON('["ix", "ix-light"]')) || 'blacksmith-4vcpu-ubuntu-2404' }} if: ${{ always() && !cancelled() }} - needs: [size-gate-linux, size-gate-macos, size-gate-windows, size-gate-wasm] + needs: [size-gate-linux, size-gate-wasm] permissions: contents: read steps: @@ -507,10 +311,7 @@ jobs: RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" BIN: baml_language/target/debug/cargo-size-gate RESULT_LINUX: ${{ needs.size-gate-linux.result }} - RESULT_MACOS: ${{ needs.size-gate-macos.result }} - RESULT_WINDOWS: ${{ needs.size-gate-windows.result }} RESULT_WASM: ${{ needs.size-gate-wasm.result }} - FORK_GATED: ${{ github.repository != 'BoundaryML/baml' }} run: | # Track which expected platforms produced a JSON report. missing=() @@ -518,22 +319,13 @@ jobs: declare -A platform_results=( [linux]="$RESULT_LINUX" - [macos]="$RESULT_MACOS" - [windows]="$RESULT_WINDOWS" [wasm]="$RESULT_WASM" ) - for platform in linux macos windows wasm; do + for platform in linux wasm; do f="reports/size-gate-${platform}.json" if [ -s "$f" ]; then json_files+=("$f") - elif [ "${platform_results[$platform]:-unknown}" = "skipped" ] \ - && [ "$FORK_GATED" = "true" ] \ - && { [ "$platform" = "macos" ] || [ "$platform" = "windows" ]; }; then - # The one sanctioned skip: mac/win are gated to the upstream - # repo, which owns the Blacksmith runners. Any other skip - # falls through to the missing callout. - echo "note: size-gate ${platform} skipped by the fork gate" else missing+=("$platform (job result: ${platform_results[$platform]:-unknown})") fi @@ -592,8 +384,6 @@ jobs: - name: "Fail if any platform is missing or any check failed" env: RESULT_LINUX: ${{ needs.size-gate-linux.result }} - RESULT_MACOS: ${{ needs.size-gate-macos.result }} - RESULT_WINDOWS: ${{ needs.size-gate-windows.result }} RESULT_WASM: ${{ needs.size-gate-wasm.result }} run: | fail=0 @@ -615,7 +405,7 @@ jobs: # stderr, so exit 127 would read as "no violation" and the gate # would fail open. command -v jq >/dev/null || { echo "::error::jq is not on PATH; the violation re-check cannot run"; exit 1; } - for platform in linux macos windows wasm; do + for platform in linux wasm; do f="reports/size-gate-${platform}.json" if [ -f "$f" ] && jq -e '.ok == false' "$f" > /dev/null 2>&1; then echo "::error::size-gate (${platform}) reported a policy violation" From 817d7b35e076f9e90e29c627bee6c42fc6720095 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Thu, 20 Aug 2026 00:22:49 +0000 Subject: [PATCH 2/3] ci: bump the ix-runners pin to current main Picks up the evidence-gated seed deletion fix and the seed-integrity batch (promotion is never silently skipped, listings tolerate partial reads, fork-PR runs cannot mint seeds). --- .github/workflows/ix-runners.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ix-runners.yml b/.github/workflows/ix-runners.yml index 70eb80050e6..839cb1415ad 100644 --- a/.github/workflows/ix-runners.yml +++ b/.github/workflows/ix-runners.yml @@ -61,7 +61,7 @@ jobs: - name: Reconcile if: steps.optin.outputs.ok == 'true' - uses: indexable-inc/ix-runners@1da294a29ca9dcc20eec21f3f5c9856dc10645eb + uses: indexable-inc/ix-runners@768d545e0cce8c62f2ce2005f2da3ec904775e35 with: ix-token: ${{ secrets.IX_TOKEN }} token-source: ix From fc41e0131d76406d5b7a176bc559914c0dae06f6 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Thu, 20 Aug 2026 00:30:02 +0000 Subject: [PATCH 3/3] ci: read IX_TOKEN from the boundary-tools-dev environment The secret lives in that environment's secrets, not the repo's; without the job-level environment it reads as empty and the reconcile skips. --- .github/workflows/ix-runners.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ix-runners.yml b/.github/workflows/ix-runners.yml index 839cb1415ad..7ed2fd52953 100644 --- a/.github/workflows/ix-runners.yml +++ b/.github/workflows/ix-runners.yml @@ -45,6 +45,8 @@ jobs: name: Reconcile runners # Control plane is hosted-only; secrets never reach the fleet. runs-on: ubuntu-latest + # IX_TOKEN lives in this environment's secrets. + environment: boundary-tools-dev steps: # Repos without IX_TOKEN configured (forks, and this repo until the # secret is set) skip quietly instead of failing every wave.