From 4d492fff6ad335b63d6cfe3e6c480d9bc74452c4 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 12:52:22 +0000 Subject: [PATCH 1/3] Start fix for #1385 Assisted-by: Claude Code:claude-opus-5-5 From 6842cce41a493cbb4a39168e98587283691eafe6 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 12:57:47 +0000 Subject: [PATCH 2/3] CI: type-check Windows in the queue, in parallel The lean merge queue's only Windows job built and linked every CLI test binary after waiting for clippy, then uploaded a bundle nothing in lean scope downloads. It set the queue's critical path in 27 of 30 runs, about 9.5 minutes of a 9.6-minute run. A new windows-compile-check job now runs on lean merge_group runs instead. It starts at once and runs cargo check over the CLI and every CLI test target, which still catches a cfg(unix) slip (#1324). Full scope, nightly and dispatch keep the full e2e-build-windows build that their Windows legs consume. Pull requests are unchanged. Fixes #1385 Assisted-by: Claude Code:claude-opus-5-5 --- .github/workflows/ci.yml | 49 ++++++++++++++++++++++++----- scripts/tests/test_ci_scheduling.py | 26 ++++++++++++++- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20caf9438..adeb15864 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,8 +58,8 @@ concurrency: # the repository variable CI_SCOPE is `full`, pull_request, merge_group and # push runs use one targeted e2e row per package manager (the rest are in # e2e-extended), one row each of the yarn and cargo VEX matrices, and skip -# the Windows/macOS legs (except e2e-build-windows, which still compiles every -# test target on Windows in the merge queue), test, test-release, old cargo toolchains and the +# the Windows/macOS legs (except windows-compile-check, which still +# type-checks every CLI test target on Windows in the merge queue), test, test-release, old cargo toolchains and the # sbt Docker coverage slice. Everything runs in the nightly schedule and on # workflow_dispatch. Set CI_SCOPE=full to restore the old gate without a # commit. ci-ok treats skipped jobs as passing. hosted-e2e is not scoped: @@ -1014,11 +1014,46 @@ jobs: if-no-files-found: error retention-days: 3 + # Lean merge queue only: type-check the CLI and every CLI test target on + # Windows. Lean pull_request runs skip Windows, and a cfg(unix) slip only + # shows up here (#1324). A check, not a build: nothing in lean scope runs + # the Windows binaries, and linking ~60 test binaries made this the + # queue's critical path (#1385). No `needs: clippy`, so it starts at once; + # merge-queue fail-fast cancels it if clippy fails. Full scope, nightly + # and dispatch build and run everything in e2e-build-windows instead. + windows-compile-check: + if: github.event_name == 'merge_group' && vars.CI_SCOPE != 'full' + runs-on: windows-latest + timeout-minutes: 30 + env: *e2e-build-env + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Install Rust + shell: bash + run: scripts/rustup-retry.sh toolchain install + + # Restore-only: the nightly e2e-build-windows cache (same key and env) + # supplies the registry, build scripts and proc macros. Merge-queue + # refs can't share a saved cache, so this job never saves one. + - name: Cache cargo + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 + with: + shared-key: e2e-windows-latest + save-if: false + + - name: Type-check the CLI and every CLI test target + shell: bash + run: cargo check --locked -p socket-patch-cli --all-features --tests + e2e-build-windows: - # Lean scope still compiles every test target on Windows in the merge - # queue (one job): lean pull_request runs skip Windows, and a cfg(unix) - # slip only shows up here (#1324). Its consumers stay full-scope only. - if: (github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full' || github.event_name == 'merge_group' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') + # Builds the Windows test binaries for e2e-windows and + # cargo-vex-matrix-windows. The lean merge queue runs + # windows-compile-check instead. + if: (github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') needs: clippy outputs: reuse: ${{ needs.clippy.outputs.reuse }} @@ -2669,7 +2704,7 @@ jobs: ci-ok: name: ci-ok # registered as a required check; do not rename if: always() - needs: [clippy, node-addon, lint-ecosystems, release-readiness, test, test-release, coverage, docker-base, coverage-docker, coverage-merge, dispatch-tests, e2e-build, e2e-build-windows, e2e-build-macos, e2e, e2e-windows, e2e-extended, e2e-full, e2e-docker, yarn-classic-matrix, yarn-berry-e2e, yarn-berry-full, cargo-vex-matrix, cargo-vex-matrix-windows, cargo-vex-matrix-full, cargo-old-toolchains, hosted-e2e, e2e-macos, yarn-berry-e2e-macos, cargo-vex-matrix-macos] + needs: [clippy, node-addon, lint-ecosystems, release-readiness, test, test-release, coverage, docker-base, coverage-docker, coverage-merge, dispatch-tests, e2e-build, windows-compile-check, e2e-build-windows, e2e-build-macos, e2e, e2e-windows, e2e-extended, e2e-full, e2e-docker, yarn-classic-matrix, yarn-berry-e2e, yarn-berry-full, cargo-vex-matrix, cargo-vex-matrix-windows, cargo-vex-matrix-full, cargo-old-toolchains, hosted-e2e, e2e-macos, yarn-berry-e2e-macos, cargo-vex-matrix-macos] runs-on: ${{ vars.DISABLE_DEPOT_RUNNERS == 'true' && 'ubuntu-latest' || 'depot-ubuntu-24.04-4' }} timeout-minutes: 5 steps: diff --git a/scripts/tests/test_ci_scheduling.py b/scripts/tests/test_ci_scheduling.py index 67427b5b4..35bba91ad 100644 --- a/scripts/tests/test_ci_scheduling.py +++ b/scripts/tests/test_ci_scheduling.py @@ -40,7 +40,11 @@ def test_required_verdict_includes_every_job(self): ancestors(job) # All dependencies exist and the graph is acyclic. def test_expensive_jobs_cannot_start_after_a_failed_preflight(self): - cheap = {"clippy", "lint-ecosystems", "release-readiness", "dispatch-tests", "ci-ok"} + # windows-compile-check is the lean queue's only Windows job and sits + # on its critical path, so it starts in parallel with clippy; + # merge-queue fail-fast cancels it when clippy fails. + cheap = {"clippy", "lint-ecosystems", "release-readiness", "dispatch-tests", "ci-ok", + "windows-compile-check"} for job in set(JOBS) - cheap: with self.subTest(job=job): self.assertIn("clippy", ancestors(job)) @@ -81,6 +85,26 @@ def test_os_builds_use_the_same_artifact_contract(self): self.assertTrue(condition.endswith(" && (vars.CI_SCOPE == 'full' || github.event_name == 'schedule'" " || github.event_name == 'workflow_dispatch')"), condition) + def test_lean_queue_type_checks_windows_and_full_scope_builds_it(self): + # Exactly one Windows compile per event: the lean merge queue + # type-checks every CLI test target (#1324) without linking (#1385); + # full scope, nightly and dispatch build the binaries their + # consumers download. Lean PR and push runs do neither. + check = JOBS["windows-compile-check"] + self.assertIn(" if: github.event_name == 'merge_group' && vars.CI_SCOPE != 'full'", check) + self.assertIn(" runs-on: windows-latest", check) + self.assertEqual(dependencies("windows-compile-check"), set()) + body = "\n".join(check) + self.assertIn("cargo check --locked -p socket-patch-cli --all-features --tests", body) + self.assertIn(" env: *e2e-build-env", check) + self.assertIn("shared-key: e2e-windows-latest", body) + self.assertIn("save-if: false", body) + self.assertNotIn("upload-artifact", body) + self.assertNotIn("--no-run", body) + build = next(line for line in JOBS["e2e-build-windows"] if line.startswith(" if:")) + self.assertEqual(build, " if: (github.event.pull_request.draft != true) && (vars.CI_SCOPE == 'full'" + " || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch')") + def test_reused_push_keeps_cache_writers_and_unqueued_jobs(self): # A push whose SHA passed the merge queue still compiles (main is the # only cache writer) and still runs what the queue never ran. From 7ca55aa2c50c2357a890979941a07498bcede4d8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 11 Oct 2026 13:01:25 +0000 Subject: [PATCH 3/3] CI: cache the Windows check, check the shipped bin A cargo build cache can't satisfy cargo check, so restoring the nightly build cache left the queue check re-checking every dependency. The nightly run now also runs windows-compile-check under its own key, and only main saves it, so queue entries restore a cache that matches. The check now also covers the lib and the socket-patch bin in non-test mode, so code under cfg(not(test)) is type-checked on Windows too. The scheduling test now exempts the job only from the clippy-ancestor rule. The rule against always() still applies to it. Assisted-by: Claude Code:claude-opus-5-5 --- .github/workflows/ci.yml | 28 ++++++++++++++-------------- scripts/tests/test_ci_scheduling.py | 25 ++++++++++++++----------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adeb15864..6824ae371 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1014,15 +1014,18 @@ jobs: if-no-files-found: error retention-days: 3 - # Lean merge queue only: type-check the CLI and every CLI test target on - # Windows. Lean pull_request runs skip Windows, and a cfg(unix) slip only - # shows up here (#1324). A check, not a build: nothing in lean scope runs - # the Windows binaries, and linking ~60 test binaries made this the - # queue's critical path (#1385). No `needs: clippy`, so it starts at once; - # merge-queue fail-fast cancels it if clippy fails. Full scope, nightly - # and dispatch build and run everything in e2e-build-windows instead. + # Lean merge queue: type-check the CLI (lib and bin, as shipped) and every + # CLI test target on Windows. Lean pull_request runs skip Windows, and a + # cfg(unix) slip only shows up here (#1324). A check, not a build: nothing + # in lean scope runs the Windows binaries, and linking ~60 test binaries + # made this the queue's critical path (#1385). No `needs: clippy`, so it + # starts at once; merge-queue fail-fast cancels it if clippy fails. Full + # scope, nightly and dispatch build and run everything in + # e2e-build-windows. The nightly run also runs this job, only to save its + # check-mode cache on main: queue refs can't share a saved cache, and a + # build-mode cache doesn't satisfy `cargo check`. windows-compile-check: - if: github.event_name == 'merge_group' && vars.CI_SCOPE != 'full' + if: (github.event_name == 'merge_group' && vars.CI_SCOPE != 'full') || github.event_name == 'schedule' runs-on: windows-latest timeout-minutes: 30 env: *e2e-build-env @@ -1036,18 +1039,15 @@ jobs: shell: bash run: scripts/rustup-retry.sh toolchain install - # Restore-only: the nightly e2e-build-windows cache (same key and env) - # supplies the registry, build scripts and proc macros. Merge-queue - # refs can't share a saved cache, so this job never saves one. - name: Cache cargo uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 with: - shared-key: e2e-windows-latest - save-if: false + shared-key: check-windows-latest + save-if: ${{ github.ref == 'refs/heads/main' }} - name: Type-check the CLI and every CLI test target shell: bash - run: cargo check --locked -p socket-patch-cli --all-features --tests + run: cargo check --locked -p socket-patch-cli --all-features --lib --bins --tests e2e-build-windows: # Builds the Windows test binaries for e2e-windows and diff --git a/scripts/tests/test_ci_scheduling.py b/scripts/tests/test_ci_scheduling.py index 35bba91ad..d0543b964 100644 --- a/scripts/tests/test_ci_scheduling.py +++ b/scripts/tests/test_ci_scheduling.py @@ -40,14 +40,15 @@ def test_required_verdict_includes_every_job(self): ancestors(job) # All dependencies exist and the graph is acyclic. def test_expensive_jobs_cannot_start_after_a_failed_preflight(self): + cheap = {"clippy", "lint-ecosystems", "release-readiness", "dispatch-tests", "ci-ok"} # windows-compile-check is the lean queue's only Windows job and sits # on its critical path, so it starts in parallel with clippy; # merge-queue fail-fast cancels it when clippy fails. - cheap = {"clippy", "lint-ecosystems", "release-readiness", "dispatch-tests", "ci-ok", - "windows-compile-check"} + parallel = {"windows-compile-check"} for job in set(JOBS) - cheap: with self.subTest(job=job): - self.assertIn("clippy", ancestors(job)) + if job not in parallel: + self.assertIn("clippy", ancestors(job)) # Job-level always() would defeat failure/skip propagation. self.assertFalse(any(line.startswith(" if:") and "always()" in line for line in JOBS[job])) @@ -86,19 +87,21 @@ def test_os_builds_use_the_same_artifact_contract(self): " || github.event_name == 'workflow_dispatch')"), condition) def test_lean_queue_type_checks_windows_and_full_scope_builds_it(self): - # Exactly one Windows compile per event: the lean merge queue - # type-checks every CLI test target (#1324) without linking (#1385); - # full scope, nightly and dispatch build the binaries their - # consumers download. Lean PR and push runs do neither. + # The lean merge queue type-checks the CLI and every CLI test target + # on Windows (#1324) without linking (#1385); full scope, nightly and + # dispatch build the binaries their consumers download. Lean PR and + # push runs do neither. The nightly also runs the check, only so main + # saves the check-mode cache the queue restores. check = JOBS["windows-compile-check"] - self.assertIn(" if: github.event_name == 'merge_group' && vars.CI_SCOPE != 'full'", check) + self.assertIn(" if: (github.event_name == 'merge_group' && vars.CI_SCOPE != 'full')" + " || github.event_name == 'schedule'", check) self.assertIn(" runs-on: windows-latest", check) self.assertEqual(dependencies("windows-compile-check"), set()) body = "\n".join(check) - self.assertIn("cargo check --locked -p socket-patch-cli --all-features --tests", body) + self.assertIn("cargo check --locked -p socket-patch-cli --all-features --lib --bins --tests", body) self.assertIn(" env: *e2e-build-env", check) - self.assertIn("shared-key: e2e-windows-latest", body) - self.assertIn("save-if: false", body) + self.assertIn("shared-key: check-windows-latest", body) + self.assertIn("save-if: ${{ github.ref == 'refs/heads/main' }}", body) self.assertNotIn("upload-artifact", body) self.assertNotIn("--no-run", body) build = next(line for line in JOBS["e2e-build-windows"] if line.startswith(" if:"))