Skip to content

ci: use host-local Fireactions caches#2926

Draft
UnArbosFive wants to merge 17 commits into
stagingfrom
codex/fireactions-host-cache-pilot
Draft

ci: use host-local Fireactions caches#2926
UnArbosFive wants to merge 17 commits into
stagingfrom
codex/fireactions-host-cache-pilot

Conversation

@UnArbosFive

@UnArbosFive UnArbosFive commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

What changed

  • discovers the host-local sccache tier and fails open to direct R2
  • routes trusted clone snapshot downloads through an authenticated host-local gateway when available
  • refreshes exact remote compiler keys every six hours
  • mirrors each successful scheduled clone snapshot to an immutable R2 object and publishes its manifest last for per-host polling
  • verifies the exact node-subtensor-runtime Cargo feature graph after cargo clean
  • keeps paired direct-origin and local-cache benchmarks available through manual workflow dispatch
  • uses the original turbo runner label for builds, clone testing, and diagnostics

Why

Fireactions VMs are ephemeral while their physical hosts persist. Immutable compiler objects and large snapshot artifacts can therefore be reused locally instead of being transferred again for every VM, while R2 and GitHub Actions remain authoritative origins.

A GitHub Actions maintenance job can warm only the physical host selected for that job, so it cannot maintain a fleet sharing one production label. Snapshot freshness is now published through R2 for each host to poll. Compiler objects remain content-addressed: a cold local lookup falls through to a remote cache hit and then remains local for later VMs.

The former warm workflow compiled the whole workspace, but representative CI selected only node-subtensor-runtime. Cargo feature unification produced different rustc/sccache keys. The exact-key warmer now cleans the job-local target directory and runs the same command as CI.

Security and failure behavior

  • local endpoints are reachable only from the isolated runner bridge
  • sccache local credentials are bucket-scoped and read-only
  • writer credentials remain restricted to protected producer and prewarm jobs
  • the mirror accepts one exact R2 endpoint and content-addressed object layout, and publishes the manifest only after the archive upload succeeds
  • artifact requests require the short-lived GitHub job token and are checked against repository, workflow, branch, artifact name, digest, and size
  • clients fail open to direct R2 or GitHub Actions
  • fork PRs cannot execute the protected writer prewarm or self-hosted benchmarks

Validation

  • exact runtime verification reached 597 Rust hits and 0 misses after a clean build
  • release compilation improved from 225s on local cold fill to 145s warm
  • a 2 GiB snapshot took 89s from GitHub and 8–9s from the local cache
  • clone-upgrade completed in 365s on cold fill and 309s warm
  • paired same-VM small-object reads showed no material regression versus direct R2
  • mirror signing and manifest boundary tests pass
  • sccache configuration, immutable snapshot selection, artifact boundary, runtime classifier, YAML, and diff checks pass

@UnArbosFive UnArbosFive added the fireactions-cache-benchmark Route selected PR cache benchmarks to the isolated turbo-8 canary label Jul 15, 2026
@vercel

vercel Bot commented Jul 15, 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 16, 2026 2:06pm

Request Review

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI Review — Skeptic (security review)

VERDICT: SAFE

VERY HIGH account-age scrutiny, mitigated by admin repository permission, substantive prior subtensor contributions, matching commit authorship, and no known Gittensor association; branch targets staging.

Static analysis covered the complete current diff, including the latest E2E coverage-routing commit, protected credential boundaries, host-local cache discovery, artifact provenance and integrity checks, archive extraction, workflow permissions, and authoritative-origin fallbacks. Trusted AI-review instructions were unchanged.

Findings

No findings.

Conclusion

No malicious behavior or security vulnerability was found in the reviewed changes.


🔍 AI Review — Auditor (domain review)

VERDICT: 👍

Gittensor association UNKNOWN; author has repository admin permission and substantial recent subtensor contributions.

