Downstream Migration Checklist
Use this guide when a downstream GitHub Actions repo is moving onto the current GloriousFlywheel runner and cache contract.
This is the shortest honest checklist for the tranche-1 migration lane tracked
in #210, and the same operator path should be used for any later promotion
candidate surfaced by just orgwide-enrollment-queue.
Treat this as a bounded migration guide. It is not a claim that shared-label configuration automatically means accessible runners, broad authority, or implemented hosted fallback behavior.
Who This Is For
- org repos that want to use shared capability runner labels
- user-owned repos that still need owner-scope cleanup such as
XoxdWM - downstream repos that want GloriousFlywheel composite actions without manual platform archaeology
Current Downstream Contract
Shared runner labels:
| Label | Use when |
|---|---|
tinyland-docker |
general CI, lint, test, and non-Docker builds |
tinyland-nix |
Nix builds and reproducible flake workflows |
tinyland-nix-heavy |
memory-heavy Rust/Nix jobs when the additive heavy lane is available |
tinyland-dind |
Docker-in-Docker or privileged container build paths |
Composite actions:
| Action | Use when |
|---|---|
tinyland-inc/GloriousFlywheel/.github/actions/setup-flywheel@main |
you only want cache/runtime auto-configuration |
tinyland-inc/GloriousFlywheel/.github/actions/docker-job@main |
you want a simple shared-runner job with Bazel cache configured |
tinyland-inc/GloriousFlywheel/.github/actions/nix-job@main |
you want a Nix job with cache setup handled for you |
Default stance:
- prefer shared runner labels first
- use composite actions when you want the cache/runtime setup packaged for you
- treat GloriousFlywheel’s own first-party validation and security scans as
dogfood gates; they should run on shared
tinyland-*lanes, not GitHub-hosted runners - do not depend on legacy
Jesssullivan/GloriousFlywheel/...paths - do not create repo-specific runner labels as the normal migration answer
- do not solve GitHub owner-scope gaps inside a downstream repo workflow; route them through the owner implementation overlay or mark the repo blocked
- treat the current
tinyland-*proof surfaces as primary when describing the live GitHub runner contract
Current Queue Boundary
The live rollout queue now starts from just orgwide-enrollment-queue, not
from stale issue comments or fixed exemplar lists.
That queue should distinguish:
- real current authority consumers
- hybrid-by-policy repos
- blocked or nominal shared-label repos
- hosted template consumers that should stay out of runner-enrollment claims
- current examples include
tinyland.devas mostly hosted onmain,betterkvmas a platform-prereq repo,XoxdWMas toggle-gated, andyt-textas hybrid by policy withtubebrain-nixtracked separately as a standalone compatibility lane pending owner-overlay rehome or retirement
Checklist
-
Inventory your workflows. Identify which jobs are general CI, Nix builds, or container builds.
-
Map each job to one shared runner label.
For Nix jobs, choose explicitly between:
tinyland-nixfor the ordinary8Gibaseline lanetinyland-nix-heavyfor recurring memory-heavy jobs when that additive lane is deployed
-
Decide whether the repo needs composite actions. If plain shell steps are enough, labels alone are acceptable.
-
Remove or replace any stale personal upstream references. Prefer
tinyland-inc/GloriousFlywheel/.github/actions/...@main. -
Validate cache expectations.
tinyland-nixgets Attic defaults;tinyland-dockerandtinyland-nixget Bazel cache defaults on self-hosted runners. Reachable self-hosted cache and cluster-local DNS are part of the proof contract, not optional polish. For Bazel jobs, fail early whenBAZEL_REMOTE_CACHEis missing on a dogfood lane instead of silently falling back to heavy local work. Keep package pull requests read-only for Bazel remote-cache writes; allow uploads only on trusted push jobs that explicitly setGF_BAZEL_REMOTE_UPLOAD=true. -
Validate self-hosted Nix bootstrap. For raw
nixcommands ontinyland-nix, useDeterminateSystems/determinate-nix-action@v3or thenix-jobcomposite action instead of assuming Nix is preinstalled on the runner forever. -
Run one branch-scoped proof workflow on the shared runner path before converting the full repo.
-
Validate local development entrypoints. If the repo has a
flake.nix, copy the shape inexamples/flake/flake.nixandexamples/flake/.envrc: local sessions should enter throughdirenv allowornix develop, deriveGF_BAZEL_SUBSTRATE_MODEfromBAZEL_REMOTE_CACHE, and avoid presenting compatibility-local-only as GloriousFlywheel-backed execution. -
Keep a rollback path ready. A downstream job can temporarily return to
ubuntu-latestor another GitHub-hosted runner while its shared-runner contract is being stabilized.This rollback language is for downstream migration only. It is not an acceptable fallback for GloriousFlywheel’s own merge-blocking validation, security scans, Bzlmod/Bazel canaries, or RBE proof/chaos workflows. The reusable Nix workflow now uses the same
nix-jobsubstrate path as the direct action, but it still does not implement automatic failover back to hosted runners.
Canonical Consumer Pattern
This is the reference downstream shape for a repo that wants one cache-backed Bazel job and one Nix job:
name: CI
on:
push:
pull_request:
permissions:
contents: read
jobs:
bazel:
runs-on: tinyland-nix
steps:
- uses: actions/checkout@v6
- uses: tinyland-inc/GloriousFlywheel/.github/actions/nix-job@main
env:
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN || '' }}
GF_BAZEL_REMOTE_UPLOAD: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'true' || 'false' }}
with:
attic-public-key: ${{ vars.ATTIC_PUBLIC_KEY || '' }}
command: |
test -n "${BAZEL_REMOTE_CACHE:-}"
test "${GF_BAZEL_SUBSTRATE_MODE:-}" = "shared-cache-backed"
nix develop -c bash ./scripts/gloriousflywheel-bazel.sh build //...
push-cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && secrets.ATTIC_TOKEN != '' && 'true' || 'false' }}
build:
runs-on: tinyland-nix
steps:
- uses: actions/checkout@v6
- uses: tinyland-inc/GloriousFlywheel/.github/actions/nix-job@main
env:
ATTIC_TOKEN: ${{ secrets.ATTIC_TOKEN || '' }}
with:
attic-public-key: ${{ vars.ATTIC_PUBLIC_KEY || '' }}
command: nix build .#default
push-cache: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && secrets.ATTIC_TOKEN != '' && 'true' || 'false' }}
Why this is the reference pattern:
- it uses stable shared labels
- it passes
ATTIC_PUBLIC_KEYfor public-read cache trust andATTIC_TOKENonly when private reads or trusted writes are required - it uses the current public GloriousFlywheel action path
- it proves Bazel cache attachment before running the repo-managed cache-backed Bazel wrapper
- it leaves Bazel remote-cache writes disabled unless a trusted push job
explicitly opts into
GF_BAZEL_REMOTE_UPLOAD=true - it keeps pull requests read-only for Attic and only enables Nix cache
publication on trusted default-branch pushes with an
ATTIC_TOKEN - the reusable Nix workflow follows this same
nix-jobcache/bootstrap path fornix flake check,nix flake show, andnix build
Verification
After the first shared-runner migration:
- confirm the job lands on the expected runner label
- confirm the workflow still passes without hidden repo-local assumptions
- confirm Nix jobs see the expected cache environment
- confirm Bazel jobs see
BAZEL_REMOTE_CACHEandGF_BAZEL_SUBSTRATE_MODE=shared-cache-backed - compare runtime against the previous GitHub-hosted baseline
Rollback
If the shared-runner path is not ready yet:
- for a downstream repo only, move the affected job back to
ubuntu-latest - keep the consumer workflow change small and reversible
- leave the rest of the repo on the previous runner path until the shared contract is fixed
- do not use this rollback for GloriousFlywheel’s own merge-blocking validation or security workflows
- do not describe that rollback as a supported automatic platform behavior