Bazel Remote Execution

Bazel Remote Execution

The GloriousFlywheel product target is broad, default-capable, multi-tenant Bazel remote execution and remote caching for Bazel/Nix-centered developer and CI workflows. It should compete in the Buildbarn / bazel-remote / BuildBuddy / NativeLink class: pooled remote build, remote test, cache-first local acceleration, runner-backed CI, tenant-aware policy, durable CAS/action-cache, and operator-facing evidence.

That is the target state, not the current state. Today GloriousFlywheel has a narrow, counted Bazel remote-execution proof lane. It is not the default product path yet.

The default operational posture remains cache-forward local and CI execution: ordinary builds attach to shared Attic and Bazel remote-cache surfaces when those endpoints are configured. Executor-backed work is opt-in, target-scoped, and governed by the proof contract.

Current Status

What is real now:

  • The machine-readable eligibility manifest records 34 proved target classes. The list below names the main product shapes; the manifest is the source of truth for exact labels, proof runs, worker image digests, and boundaries.
  • //app:build has a forced REAPI proof through the GF-owned proof cell.
  • //app:unit_tests has a forced remote-test proof through the same lane.
  • tinyland-inc/omux.xoxd.ai //:unit_tests has a forced public consumer Vite/SvelteKit Vitest unit-test proof.
  • tinyland-inc/omux.xoxd.ai //:build has a forced public consumer SvelteKit/Vite standalone build proof.
  • //:deployment_bundle has a forced packaging proof over declared k8s and Nix inputs.
  • //docs-site:build has a forced static docs-site rendering proof.
  • //:public_vendor_handoff_fixture has a forced public-input consumer proof using a checked-out WAS-110 workspace and verified injected repository input.
  • //examples/hello-go:hello_test has a forced pure-Go remote-test proof for one trivial rules_go unit-test class.
  • //examples/hello-go-cgo:cgo_test has a forced cgo-backed Go remote-test proof for one trivial rules_go + C toolchain target class.
  • //examples/hello-rust:hello_test and //examples/hello-cc:hello_test each have a forced remote-test proof for one trivial target class.
  • //docs-site:playwright_chromium_smoke has a forced Chromium static-site Playwright smoke proof for one browser/web target class.
  • tinyland-inc/omux.xoxd.ai //:puppeteer_chromium_smoke has a forced Chromium static-output Puppeteer smoke proof for one public consumer browser/web target class.
  • tinyland-inc/omux.xoxd.ai //:playwright_chromium_smoke has a forced Chromium static-output Playwright smoke proof for one public consumer browser/web target class.
  • tinyland-inc/omux.xoxd.ai //:playwright_local_route_smoke has a forced Chromium local-server Playwright route-smoke proof for one public consumer browser/web target class.
  • tinyland-inc/omux.xoxd.ai //:puppeteer_local_route_smoke has a forced Chromium local-server Puppeteer route-smoke proof for one public consumer browser/web target class.
  • Jesssullivan/jesssullivan.github.io //:puppeteer_chromium_smoke has a forced Chromium static-output Puppeteer smoke proof for a second public consumer browser/web target class.
  • Jesssullivan/jesssullivan.github.io //:playwright_chromium_smoke has a forced Chromium Playwright runtime-smoke proof for one public consumer browser/web target class.
  • Jesssullivan/jesssullivan.github.io //:sveltekit_vite_build_smoke has a forced SvelteKit/Vite build-smoke proof for one public consumer web build target class.
  • Jesssullivan/jesssullivan.github.io //:types_unit_tests has a forced SvelteKit/Vite/Vitest proof for one public consumer unit-test target class.
  • tinyland-inc/tinyland.dev //packages/tinyland-grafana:test has a forced private consumer package Vitest proof using private checkout authority and verified private distdir staging.
  • tinyland-inc/tinyland.dev //:app_typecheck has a forced private consumer root SvelteKit app typecheck proof using GitHub App checkout authority and verified private distdir staging.
  • tinyland-inc/tinyland.dev //:app_build has a forced private consumer root Vite/SvelteKit production-build proof using the same GitHub App checkout authority and verified private distdir staging.
  • tinyland-inc/tinyland.dev //packages/tinyland-activitypub:test has a forced private consumer package Vitest proof using the same GitHub App checkout authority and verified private distdir staging.
  • tinyland-inc/tinyland.dev //packages/tinyland-a11y-engine:typecheck has a forced private consumer package TypeScript typecheck proof using the same GitHub App checkout authority and verified private distdir staging.
  • Jesssullivan/MassageIthaca //:sveltekit_node_build has a forced private consumer SvelteKit/Vite production-build proof using repo-scoped deploy-key checkout authority.
  • scripts/bazel-cache-backed.sh can run in executor-backed mode when both BAZEL_REMOTE_CACHE and BAZEL_REMOTE_EXECUTOR are set explicitly.
  • ARC runner modules can inject BAZEL_REMOTE_EXECUTOR only when bazel_executor_endpoint is configured; the default value is empty.
  • target eligibility is machine-checked by config/rbe-target-eligibility.json.

