Skip to content

ci: accelerate Subtensor CI with R2 sccache and tiered Fireactions pools#2857

Open
UnArbosFive wants to merge 30 commits into
bittensor-core-explorationfrom
codex/fireactions-runner-density-experiment
Open

ci: accelerate Subtensor CI with R2 sccache and tiered Fireactions pools#2857
UnArbosFive wants to merge 30 commits into
bittensor-core-explorationfrom
codex/fireactions-runner-density-experiment

Conversation

@UnArbosFive

@UnArbosFive UnArbosFive commented Jul 12, 2026

Copy link
Copy Markdown

Summary

This is the unified Subtensor CI acceleration change. It supersedes #2855 and combines:

  • Cloudflare R2-backed shared sccache for Rust compilation
  • trusted-writer and fork-safe read-only cache boundaries
  • build-once/fan-out workflow consolidation
  • explicit fireactions-turbo-16 and fireactions-turbo-8 runner lanes
  • retention of latency-sensitive try-runtime work on the European AX102 pool

Shared compiler cache

  • configures sccache centrally through the shared Rust setup path
  • reads bucket-scoped R2 configuration from Firecracker MMDS without logging credentials
  • writes through to R2 during the existing compile job for trusted same-repository PRs and main pushes, avoiding a second post-CI compilation
  • keeps forks read-only: fork jobs are excluded from self-hosted compilers, GitHub withholds their secrets, and the cache setup independently rejects fork payloads
  • retains dedicated maintenance only for devnet/testnet updates, Amsterdam-noon main maintenance, and restricted main/devnet/testnet manual recovery
  • keeps Cargo registry/git caching while disabling duplicate target-directory caching
  • degrades to ordinary Cargo compilation if MMDS, R2, or the sccache server is unavailable
  • reports sccache --show-stats for cache observability

Writer policy

The trust boundary is repository contents-write access, inferred from the PR source; it is not hard-coded to the arbos team. arbos members, direct collaborators, GitHub Apps, or other principals that can push a branch inside RaoFoundation/subtensor are therefore trusted equivalently. Organization members without repository write access are not.

Source/event Cache mode Rationale
Same-repository pull_request Read/write Creating or updating the head branch requires repository write access
Fork or Dependabot PR Read-only or skipped No writer secrets; event guard rejects the source
Push to main Read/write in normal CI Populates each cache shape during its existing compilation
Push to devnet or testnet Read/write maintenance Keeps deployed-state refs warm when they move
Scheduled maintenance Read/write on main at 12:00 Europe/Amsterdam Repairs expired or missing entries outside the PR critical path
Manual maintenance Read/write only when dispatched from main for an enumerated main/devnet/testnet source Recovery/benchmark fallback without arbitrary-ref credentials
Ordinary feature-branch workflow_dispatch Read-only Uses the no-secret sccache-reader environment and preserves manual CI behavior
pull_request_target, arbitrary push, malformed event, partial credentials Read-only/disabled Fails closed

R2 writes are content-addressed. A changed source, compiler, feature set, flag set, or target creates a different key, so artifacts used by older PRs remain alongside newer results until the 30-day lifecycle removes them. sccache stores each successful compiler invocation independently: if a later crate or test fails, earlier valid compilation results remain useful and require no rollback.

The bucket-scoped writer credential is intentionally available to later steps and Rust build scripts in an authorized job because sccache itself needs it. Consequently, every repository-write principal is effectively trusted with that credential for the duration of their ephemeral job. Read-only credentials remain in Fireactions MMDS; writer credentials remain exclusively in the GitHub sccache-writer environment.

The persistent Benchmarking runner remains read-only so a background sccache process cannot retain the writer credential across jobs. The accepted containerized docker-localnet build remains outside sccache; its roughly 15-minute main/release build does not extend ordinary PR critical-path compilation.

Measured CI impact