The implementation matches the substantive PR description. Overlaps with #2853 and #2804 are incidental. This CI-only change targets staging, so no runtime spec-version bump applies.

Cache access fails open to authoritative origins, while artifact identity, digest, size, producer workflow, and publication ordering are validated. The latest E2E routing remains fail-safe for unknown or incomplete change sets. No auto-fix was needed.

Findings

No findings.

Conclusion

The host-local cache pilot is ready to merge. The cache, snapshot mirroring, and selective E2E changes preserve trusted execution and artifact-integrity boundaries.

@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.

payload="$RUNNER_TEMP/artifacts.json"
for attempt in 1 2 3 4 5; do
gh api "repos/$GITHUB_REPOSITORY/actions/runs/$PRODUCER_RUN_ID/artifacts?per_page=100" > "$payload"
count=$(jq '[.artifacts[] | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")

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.

[LOW] Count only artifacts the warming loop can process

This readiness count includes expired artifacts, but the processing query below excludes them. If a run contains only expired matching artifacts, the retry loop exits and the job succeeds after warming nothing. Apply the same expiry filter here so maintenance fails or retries instead of reporting a false success.

Suggested change
count=$(jq '[.artifacts[] | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")
count=$(jq '[.artifacts[] | select(.expired == false) | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@UnArbosFive

UnArbosFive commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Benchmark results on the standard 8 vCPU / 28 GiB turbo runner shape:

  • Exact runtime prewarm: first clean check 155s with 213 Rust hits / 384 misses; second clean check 49s with 596 hits / 1 miss (99.83% Rust hit rate).
  • Paired same-VM runtime reads: direct R2 34s and 33s (33.5s mean); warm host-local 38s and 31s (34.5s mean). This small-object check is effectively tied.
  • Real PR release build: recent turbo job median 332s; local cold-fill job 280s (225s compile); warm job 206s (145s compile). Both cache-enabled compiles had 1,890 Rust hits / 0 misses.
  • 2.0 GiB snapshot, same VM: direct GitHub 89s; host-local 9s and 8s. The real clone cold fill took 67s; the warm rerun took 19s.
  • Full clone-upgrade: recent turbo median 601s; local cold fill 365s; warm 309s. Both passed.

Exact remote compiler keys refresh every six hours. Scheduled clone snapshots are produced daily with a 36-hour freshness gate and now publish an immutable R2 mirror manifest for per-host polling. There is no random-runner local maintenance job because one selected VM cannot warm a shared-label fleet.

Runs: exact-key verification https://github.com/RaoFoundation/subtensor/actions/runs/29456620982 ; paired/artifact benchmark https://github.com/RaoFoundation/subtensor/actions/runs/29456911456 ; cold + warm PR attempts https://github.com/RaoFoundation/subtensor/actions/runs/29456621901

@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.

payload="$RUNNER_TEMP/artifacts.json"
for attempt in 1 2 3 4 5; do
gh api "repos/$GITHUB_REPOSITORY/actions/runs/$PRODUCER_RUN_ID/artifacts?per_page=100" > "$payload"
count=$(jq '[.artifacts[] | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")

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.

[LOW] Count only artifacts the warming loop can process

This count includes expired artifacts and any name with the try-runtime prefix. Such an artifact can end polling even though the loop skips it or download-artifact.sh rejects its name, producing misleading maintenance results. Match the downloader’s exact allowlist and the loop’s expiry filter.

Suggested change
count=$(jq '[.artifacts[] | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")
count=$(jq '[.artifacts[] | select(.expired == false) | select(.name == "mainnet-snapshot" or .name == "try-runtime-snap-v0.10.1-mainnet" or .name == "try-runtime-snap-v0.10.1-testnet" or .name == "try-runtime-snap-v0.10.1-devnet")] | length' "$payload")

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@UnArbosFive

Copy link
Copy Markdown
Contributor Author

Final validation note: a subsequent run reached 597 Rust hits / 0 misses, which exposed that sccache omits the language-specific miss row at zero. The gate initially parsed that omission as empty and failed despite a perfect cache result. Commit e339b14 normalizes omitted counters to zero; the final validation is green with 596 hits / 1 miss on the fill pass and 597 hits / 0 misses (100%) after the second cargo clean.

Final validation: https://github.com/RaoFoundation/subtensor/actions/runs/29458291945

@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.

payload="$RUNNER_TEMP/artifacts.json"
for attempt in 1 2 3 4 5; do
gh api "repos/$GITHUB_REPOSITORY/actions/runs/$PRODUCER_RUN_ID/artifacts?per_page=100" > "$payload"
count=$(jq '[.artifacts[] | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")

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.

[LOW] Count only artifacts the warming loop can process

This readiness check counts expired artifacts and any name beginning with try-runtime-snap-v0.10.1-, while the loop excludes expired entries and download-artifact.sh accepts only three exact network names. An unusable artifact can therefore stop polling before a usable one exists. Apply the processing loop/downloader’s expiry and exact-name filters here.

Suggested change
count=$(jq '[.artifacts[] | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")
count=$(jq '[.artifacts[] | select(.expired == false) | select(.name == "mainnet-snapshot" or .name == "try-runtime-snap-v0.10.1-mainnet" or .name == "try-runtime-snap-v0.10.1-testnet" or .name == "try-runtime-snap-v0.10.1-devnet")] | length' "$payload")

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@UnArbosFive UnArbosFive removed the fireactions-cache-benchmark Route selected PR cache benchmarks to the isolated turbo-8 canary label Jul 16, 2026
@UnArbosFive UnArbosFive changed the title ci: pilot host-local Fireactions caches ci: use host-local Fireactions caches Jul 16, 2026

@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.

payload="$RUNNER_TEMP/artifacts.json"
for attempt in 1 2 3 4 5; do
gh api "repos/$GITHUB_REPOSITORY/actions/runs/$PRODUCER_RUN_ID/artifacts?per_page=100" > "$payload"
count=$(jq '[.artifacts[] | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")

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.

[LOW] Count only artifacts the warming loop can process

This count still includes expired artifacts and any name beginning with the try-runtime prefix, while the loop excludes expired entries and download-artifact.sh accepts only three exact try-runtime names. An expired or similarly prefixed artifact can make the retry loop stop despite having nothing usable, or make the warming step fail. Apply the same expired == false and exact-name allowlist predicates here and in the selection at line 69.

Suggested change
count=$(jq '[.artifacts[] | select(.name == "mainnet-snapshot" or (.name | startswith("try-runtime-snap-v0.10.1-")))] | length' "$payload")
count=$(jq '[.artifacts[] | select(.expired == false) | select(.name == "mainnet-snapshot" or .name == "try-runtime-snap-v0.10.1-mainnet" or .name == "try-runtime-snap-v0.10.1-testnet" or .name == "try-runtime-snap-v0.10.1-devnet")] | length' "$payload")

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@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 +251 to +252
publisher.put(
f"{MIRROR_PREFIX}/{args.artifact_name}/latest.json",

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.

[LOW] Prevent stale writers from replacing the latest manifest

Both the scheduled snapshot producer and per-PR prewarm job call this publisher. If a prewarm selects artifact A, then a scheduled refresh publishes newer artifact B before the prewarm finishes, this unconditional final PUT replaces latest.json with A and gives it a new published_at. Hosts can consequently prefetch an older snapshot until another publication. Preserve monotonic freshness—for example, publish latest.json only from the scheduled producer, or conditionally replace it only when the existing manifest has an older artifact/production timestamp.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@UnArbosFive UnArbosFive changed the base branch from main to staging July 16, 2026 11:50
@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

@github-actions

Copy link
Copy Markdown
Contributor

🔄 AI review updated — Skeptic: SAFE Auditor: 👍

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