What is not real yet:

  • broad remote build for every Bazel target
  • default .bazelrc executor endpoint literals
  • RustFS as trusted RBE CAS/action-cache authority
  • remote execution for OpenTofu validation, image publication, dev servers, or targets with private mutable inputs
  • broad remote execution for Go, Rust, or C++ tests beyond the proved trivial target classes
  • broad Vitest or web unit-test RBE beyond //app:unit_tests, the public omux //:unit_tests target class, and the proved private tinyland.dev Grafana and ActivityPub package target classes
  • broad private app typecheck/build/package-test RBE beyond the proved tinyland-inc/tinyland.dev //:app_typecheck, //:app_build, and package targets //packages/tinyland-grafana:test and //packages/tinyland-activitypub:test, plus package typecheck target //packages/tinyland-a11y-engine:typecheck
  • broad Vite/SvelteKit build RBE beyond //app:build, //docs-site:build, the public consumer omux //:build target class, the private tinyland-inc/tinyland.dev //:app_build class, and the private Jesssullivan/MassageIthaca //:sveltekit_node_build class
  • broad Playwright, broad Puppeteer, deployed-environment E2E, Firefox, or browser-download-at-action-time remote test classes (WebKit is proved for one consumer static-smoke target class via run 27330688866, not broadly)
  • public adoption docs that promise remote build as the normal path

Those are maturity gaps, not non-goals. The route to default RBE is to turn the counted target-class proofs into a production contract: durable CAS/action-cache authority, external-input authority, tenant isolation, quota/fair scheduling, worker provenance, cache-write policy, audit, and self-service onboarding.

Architecture

The first endpoint is gf-reapi-cell, a GloriousFlywheel-owned REAPI proof cell. It implements the minimal REAPI surface needed for proof work:

  • Capabilities
  • ByteStream
  • CAS
  • Action Cache
  • Execution
  • WaitExecution

The current proof cell stores CAS and action-cache data on service-local proof storage. That is deliberate. It keeps the proof independent from RustFS while RustFS still has bucket-index reliability debt.

The proof-local action-cache authority now has first safety primitives: attested AC writers, server-attached platform tags, append-only AC audit rows, and a W2.4 nuke-key/quarantine drill for one poisoned AC key. The Execute path also has the first scheduler/placement seam: after executor-pool and quota admission, the cell records enqueue, start, completion, inflight, and queue-time metrics by instance_name and pool, then acquires a local worker-pool lease bounded by GF_REAPI_WORKER_POOLS when configured. Worker-pool rules can now carry a static workers inventory, so execution metadata can name the selected worker identity instead of only a generated local slot. The cell also has an opt-in, token-protected in-memory heartbeat registry: GF_REAPI_WORKER_REGISTRY_TTL + GF_REAPI_WORKER_REGISTRY_TOKEN allow workers to post /worker/heartbeat, and non-expired live workers are preferred for scheduler lease provenance. These are productionization steps toward broad/default RBE, not a claim that gf-reapi-cell is already a production multi-tenant CAS/action-cache or distributed executor service. The remaining gate is still durable storage, retention, restore, remote worker dispatch, durable worker registration/control-plane state, durable tenant quota, fair scheduling, visibility, chaos proof, and default-on rollout policy.

The current RustFS deployment is not a trusted RBE CAS/action-cache authority because RustFS returned NoSuchBucket for existing bucket data/metadata and required a controlled restart to recover the S3 API view. The live operator surface also lacks a proved signed non-restart repair runbook for that recurrence. CAS/action-cache production authority needs stronger evidence than “objects are on disk”: retention, restore, quota, tenant namespace isolation, write admission, audit, observability, and failure mode proof. RustFS can be reconsidered only if TIN-1147 repairs, replaces, or proves that backend path. Until then, durable CAS/action-cache authority is a separate backend decision, not a side effect of the current OpenTofu state or Attic/RustFS cache services.

Modes

Mode Trigger Product meaning
compatibility-local-only no Bazel cache endpoint local/debug path, not shared substrate proof
shared-cache-backed BAZEL_REMOTE_CACHE only normal cache-forward local/CI acceleration
executor-backed BAZEL_REMOTE_CACHE and BAZEL_REMOTE_EXECUTOR opt-in RBE path for eligible targets
explicit proof GF_RBE_PROOF_MODE=explicit plus executor/cache env countable evidence path, not ordinary product usage

BAZEL_REMOTE_EXECUTOR and BAZEL_REMOTE_CACHE are separate authorities. The executor endpoint runs actions. The cache endpoint is still the CAS/action-cache surface passed to Bazel. Do not collapse those variables into one product claim.

Operator Usage

For ordinary source-repo Bazel dogfood, keep using the cache-backed path:

just cache-contract-strict
just bazel-build-cached //app:build

For an explicit proof run, use the non-default proof wrapper:

GF_RBE_PROOF_MODE=explicit \
GF_RBE_PROOF_FORCE_EXECUTION=true \
GF_BAZEL_SUBSTRATE_MODE=executor-backed \
BAZEL_REMOTE_CACHE=grpc://bazel-cache.nix-cache.svc.cluster.local:9092 \
BAZEL_REMOTE_EXECUTOR=grpc://gf-reapi-cell.gf-rbe.svc.cluster.local:8980 \
bash ./scripts/bazel-rbe-proof.sh --target //app:build

For ordinary wrapper-managed executor-backed work, use only target classes that are already proved in RBE Target Eligibility:

GF_BAZEL_SUBSTRATE_MODE=executor-backed \
BAZEL_REMOTE_CACHE=grpc://bazel-cache.nix-cache.svc.cluster.local:9092 \
BAZEL_REMOTE_EXECUTOR=grpc://gf-reapi-cell.gf-rbe.svc.cluster.local:8980 \
scripts/bazel-cache-backed.sh build //app:build

The proof wrapper should be used when the result will be cited as evidence. The cache-backed wrapper should be used when exercising an already eligible target class through the repo-managed operational path.

For timing comparisons, use Bazel Benchmarking. It keeps cold-local, shared-cache-backed, and executor-backed samples in separate JSON evidence instead of blending them into one product claim.

ARC Runner Wiring

ARC lanes do not become RBE lanes by existing. The runner module only passes an executor endpoint when the operator configures:

  • bazel_cache_endpoint
  • bazel_executor_endpoint
  • bazel_remote_execution_platform

When bazel_executor_endpoint is set, runner pods receive:

  • BAZEL_REMOTE_CACHE
  • BAZEL_REMOTE_EXECUTOR
  • GF_BAZEL_SUBSTRATE_MODE=executor-backed
  • GF_BAZEL_REMOTE_EXECUTION_PLATFORM

The module rejects executor-only wiring. bazel_executor_endpoint requires bazel_cache_endpoint so cache and executor authorities remain visible and separate.

Worker Image

The first proof worker is the digest-pinned gf-reapi-cell image. It includes the minimal runtime envelope needed by the proved actions:

  • /bin/sh
  • /usr/bin/env
  • Node 22
  • Python 3
  • glibc and the /lib64/ld-linux-x86-64.so.2 loader bridge
  • C++ runtime libraries needed by hermetic Linux tool inputs
  • common POSIX archive tools
  • Chromium for the bounded static-site Playwright candidate

The current Worker Toolchain Model is recorded in RBE Worker Toolchain Model. That contract keeps worker-image breadth separate from target-class eligibility: a runtime being present in the image is blocker-burn-down evidence, and the status remains not broad/default RBE. The proof cell still uses proof-local storage and must not be treated as a RustFS-backed CAS/action-cache authority.

Adding tools to the worker image is a product decision. A target should not be marked RBE-eligible just because it happens to pass on an over-broad worker image. The target class must declare its tool, input, network, and output requirements first.

Target Eligibility