The final matched comparison uses #2846 at 729385d as the legacy-runner/cache baseline and this PR at e9cf2dd. Both ran against the same Subtensor source on 2026-07-12, at 09:03 and 12:31 UTC respectively.

  • main compile/artifact fan-out: 15:26 -> 11:28 (3:58 faster, 26%)
  • aggregate time across 14 directly comparable compile/build paths: 130.1 -> 83.2 runner-minutes (46.9 minutes saved per PR, 36%)
  • Docker PR workflow end-to-end: 12:36 -> 9:00 (3:36 faster, 29%)
  • isolated production-build cache test: 14:13 cold -> 8:39 warm (5:34 faster, 39%)
Job #2846 baseline Turbo + R2 Improvement
Cargo audit 7:04 2:11 69%
Eco tests 6:21 3:07 51%
Clippy (default) 8:27 4:15 50%
Clippy (all features) 8:52 3:54 56%
Cargo fix 8:31 4:15 50%
wasm32 seam 7:00 2:27 65%
Warnings check 4:10 1:15 70%
Cargo test 6:47 4:40 31%
Runtime artifacts 11:10 9:53 12%
TypeScript E2E fast build 8:20 8:01 4%
TypeScript E2E release build 11:57 8:19 30%
SDK localnet fast node 13:49 10:49 22%
SDK localnet normal node 15:02 11:05 26%
Docker PR workflow 12:36 9:00 29%

These figures intentionally do not claim a 36% reduction in full merge latency. Try-runtime, clone-upgrade, and Zombienet execution are endpoint/test-bound and dominate the tail; they gain little from faster compilation hardware. Try-runtime was materially slower from BHS, which is why it remains on the European pool.

The one-pass writer policy removes the separate PR warming compile. Trusted jobs selected R2 writer mode with zero cache write errors, while parallel jobs immediately reused each other's outputs: the amd64 production binary reached 99.94% cache hits, cargo test 99.32%, all-feature clippy 92.90%, default clippy 54.58%, and cargo fix 64.95%. Average R2 writes were 0.17-1.03s; the production job had only two misses at the upper end.

Runner-density design

The ten-machine 9950X experiment is intentionally fixed at:

Pool Machines Runners per machine Total runners
fireactions-turbo-16 4 2 x 16 vCPU / 56 GiB 8
fireactions-turbo-8 6 4 x 8 vCPU / 28 GiB 24

The three PR-critical compile jobs retain 16 cores:

  • cargo test
  • the shared runtime-artifact build that gates try-runtime and clone-upgrade
  • the amd64 production binary used by the per-PR Docker check

General Rust checks, SDK/docs, E2E builds and execution, and Docker packaging use the 8-core pool.

The release-only production-binary matrix in docker.yml also intentionally uses fireactions-turbo-8 for both amd64 and arm64. It does not gate pull requests, runs infrequently, and favors fleet efficiency over minimum release-build latency. The per-PR amd64 production build remains on fireactions-turbo-16 because it is on the review critical path. This distinction is deliberate; the release matrix is not expected to mirror check-docker.yml's runner assignment.

Try-runtime uses the four interchangeable fireactions-tryruntime runners on AX102. Historical AX102 runs were roughly twice as fast as BHS despite fewer cores, and direct endpoint probes showed materially lower archive-RPC latency. A separate fireactions-tryruntime-finney fallback remains deployed for compatibility, but workflows in this PR do not select it.

Observed capacity

The final run peaked at 3 of 8 fireactions-turbo-16 runners and 15 of 24 fireactions-turbo-8 runners. One full PR is strictly queue-free.

Two perfectly aligned PRs use 6/8 heavy runners but request 30/24 light runners, so up to six light jobs queue. The observed short-job completion profile implies roughly 1-3 minutes of light-lane delay and no heavy-lane delay. Three aligned PRs request 9/8 heavy and 45/24 light runners; one critical heavy job waits about 4:40 for the first slot and up to 21 light jobs queue, so three is outside the low-latency design point. Operationally this is a two-concurrent-PR fleet with modest bursting, not a two-PR queue-free fleet.

The external AX102 try-runtime pool remains a separate bottleneck: each PR requests three of its four runners, so a second overlapping PR queues two try-runtime jobs even when the 9950X fleet is healthy.

Infrastructure dependency

The R2 bucket, MMDS reader configuration, writer secrets, and matching Fireactions pools must remain deployed from the infrastructure repository. Excess compatibility capacity is intentionally excluded from the designed 8/24 runner totals so it can be retired without reducing the experiment pool.

Rollout status

  • cache infrastructure and MMDS delivery are live
  • R2 read hits have been observed from both runner profiles
  • one-pass writer authorization has local fixture coverage for same-repository PRs, forks, Dependabot, malformed events, trusted branches, schedules, and restricted dispatches
  • sccache-writer is restricted to main, devnet, testnet, and PR merge refs; sccache-reader contains no secrets and preserves feature-branch dispatches
  • local shell tests and actionlint pass
  • the ten-machine desired layout is inventory-tested with exact fleet-capacity assertions
  • live host changes are applied only while hosts are idle; no running jobs are intentionally interrupted
  • the branch is based on the current bittensor-core: one Rust core (keys, keyfiles, timelock, codec, RFC-0078 digest, Ledger) under a thin Python SDK #2846 head (729385d); final CI for e9cf2dd is running normally

@vercel

vercel Bot commented Jul 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
subtensor Ready Ready Preview, Comment Jul 12, 2026 12:32pm

Request Review

@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI Review — Skeptic (security review)

VERDICT: VULNERABLE

VERY HIGH account-age scrutiny, mitigated by repository admin permission and matching authorship; no Gittensor association; stacked branch targets bittensor-core-exploration.

Static analysis found a steady-state cache-writer credential exposure affecting same-repository pull requests. No trusted review-instruction files were modified.

Findings

Sev File Finding
HIGH .github/workflows/check-rust.yml:94 PR-controlled jobs receive cache-writer credentials inline

Conclusion

Same-repository PR-controlled code receives R2 writer credentials and can poison compiler-cache objects consumed by later trusted builds. Writer secrets must never enter pull-request jobs.


🔍 AI Review — Auditor (domain review)

VERDICT: 👍

Gittensor association UNKNOWN; the author is a new account with repository admin permission, so workflow routing received direct scrutiny.

The implementation otherwise matches the substantive description, and overlapping PRs are upstream/dependent work rather than competing implementations. No runtime change or spec-version bump applies.

Description discrepancy: the body says the PR remains draft, while current metadata reports it as ready for review.

No build or test was run because the remaining issue is statically evident.

Findings

Sev File Finding
MEDIUM .github/workflows/docker.yml:43 Release production build still uses the general pool inline

Prior-comment reconciliation

  • 7f8e5436: not addressed.github/workflows/docker.yml:43 still routes the release production-binary matrix to fireactions-turbo-8.

Conclusion

Approve after applying the runner-label correction so both release production-binary builds retain the documented 16-core lane.


📜 Previous run (superseded)
Sev File Finding Status
MEDIUM .github/workflows/docker.yml:43 Release production build still uses the general pool ➡️ Carried forward to current findings
.github/workflows/docker.yml:43 still routes the release production-binary matrix to fireactions-turbo-8.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build uses the general 8-core pool

The PR promises to reserve fireactions-turbo for production-binary builds, and the equivalent PR validation build does so, but the release workflow routes this CPU-heavy binary build to fireactions-turbo-8. That contradicts the stated allocation and can lengthen the release critical path. Keep only the image validation and publishing jobs on the 8-core pool.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo]

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build still uses the general pool

The PR says production-binary builds retain the reserved 16-core lane, and the equivalent PR build correctly uses fireactions-turbo. This release job performs the same cross-compiled production build but routes both architectures to the general 8-core pool. Keep the expensive compilation on the documented reserved lane; the image and publish jobs can remain on fireactions-turbo-8.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo]

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build still uses the general pool

The PR says production-binary builds retain the 16-core fireactions-turbo lane, but this production binary matrix is routed to the general 8-core pool. This is the cross-compilation-heavy build the capacity policy explicitly reserves for 16 cores.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo]

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build still uses the general pool

