Consumer Onboarding

Consumer onboarding (plain RBE / image-builder repos)

config/consumer-registry.json is the registry-of-record for repositories that consume the shared GloriousFlywheel substrate as plain RBE / container image builders — they build/test/push on the shared runner pool via an overlay extra_runner_sets anchor. It answers the question that is otherwise archaeology: “is THIS repo enrolled, and via which path?”

This is not the PR-environment spoke registry. If your repo needs per-PR ephemeral environments (*.pr.<brand_domain>, Blahaj app install, a per-spoke cache quota), use config/spoke-registry.json / docs/build-system/spoke-onboarding.md instead. A repo is a spoke or a consumer, never both (the validator enforces the mutual exclusion).

Onboard in one PR

Add one entry to config/consumer-registry.json consumers[]:

{
  "github_repository": "Owner/repo",
  "runner_class": "tinyland-nix",
  "image_repository": "ghcr.io/owner/repo",
  "tfvars_anchor": "repo-nix",
  "substrate_mode": "executor-backed",
  "enrolled_via": "overlay-extra_runner_sets",
  "workflow": ".github/workflows/docker-ghcr.yml",
  "build_targets": ["//path:image", "//path:push"],
  "enrolled": true
}
field meaning / rule
github_repository <owner>/<repo>. Unique; must not also be a spoke.
runner_class the shared capability label the workflow’s runs-on requests (tinyland-nix, tinyland-dind, …). Validated against the same taxonomy as the runs-on guard — a repo-shaped label (repo-nix) is rejected.
image_repository must equal ghcr.io/<owner-lowercased>/<repo> (site.scaffold CI-SCHEMA).
tfvars_anchor the extra_runner_sets key in the implementation overlay’s arc-runners tfvars (registration identity). Unique. Recorded here; verified live by flywheel-enroll-verify.
substrate_mode executor-backed or shared-cache-backed (the arc-runner module’s own value).
enrolled_via overlay-extra_runner_sets.
enrolled boolean. The static validator asserts the type only; flywheel-enroll-verify earns true by checking the three live realities.

Then run just flywheel-enroll-register (or just consumers-onboarding-contract-check, which also runs in just check).

Static vs live: what is checked where

The static validator (scripts/validate-consumer-registry.py, in just check) is GF-core-self-contained — it cannot see the overlay tfvars (a separate repo), the consumer workflow (another repo), or the cluster. It checks the entry’s internal honesty: required fields, the runner_class taxonomy, the ghcr image-org convention, the substrate/path enums, uniqueness, and the spoke mutual exclusion.

The three live realities are confirmed by just flywheel-enroll-verify in the implementation overlay (where the overlay tfvars, the consumer checkout, and the kubeconfig are reachable), each reusing an already-built guard:

  1. the tfvars_anchor exists and is RBE-wired (validate-overlay-runner-taxonomy.py);
  2. the consumer workflow runs-on uses the shared runner_class (the runs-on label rules);
  3. the live runner is managed-by=Helm with no manual drift (the drift audit).

enrolled: true requires all three. Runner provisioning (tofu apply) is operator-gated — the just flywheel-enroll umbrella stops and hands off.

GloriousFlywheel