Target-class promotion is controlled by RBE Target Eligibility.

Currently proved:

  • //:deployment_bundle
  • //:public_vendor_handoff_fixture
  • //docs-site:build
  • //app:build
  • //app:unit_tests
  • tinyland-inc/omux.xoxd.ai //:unit_tests
  • tinyland-inc/omux.xoxd.ai //:build
  • //examples/hello-go:hello_test
  • //examples/hello-go-cgo:cgo_test
  • //examples/hello-rust:hello_test
  • //examples/hello-cc:hello_test
  • //docs-site:playwright_chromium_smoke
  • tinyland-inc/omux.xoxd.ai //:puppeteer_chromium_smoke
  • tinyland-inc/omux.xoxd.ai //:playwright_chromium_smoke
  • tinyland-inc/omux.xoxd.ai //:playwright_local_route_smoke
  • tinyland-inc/omux.xoxd.ai //:puppeteer_local_route_smoke
  • Jesssullivan/jesssullivan.github.io //:puppeteer_chromium_smoke
  • Jesssullivan/jesssullivan.github.io //:playwright_chromium_smoke
  • Jesssullivan/jesssullivan.github.io //:sveltekit_vite_build_smoke
  • Jesssullivan/jesssullivan.github.io //:types_unit_tests
  • tinyland-inc/tinyland.dev //packages/tinyland-grafana:test
  • tinyland-inc/tinyland.dev //:app_typecheck
  • tinyland-inc/tinyland.dev //:app_build
  • tinyland-inc/tinyland.dev //packages/tinyland-activitypub:test
  • tinyland-inc/tinyland.dev //packages/tinyland-a11y-engine:typecheck
  • Jesssullivan/MassageIthaca //:sveltekit_node_build