The PR states that production-binary builds retain the reserved 16-core lane, but this release job routes both architecture builds to the general 8-core pool. This contradicts the documented capacity policy and can lengthen release builds or contend with general workloads. Route this compilation job to fireactions-turbo-16; the image-validation and publishing jobs can remain on the 8-core pool.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo-16]

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@UnArbosFive UnArbosFive changed the title ci: trial 16-core and 8-core Fireactions pools ci: accelerate Subtensor CI with R2 sccache and tiered Fireactions pools Jul 12, 2026
@UnArbosFive UnArbosFive force-pushed the codex/fireactions-runner-density-experiment branch from c157fb5 to db0d556 Compare July 12, 2026 02:11

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build still uses the general pool

The PR states that both amd64 and arm64 production-binary builds retain 16 cores, but this release matrix still runs them on fireactions-turbo-8. This also diverges from the equivalent PR validation job in check-docker.yml. Route this compile-heavy job to the 16-core pool.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo-16]

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build still uses the general pool

The PR states that both amd64 and arm64 production binary builds retain 16 cores, and the equivalent PR validation job uses fireactions-turbo-16. This release matrix still selects the 8-core pool, contradicting that allocation and potentially doubling latency on the release-critical builds.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo-16]

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@UnArbosFive UnArbosFive marked this pull request as ready for review July 12, 2026 02:43

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build still uses the general pool

The PR description says the amd64 and arm64 production-binary builds retain the 16-core lane, but this release workflow routes both builds to the 8-core pool. This also differs from the equivalent PR validation build in check-docker.yml. Route this compile-heavy matrix to fireactions-turbo-16.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo-16]

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build still uses the general pool

This production-binary matrix still runs on the 8-core general lane, contrary to the PR’s stated allocation of the amd64 and arm64 production builds to 16 cores. It also differs from the equivalent matrix in check-docker.yml. Route this compile-heavy release job to the 16-core pool.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo-16]

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@UnArbosFive UnArbosFive force-pushed the codex/fireactions-runner-density-experiment branch from 163e63a to c5dd58b Compare July 12, 2026 03:15
@UnArbosFive UnArbosFive force-pushed the codex/fireactions-runner-density-experiment branch from c5dd58b to d981a4c Compare July 12, 2026 09:35

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

binary:
name: production binary (${{ matrix.platform.arch }})
needs: setup
runs-on: [self-hosted, fireactions-turbo-8]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[MEDIUM] Release production build still uses the general pool

The PR description explicitly assigns both amd64 and arm64 production-binary builds to the 16-core lane, but this release matrix still runs them on fireactions-turbo-8. This contradicts the documented capacity design and leaves the most expensive release compiles on half-sized runners. Route this build job to the dedicated 16-core pool, consistent with check-docker.yml.

Suggested change
runs-on: [self-hosted, fireactions-turbo-8]
runs-on: [self-hosted, fireactions-turbo-16]

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Addressed as a documentation contradiction. The PR description now distinguishes the per-PR amd64 production build, which remains on fireactions-turbo-16, from the infrequent release-only amd64/arm64 matrix, which intentionally stays on fireactions-turbo-8 to favor fleet efficiency over release latency. No runner change is intended here.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI review — see the sticky summary comment for the verdict and the inline comments below for specific findings.

Comment on lines +93 to +94
environment:
name: ${{ github.event_name == 'workflow_dispatch' && 'sccache-reader' || 'sccache-writer' }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[HIGH] PR-controlled jobs receive cache-writer credentials

This selects sccache-writer for every event except workflow_dispatch, including pull_request. The job then checks out and executes PR-controlled composite actions, build scripts, and compiler inputs while passing the writer secrets. A same-repository PR can exfiltrate these credentials or overwrite cache objects for later trusted builds; the event checks inside sccache-configure.sh occur only after the secrets have already entered PR-controlled code.

Use the reader environment for every pull-request job and do not pass writer secrets there. Apply the same correction to the other PR-triggered workflows introduced here.

Suggested change
environment:
name: ${{ github.event_name == 'workflow_dispatch' && 'sccache-reader' || 'sccache-writer' }}
environment:
name: ${{ github.event_name == 'push' && 'sccache-writer' || 'sccache-reader' }}

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: VULNERABLE

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