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:buildhas a forced REAPI proof through the GF-owned proof cell.//app:unit_testshas a forced remote-test proof through the same lane.tinyland-inc/omux.xoxd.ai //:unit_testshas a forced public consumer Vite/SvelteKit Vitest unit-test proof.tinyland-inc/omux.xoxd.ai //:buildhas a forced public consumer SvelteKit/Vite standalone build proof.//:deployment_bundlehas a forced packaging proof over declared k8s and Nix inputs.//docs-site:buildhas a forced static docs-site rendering proof.//:public_vendor_handoff_fixturehas a forced public-input consumer proof using a checked-out WAS-110 workspace and verified injected repository input.//examples/hello-go:hello_testhas a forced pure-Go remote-test proof for one trivialrules_gounit-test class.//examples/hello-go-cgo:cgo_testhas a forced cgo-backed Go remote-test proof for one trivialrules_go+ C toolchain target class.//examples/hello-rust:hello_testand//examples/hello-cc:hello_testeach have a forced remote-test proof for one trivial target class.//docs-site:playwright_chromium_smokehas a forced Chromium static-site Playwright smoke proof for one browser/web target class.tinyland-inc/omux.xoxd.ai //:puppeteer_chromium_smokehas a forced Chromium static-output Puppeteer smoke proof for one public consumer browser/web target class.tinyland-inc/omux.xoxd.ai //:playwright_chromium_smokehas a forced Chromium static-output Playwright smoke proof for one public consumer browser/web target class.tinyland-inc/omux.xoxd.ai //:playwright_local_route_smokehas 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_smokehas a forced Chromium local-server Puppeteer route-smoke proof for one public consumer browser/web target class.Jesssullivan/jesssullivan.github.io //:puppeteer_chromium_smokehas a forced Chromium static-output Puppeteer smoke proof for a second public consumer browser/web target class.Jesssullivan/jesssullivan.github.io //:playwright_chromium_smokehas a forced Chromium Playwright runtime-smoke proof for one public consumer browser/web target class.Jesssullivan/jesssullivan.github.io //:sveltekit_vite_build_smokehas a forced SvelteKit/Vite build-smoke proof for one public consumer web build target class.Jesssullivan/jesssullivan.github.io //:types_unit_testshas a forced SvelteKit/Vite/Vitest proof for one public consumer unit-test target class.tinyland-inc/tinyland.dev //packages/tinyland-grafana:testhas a forced private consumer package Vitest proof using private checkout authority and verified private distdir staging.tinyland-inc/tinyland.dev //:app_typecheckhas a forced private consumer root SvelteKit app typecheck proof using GitHub App checkout authority and verified private distdir staging.tinyland-inc/tinyland.dev //:app_buildhas 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:testhas 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:typecheckhas a forced private consumer package TypeScript typecheck proof using the same GitHub App checkout authority and verified private distdir staging.Jesssullivan/MassageIthaca //:sveltekit_node_buildhas a forced private consumer SvelteKit/Vite production-build proof using repo-scoped deploy-key checkout authority.scripts/bazel-cache-backed.shcan run inexecutor-backedmode when bothBAZEL_REMOTE_CACHEandBAZEL_REMOTE_EXECUTORare set explicitly.- ARC runner modules can inject
BAZEL_REMOTE_EXECUTORonly whenbazel_executor_endpointis 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
.bazelrcexecutor 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_teststarget 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:testand//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//:buildtarget class, the privatetinyland-inc/tinyland.dev //:app_buildclass, and the privateJesssullivan/MassageIthaca //:sveltekit_node_buildclass - 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_endpointbazel_executor_endpointbazel_remote_execution_platform
When bazel_executor_endpoint is set, runner pods receive:
BAZEL_REMOTE_CACHEBAZEL_REMOTE_EXECUTORGF_BAZEL_SUBSTRATE_MODE=executor-backedGF_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.2loader 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_teststinyland-inc/omux.xoxd.ai //:unit_teststinyland-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_smoketinyland-inc/omux.xoxd.ai //:puppeteer_chromium_smoketinyland-inc/omux.xoxd.ai //:playwright_chromium_smoketinyland-inc/omux.xoxd.ai //:playwright_local_route_smoketinyland-inc/omux.xoxd.ai //:puppeteer_local_route_smokeJesssullivan/jesssullivan.github.io //:puppeteer_chromium_smokeJesssullivan/jesssullivan.github.io //:playwright_chromium_smokeJesssullivan/jesssullivan.github.io //:sveltekit_vite_build_smokeJesssullivan/jesssullivan.github.io //:types_unit_teststinyland-inc/tinyland.dev //packages/tinyland-grafana:testtinyland-inc/tinyland.dev //:app_typechecktinyland-inc/tinyland.dev //:app_buildtinyland-inc/tinyland.dev //packages/tinyland-activitypub:testtinyland-inc/tinyland.dev //packages/tinyland-a11y-engine:typecheckJesssullivan/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_EXECUTORis set and has a real endpoint URLBAZEL_REMOTE_CACHEis also setGF_BAZEL_SUBSTRATE_MODE=executor-backedjust cache-contract-strictpasses
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.