Run 25608601158 promoted //docs-site:build after a forced default-branch proof with 1046 remote processes and remote docs-site/.svelte-kit / docs-site/build action evidence. Run 25634296833 promoted //examples/hello-go:hello_test after a forced default-branch proof with 11 remote processes and remote GoStdlib, compile, link, and test-setup evidence. Run 25649628233 promoted the trivial cgo-backed Go class with 11 remote processes and remote runtime/cgo, GoCompilePkg, GoLink, and test-setup evidence. Runs 25648670844 and 25648975728 promoted the trivial Rust and C++ unit-test classes with 5 remote and 4 remote processes. Run 25712694947 promoted //docs-site:playwright_chromium_smoke after a forced bazel_command=test proof with 1060 remote processes, remote sveltekit_sync, remote vite_build, remote test-setup, and a passing playwright-core smoke with /bin/chromium. Run 25826953857 promoted tinyland-inc/omux.xoxd.ai //:puppeteer_chromium_smoke after a forced bazel_command=test proof with 137 remote processes, remote sveltekit_sync, remote vite_build, remote test-setup, and a passing puppeteer-core smoke with /bin/chromium. Run 25742782051 promoted tinyland-inc/omux.xoxd.ai //:unit_tests after a forced bazel_command=test proof with 4 remote processes and remote test-setup.sh unit_tests_/unit_tests run --reporter=verbose --config ./vitest.config.ts evidence. Run 25891956165 promoted tinyland-inc/omux.xoxd.ai //:build after a forced bazel_command=build proof with non-secret GF_RBE_PROOF_NONCE action-key perturbation, 4 remote processes, remote @tailwindcss/oxide and esbuild lifecycle-hook actions, remote sveltekit_sync, and remote vite_build evidence. Run 25897326537 promoted tinyland-inc/omux.xoxd.ai //:playwright_chromium_smoke after a forced bazel_command=test proof from public main commit d3608a5a6325adee0a5e625cf7ad76b470e7b83f with proof nonce 20260515T024138Z-25897326537-1, 6 remote processes, remote @tailwindcss/oxide and esbuild lifecycle hooks, remote sveltekit_sync, remote vite_build, remote test-setup.sh playwright_chromium_smoke_/playwright_chromium_smoke, remote generate-xml.sh, and a passing Playwright Chromium static-output smoke with /bin/chromium. Run 26037732121 promoted tinyland-inc/omux.xoxd.ai //:puppeteer_local_route_smoke after a forced bazel_command=test proof from public main commit 50e0b796cbc44bc82de67891b1999e7e48cff473 with GitHub App checkout authority, proof nonce 20260518T135044Z-26037732121-1, 10 remote processes, remote @tailwindcss/oxide and esbuild lifecycle hooks, remote sveltekit_sync, remote vite_build, remote test-setup.sh puppeteer_local_route_smoke_/puppeteer_local_route_smoke, remote generate-xml.sh, and a passing Puppeteer local route smoke with /bin/chromium. Runs 25777472760 and 25779597385 promoted the public Jesssullivan/jesssullivan.github.io //:puppeteer_chromium_smoke and //:sveltekit_vite_build_smoke target classes after forced bazel_command=test proofs with 855 remote processes each. The Puppeteer proof shows remote lifecycle-hook execution without browser download and remote test-setup; the SvelteKit/Vite build-smoke proof shows remote npm package extraction/lifecycle actions and remote test-setup. Run 25894297074 promoted the public Jesssullivan/jesssullivan.github.io //:playwright_chromium_smoke target class after a forced bazel_command=test proof with proof nonce 20260515T005745Z-25894297074-1, 855 remote processes, remote lifecycle-hook execution without browser download, remote test-setup.sh playwright_chromium_smoke_/playwright_chromium_smoke, remote generate-xml.sh, and a passing Playwright Chromium runtime smoke with /bin/chromium. Run 25892939448 promoted Jesssullivan/jesssullivan.github.io //:types_unit_tests after a forced bazel_command=test proof with proof nonce 20260515T001050Z-25892939448-1, 855 remote processes, remote esbuild, sharp, and puppeteer lifecycle-hook actions without action-time browser downloads, and remote test-setup.sh types_unit_tests_/types_unit_tests with exit_code=0. Run 25953478878 promoted Jesssullivan/MassageIthaca //:playwright_tmd_smoke after a forced bazel_command=test proof with repo-scoped deploy-key checkout, consumer commit 08555e16b9ee0504b1b23e6373b5b6bbfb799f5f, proof nonce 20260516T050753Z-25953478878-1, 3318 remote processes, remote sveltekit_sync_bin_/sveltekit_sync_bin, remote vite_build_bin_/vite_build_bin, remote test-setup.sh playwright_tmd_smoke_/playwright_tmd_smoke, remote generate-xml.sh, and a passing Playwright TMD smoke with /bin/chromium. Run 25970619559 promoted tinyland-inc/tinyland.dev //:app_typecheck after a forced bazel_command=build proof with GitHub App checkout authority, the verified private tummycrypt_tinyland_schemas:0.2.4 distdir handoff, proof nonce 20260516T191944Z-25970619559-1, 5578 processes: 1 action cache hit, 2567 remote cache hit, 2955 internal, 56 remote, remote TypeScript tsc, remote Svelte build tool, remote Vite build tool, remote app_typecheck_tool, artifact verifier success, and Kubernetes restart evidence that stayed at 0. Run 25978934708 promoted tinyland-inc/tinyland.dev //:app_build after a forced bazel_command=build proof with GitHub App checkout authority, the verified private tummycrypt_tinyland_schemas:0.2.4 distdir handoff, proof nonce 20260517T021820Z-25978934708-1, 6146 processes: 3125 remote cache hit, 2959 internal, 62 remote, remote TypeScript package fanout, remote JsRunBinary app_build.log, artifact verifier success, and Kubernetes restart evidence that stayed at 0. Run 25981546207 promoted tinyland-inc/tinyland.dev //packages/tinyland-activitypub:test after a forced bazel_command=test proof with GitHub App checkout authority, workspace_path=consumer-workspace, the verified private tummycrypt_tinyland_schemas:0.2.4 distdir handoff, proof nonce 20260517T044208Z-25981546207-1, 728 processes: 1 action cache hit, 299 remote cache hit, 415 internal, 14 remote, remote esbuild lifecycle-hook execution, remote TypeScript tsc for packages/tinyland-content-types, remote test-setup.sh packages/tinyland-activitypub/test_/test, remote generate-xml.sh, artifact verifier success, and Kubernetes restart evidence that stayed at 0. Run 25984827370 promoted tinyland-inc/tinyland.dev //packages/tinyland-a11y-engine:typecheck after a forced bazel_command=build proof with GitHub App checkout authority, workspace_path=consumer-workspace, the verified private tummycrypt_tinyland_schemas:0.2.4 distdir handoff, proof nonce 20260517T073751Z-25984827370-1, consumer checkout commit 3730c6966d5e069cff92abc7c606fca9db5b54af, 553 processes: 223 remote cache hit, 328 internal, 2 remote, remote esbuild lifecycle-hook execution, remote TypeScript tsc for packages/tinyland-color-utils, artifact verifier success, and Kubernetes restart evidence that stayed at 0. Run 25983800544 promoted Jesssullivan/MassageIthaca //:sveltekit_node_build after a forced bazel_command=build proof with repo-scoped deploy-key checkout authority, consumer commit e06a70d12417f04568092a62e225b6c6595c3b39, proof nonce 20260517T064447Z-25983800544-1, 7379 processes: 2 action cache hit, 4186 internal, 3193 remote, remote lifecycle-hook execution for esbuild, msw, and sharp, remote sveltekit_sync_bin_/sveltekit_sync_bin, remote vite_build_bin_/vite_build_bin, artifact verifier success, and Kubernetes restart evidence that stayed at 0.

