Skip to content

ci: cache Rust builds in R2, written from the merge queue - #5685

Merged
kixelated merged 7 commits into
mainfrom
quest/m0/ci/mbx-r2
Oct 20, 2026
Merged

kixelated merged 7 commits into
mainfrom
quest/m0/ci/mbx-r2

Conversation

@kixelated

@kixelated kixelated commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Moves the Rust build cache from the Actions cache to a private R2 bucket (mbx-moq-dev), using mbx's S3 backend, and writes it from the merge queue and main instead of a post-merge warm. Completes quest/m0/ci/mbx-r2.md.

Problem

The Actions cache is 10 GB per repository and scoped by branch, so only main could write a cache that pull requests read, through a separate warm in cache.yml that rebuilt everything after each merge. That warm was ARM64 only (x86, macOS, and Windows did not fit the budget) and ran a second full build of code the queue had just built.

Approach

  • Writers are every Rust cache user on main and in its merge queue. A queued PR is about to become main, so its code is trusted like main's (maintainer decision, 2026-10-19). Each such job names the cache-write Environment with environment: ${{ (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/gh-readonly-queue/main/')) && 'cache-write' || '' }}, which matches the Environment's branch policies for main and the queue. Other jobs get no Environment and read with the repository's read key. Since ci: run cloud CI only in the merge queue #6038, main PRs run no cloud CI, so the writers are Check and Test (queue), and on main Nightly's own jobs (nightly, tests, media-engines, audio-quality, sizes, which include the obs ci row), the workflows Nightly calls that use the cache (Platform's macOS and Windows, X11, WASM), and the scheduled Interop and TS runs. Readers are release PRs and pushes, and every writer before it publishes.
  • .github/actions/rust-cache: mbx 1.24.0 -> 1.25.0. It derives the writer decision from github.ref itself, so the write input is gone. For writers it exports MBX_REMOTE_MODE=read-write and MBX_REMOTE_TRUST_WRITES=true (new in mbx 1.25.0, feat(cache): add remote.trust_writes for CI systems mbx does not detect jdx/mr-boxington#724). Without it mbx forces read-only for anything but a push to a protected branch, which excludes merge_group and schedule. Bypassing mbx's policy is deliberate: the Environment is the boundary. mr-boxington-action stays at v1.7.2, its newest release; it passes MBX_REMOTE_MODE through when remote-mode is unset.
  • Fail loud: a writer ref without a key fails (Environment misconfigured), half a key pair fails on any ref, a key the bucket rejects fails mbx doctor, and a writer that does not come out effective read-write fails. Missing credentials on a reader (fork or Dependabot PRs into release) give a warning and a cold build.
  • cache.yml keeps only the Nix dev-shell Cachix push, now triggered by flake.nix, flake.lock, and nix/**. The ARM64, x86, macOS, and Windows Rust warms are deleted. It no longer needs the Environment. alert.yml is unchanged, since Cache stays a CI-only workflow.
  • The Cargo shim's directory is added to GITHUB_PATH, so jobs on the runner's rustup toolchain also go through mbx.
  • Readers only: uring, OBS (both run only for release now), and release-rs (release is not a writer ref).
  • infra/mbx: a wrangler package with lifecycle.json (expire objects after 30 days, abort multipart uploads after 1 day), plus just infra mbx create and just infra mbx lifecycle. infra/README.md documents the bootstrap and the writer rule.
  • Quest: deleted mbx-r2.md; mbx-r2-verify.md is a condition quest that measures hits, restore time, and expiry once the queue has written.

Dropped: the write input on the rust-cache action. It always equalled "this ref is main or its queue", so callers only declare the Environment.

Maintainer actions

Done 2026-10-19: the bucket and lifecycle rule, both R2 tokens, the cache-write Environment with the main and gh-readonly-queue/main/* policies, and the repository and Environment secrets.

Impact

None on the public API or wire. CI and infra only.

Merge with #6038

That PR landed first: main PRs report Check and Test skipped, Platform left the queue for Nightly, OBS dropped its main push, and Nightly calls more workflows. The merge of origin/main resolves it so both hold:

  • cache.yml: no Rust warm (this PR), so ci: run cloud CI only in the merge queue #6038's edits to the deleted warm steps go too.
  • check.yml: ci: run cloud CI only in the merge queue #6038's queue-only gating and CI_BASE stand; Check and Test keep the writer Environment, which now applies only to merge groups.
  • obs.yml: it runs only for release, which never writes, so the writer Environment line is dropped and it reads. Nightly's obs ci row writes on main instead.
  • wasm.yml: Nightly now calls it on main, where the action requires the write key, so it names the Environment and Nightly passes secrets: inherit, like X11 and Platform. Without this, Nightly's WASM job would fail at Cache credentials.
  • Comments in platform.yml, infra/README.md, and mbx-r2-verify.md no longer say the queue runs macOS and Windows or that main PRs read.

Checks

  • just check and just gh check pass after the merge (actionlint, alert coverage, check-runs, quest, markdown and justfile lints), and so do bun test sh/gh/setup.test.ts and bun sh/gh/queue.test.ts.
  • The credentials step's shell logic was exercised locally for writer and reader, with and without a key.
  • mbx 1.25.0's source confirms MBX_REMOTE_TRUST_WRITES is read from the environment (#[usage(env = ...)], the same path as MBX_REMOTE_S3_ENDPOINT), that trust_writes returns the configured mode before the GitHub check, and that mbx doctor reports configured <mode>, effective <mode>.
  • CI on 8dac66ea1f: pull request jobs with the empty environment: name start normally with the repository read key. io_uring's Check the cache reported remote: pass: s3://mbx-moq-dev (Linux-ARM64) is compatible and policy: configured read-only, effective read-only on mbx 1.25.0.
  • Not verified until it runs: a writer against the real bucket. This PR's own merge group is the first write; main PRs no longer run Check and Test, so nothing exercises the reader path on this PR after the merge.

Decisions

  1. Warm x86, macOS, and Windows from main. Replaced by the queue-writer decision: the queue and main publish what they build, and no separate warm runs. Trade-off: the queue builds only what its diff selects, so an object that expires is rebuilt by the next queue or main job that builds it, and a queue entry in between pays that compile. mbx-r2-verify measures how often.
  2. 30-day expiry. Confirmed by the maintainer.
  3. Fail the job when the R2 key is rejected or unreachable, instead of building cold. Confirmed by the maintainer.
  4. Release builds stay uncached (release-ffi, release-kt-lib, release-binary). Confirmed by the maintainer.
  5. No flake hash in the namespace. Confirmed by the maintainer.
  6. Where the cache is written and read after ci: run cloud CI only in the merge queue #6038 (picked by the agent resolving the merge, as the option both quests already imply):
    • ✅ Keep the writer rule as is: the queue and main (Nightly, scheduled runs) write; release PRs and every writer read. The cache now mainly speeds up the queue itself, each entry reading what earlier entries and Nightly published, which is the critical path queue-only left.
    • Bring back a post-merge warm on main so a queue entry never pays for an expired object. Rejected: it is the second full build this PR removes, and mbx-r2-verify measures whether the rebuilds matter.
    • Also let main PRs read through an opt-in job. Rejected: queue-only decided main PRs run no cloud CI.

Suggested follow-ups

  • The cache-write Environment also admits the moq-boy-v*, moq-c-v*, moq-cli-v*, moq-gst-v*, and moq-relay-v* tags. No workflow here names the Environment on a tag, but infra/README.md says only main and the queue can deploy to it; drop those policies or document why they exist.
  • Add reads to jobs with no cache yet: video.yml (x86 nix) and audio-quality.yml (ARM nix).
  • cpp.yml, android.yml, and the release dry runs build with rustup or cross targets that nothing writes yet.
  • environment: {name: ..., deployment: false} would stop each writer job creating a deployment record; it needs checking that branch policies still apply without a deployment.
  • nix-cache can reuse this Environment and bootstrap pattern.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 2 commits October 15, 2026 22:36
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every job that used the Actions cache now reads the private mbx-moq-dev
R2 bucket instead, and the macOS and Windows platform jobs gain a cache.
Only cache.yml writes, with a key held in a `cache-write` Environment
that only `main` can deploy to. It now warms x86 Linux, macOS, and
Windows alongside ARM64 Linux, since the 10 GB budget no longer decides
which platforms get a cache.

The bucket and lifecycle rule are checked in under infra/mbx; the tokens
and Environment are maintainer steps documented in infra/README.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Quest outcome: the implementation is complete and the PR stays a draft. Before it can merge, a maintainer has to run the four bootstrap steps listed in the description (bucket and lifecycle rule, two R2 tokens, the cache-write Environment, and the secrets). Until the repository secrets exist, this PR's own CI builds cold with a warning. Measurement is tracked in quest/m0/ci/mbx-r2-verify.md, after the first main warms.

(Written by Claude Opus 5.5)

kixelated and others added 2 commits October 19, 2026 21:08
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Jobs on main and in its merge queue now publish what they compile to R2, in
the cache-write Environment, and pull requests only read. cache.yml keeps
only the dev shell push. mbx 1.25.0's MBX_REMOTE_TRUST_WRITES lets the queue
and Nightly's schedule write, since mbx alone trusts only protected pushes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated kixelated changed the title ci: cache Rust builds in R2 through mbx's S3 backend ci: cache Rust builds in R2, written from the merge queue Oct 20, 2026
@kixelated
kixelated marked this pull request as ready for review October 20, 2026 04:10
@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 24 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0dee828b-b8f0-4b60-b3ad-6398e7b380ee
📥 Commits

Reviewing files that changed from the base of the PR and between 6f0ff0b and 41639e0.

⛔ Files ignored due to path filters: 1
  • infra/mbx/bun.lock is excluded by !**/*.lock
📒 Files selected for processing: 27
  • .github/actions/rust-cache/action.yml
  • .github/workflows/cache.yml
  • .github/workflows/check.yml
  • .github/workflows/dependabot.yml
  • .github/workflows/interop.yml
  • .github/workflows/nightly.yml
  • .github/workflows/obs.yml
  • .github/workflows/platform.yml
  • .github/workflows/release-ffi.yml
  • .github/workflows/release-kt-lib.yml
  • .github/workflows/release-rs.yml
  • .github/workflows/ts.yml
  • .github/workflows/uring.yml
  • .github/workflows/wasm.yml
  • .github/workflows/x11.yml
  • infra/README.md
  • infra/justfile
  • infra/mbx/justfile
  • infra/mbx/lifecycle.json
  • infra/mbx/package.json
  • quest/m0/ci/README.md
  • quest/m0/ci/audit.md
  • quest/m0/ci/mbx-r2-verify.md
  • quest/m0/ci/mbx-r2.md
  • quest/m0/ci/nix-cache.md
  • quest/m0/ci/one-pass.md
  • quest/m0/ci/runners.md
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-20T05:17:29.357735Z 640ea54 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Keeps mbx-r2.md and platform-queue.md deleted and points their links at mbx-r2-verify.md and release-gates.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated added this pull request to the merge queue Oct 20, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 20, 2026
Resolves the conflicts with #6038 (cloud CI only in the merge queue):
cache.yml drops the Rust warm, Check and Test keep their queue-only
gating and write from the merge queue, and OBS, which now runs only for
release, drops its writer Environment. WASM, newly called by Nightly,
names the Environment and inherits secrets so its main run writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 640ea54858

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/actions/rust-cache/action.yml Resolved
A missing access key id or secret on its own was treated like a fork's
empty credentials, so a broken secret built every reader cold without
an error. Only both empty is the fork case now; one empty fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated added this pull request to the merge queue Oct 20, 2026
Merged via the queue into main with commit 895b8cb Oct 20, 2026
5 checks passed
@kixelated
kixelated deleted the quest/m0/ci/mbx-r2 branch October 20, 2026 15:01
kixelated added a commit that referenced this pull request Oct 20, 2026
Take #5685's dev-shell-only cache.yml and push it to nix.moq.dev from
cache-write. List the mbx and nix infra side by side, and point the
Nightly tooling test and the remaining quest links at the nix composite
and nix-cache-verify.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant