Problem
continuous_integration.yml triggers only on pull_request. GitHub Actions scopes a cache written during a PR run to that PR's ref (refs/pull/<n>/merge), and only caches at default-branch scope are readable by every branch. Because CI never runs on a push to main, it never writes a cache any other PR can read, so nearly every PR pays a cold bundle install on nearly every job.
The one exception is Ruby 4.0, and only by accident: release.yml uses ruby-version: ruby, which currently resolves to 4.0.6, and it runs on pushes to main. The v5.0.4 release populated that cache.
Evidence
From the first (cold) run on the ci/split-lint-job-from-matrix branch, run 31216830767 attempt 1 — Setup Ruby accounted for 293s of 925s total:
| Job |
Setup Ruby |
Cache |
| Ruby 3.2 on windows-latest |
109s |
miss |
| Ruby jruby-10.0.0.1 on ubuntu-latest |
54s |
miss |
| Ruby truffleruby-24.2.1 on ubuntu-latest |
45s |
miss |
| Ruby 3.2 on ubuntu-latest |
41s |
miss |
| Lint and Docs (Ruby 3.4) |
35s |
miss |
| Ruby 4.0 on ubuntu-latest |
9s |
hit |
Attempt 2 of the same run, with the PR-scoped caches now warm, took 731s total versus 925s.
Expected value
If every job matched the cache-hitting 4.0 job's 9s setup, that is roughly 240s off total job-seconds and 100s off the critical path -- comparable to the savings in PR #1672.
Options
- A dedicated cache-warming workflow on
push: [main] that runs ruby/setup-ruby with bundler-cache: true for each version in the matrix and nothing else. Cheapest: no specs, no lint, just populates the caches at default-branch scope.
- Add
push: branches: [main] to the existing CI workflow. Simpler diff, but runs the entire matrix on every merge, which partly spends the savings it creates.
Option 1 is likely preferable.
Implementation note
PR #1672 added a workflow-level concurrency group keyed on ${{ github.workflow }}-${{ github.ref }} with cancel-in-progress: true. A push-triggered run needs either its own concurrency group or cancel-in-progress: false, otherwise consecutive merges to main will cancel each other's cache warming.
Also worth confirming: cache keys include the runner OS, Ruby version, and Gemfile.lock hash, so the warming job must cover every (os, ruby) pair the matrix uses, including windows-latest + 3.2.
Found while verifying PR #1672.
🤖 Generated with Claude Code
Problem
continuous_integration.ymltriggers only onpull_request. GitHub Actions scopes a cache written during a PR run to that PR's ref (refs/pull/<n>/merge), and only caches at default-branch scope are readable by every branch. Because CI never runs on a push tomain, it never writes a cache any other PR can read, so nearly every PR pays a coldbundle installon nearly every job.The one exception is Ruby 4.0, and only by accident:
release.ymlusesruby-version: ruby, which currently resolves to 4.0.6, and it runs on pushes tomain. The v5.0.4 release populated that cache.Evidence
From the first (cold) run on the
ci/split-lint-job-from-matrixbranch, run31216830767attempt 1 —Setup Rubyaccounted for 293s of 925s total:Setup RubyAttempt 2 of the same run, with the PR-scoped caches now warm, took 731s total versus 925s.
Expected value
If every job matched the cache-hitting 4.0 job's 9s setup, that is roughly 240s off total job-seconds and 100s off the critical path -- comparable to the savings in PR #1672.
Options
push: [main]that runsruby/setup-rubywithbundler-cache: truefor each version in the matrix and nothing else. Cheapest: no specs, no lint, just populates the caches at default-branch scope.push: branches: [main]to the existing CI workflow. Simpler diff, but runs the entire matrix on every merge, which partly spends the savings it creates.Option 1 is likely preferable.
Implementation note
PR #1672 added a workflow-level concurrency group keyed on
${{ github.workflow }}-${{ github.ref }}withcancel-in-progress: true. Apush-triggered run needs either its own concurrency group orcancel-in-progress: false, otherwise consecutive merges tomainwill cancel each other's cache warming.Also worth confirming: cache keys include the runner OS, Ruby version, and
Gemfile.lockhash, so the warming job must cover every(os, ruby)pair the matrix uses, includingwindows-latest+ 3.2.Found while verifying PR #1672.
🤖 Generated with Claude Code