Those scopes are static docs-site rendering, one in-repo Chromium static-site Playwright smoke, one public omux Chromium Playwright static-output smoke, two public consumer Chromium static-output Puppeteer smokes, one public consumer Chromium Playwright runtime smoke, one public consumer SvelteKit/Vite build smoke, one public consumer SvelteKit/Vite standalone build class, two public consumer Vite/SvelteKit Vitest unit-test classes, one private tinyland.dev root app typecheck class, one private tinyland.dev root Vite/SvelteKit production-build class, two private tinyland.dev package Vitest classes, one private MassageIthaca SvelteKit/Vite production-build class, and one trivial unit-test class each for pure-Go, cgo-backed Go, Rust, and C++. They do not prove docs deployment/publication, broader Vitest, broader Playwright/Puppeteer/E2E, broader Vite/SvelteKit build/typecheck RBE, broader language-class RBE, durable private mirror/repository-cache authority, or broad/default RBE.

Current blocked classes include OpenTofu validation/formatting, image publication, interactive devserver targets, broader cgo-backed Go, and broader Rust or C++ target classes. Run 25638930305 remains negative C++ evidence: the first forced C++ proof reached the remote compile action and failed because the worker lacked the referenced Nix gcc-wrapper path. Run 25632300253 remains negative cgo-backed Go evidence before that closure was present. Remote cache hits, GitHub job placement, and ARC runner dispatch are useful substrate evidence, but they are not RBE evidence.

Storage And State Boundaries

Do not use current RustFS as RBE CAS/action-cache authority. RustFS is guarded interim infrastructure for existing cache/state checks and still carries bucket-index reliability debt. A green RustFS canary means the current state path is coherent now; it does not promote RustFS to durable RBE storage.

Do not use OpenTofu state buckets, Attic buckets, or Bazel cache buckets as RBE CAS/action-cache storage. Future CAS/action-cache authority needs its own retention, repair, auth, and observability contract.

Troubleshooting

If a proof run reports only remote cache hits, rerun with:

GF_RBE_PROOF_FORCE_EXECUTION=true

That passes --remote_accept_cached=false, adds --nocache_test_results for test proofs, injects a non-secret GF_RBE_PROOF_NONCE action environment value to perturb action keys for cache-warm target classes, and rejects cache-hit-only evidence.

If the wrapper refuses executor-backed mode, check:

  • BAZEL_REMOTE_EXECUTOR is set and has a real endpoint URL
  • BAZEL_REMOTE_CACHE is also set
  • GF_BAZEL_SUBSTRATE_MODE=executor-backed
  • just cache-contract-strict passes

If a target is not eligible, do not work around the manifest. Add or update a target-class entry with blockers, proof requirements, and a cited proof plan.

If a worker action fails because a tool is missing, decide whether that tool is part of the platform contract. Do not silently expand the worker image and then claim the target was already eligible.

Validation Commands

Use these checks before citing or publishing RBE posture changes:

just rbe-boundary-check
just rbe-proof-contract-check
just rbe-target-eligibility-check
just rbe-worker-toolchain-model-contract-check
just arc-runner-executor-endpoint-contract-check
just gf-reapi-cell-proof-contract-check
just gf-reapi-cell-proof-artifact-contract-check

just check includes these guards in the bounded local validation cycle.

GloriousFlywheel