Metagraphed Backend Operations#
Source Of Truth#
GitHub-reviewed registry source, compact generated indexes, and compact release manifests are canonical for v1. High-churn generated detail is staged under dist/metagraph-r2/metagraph and published to R2; Cloudflare serves and stores artifacts, but it does not become the registry truth source.
Routine Validation#
npm run pipeline:check
This performs dry-run sync/discovery/verification, contract validation, Worker runtime checks, workflow validation, public-safety scanning, and tests.
The contract checks include schema bundle drift, schema/query enum parity, OpenAPI example validation, generated TypeScript freshness, and generated client freshness.
Operator Briefs#
Contributor curation:
npm run curation:brief
Endpoint operations:
npm run endpoint:brief
The endpoint brief summarizes monitored resources, root RPC/WSS/archive advisory pools, provider scores, incidents, and the disabled proxy contract from existing artifacts. Health, latency, latest block, incidents, and pool eligibility remain probe-derived only.
Refreshing Artifacts#
npm run pipeline:refresh
This updates native subnet data, candidates, verification, baseline curation, adapter snapshots, generated artifacts, schema snapshots, R2 manifest, and validation outputs.
The refresh keeps Git reviewable: compact artifacts remain in public/metagraph, while per-subnet candidates, verification details, health detail/history, adapter snapshots, schema snapshots, and provider detail outputs are staged for R2 and should not be committed.
Candidate discovery reads public enrichment sources such as TaoMarketCap,
Backprop Finance dashboard routes, Taostats metagraph dashboard routes,
Tensorplex subnet-docs, and Taopedia articles. Set GITHUB_TOKEN or
GH_TOKEN for authenticated read-only GitHub API requests during local
refreshes; scheduled sync and publish workflows already pass GITHUB_TOKEN
from GitHub Actions.
Discovery also probes every known base origin (discovered project websites
plus existing subnet-api/docs surfaces) for an OpenAPI/Swagger spec at
conventional paths, registering an openapi candidate only on a validated
document. These are read-only GETs with a per-request timeout, a 2 MiB body
cap, and the private-IP/unsafe-URL block, run at concurrency 8 and
short-circuiting on the first hit per origin — so each refresh makes live
requests to all known origins.
Live health probes are only written when explicitly enabled:
METAGRAPH_WRITE_PROBE_RESULTS=1 npm run pipeline:refresh
Cloudflare Publish#
The Publish Cloudflare Backend workflow is fail-closed for main pushes:
CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID must be configured as
GitHub Actions secrets or the publish run fails before any upload/deploy step.
Manual workflow_dispatch runs can choose publish_mode=dry-run for
validation-only checks; dry-run mode must not upload to R2, publish KV, deploy
the Worker, or claim a production publish.
Before publishing:
npm run cloudflare:verify:dry-run
npm run r2:upload:dry-run
npm run kv:publish:dry-run
npm run worker:deploy:dry-run
Actual writes require explicit environment gates:
METAGRAPH_ALLOW_R2_UPLOAD=1METAGRAPH_R2_UPLOAD_HISTORY=1when the publish job should also write run-prefix history copies for all planned artifacts and control files.METAGRAPH_R2_UPLOAD_FORCE=1when a publish job should ignore the remotelatest/r2-manifest.jsoncomparison and republish every planned artifact.METAGRAPH_R2_UPLOAD_LIMITfor smoke-only uploads against a small artifact subset. Limited smoke uploads skip control files solatest/r2-manifest.jsoncontinues to describe only a complete latest artifact set.METAGRAPH_ALLOW_KV_WRITE=1METAGRAPH_KV_NAMESPACE_ID- Cloudflare account/API credentials
Normal R2 publishes are delta-based. The uploader reads latest/r2-manifest.json, compares artifact SHA-256 values, reads R2-tier files from the staging tree, skips unchanged artifact files, and refreshes latest/r2-manifest.json plus latest/build-summary.json on full uploads so Worker fallback and operator summaries stay current.
After the Worker is deployed, run the live smoke gate:
npm run smoke:live
The live smoke checks metagraph.sh API envelopes, Worker-mediated raw artifact routes, CORS/cache headers, R2-backed detail routes, invalid-query errors, and verifies the v1 RPC proxy still returns rpc_proxy_disabled.
Restore From R2#
Dry-run:
npm run r2:download:dry-run
Write mode verifies downloaded SHA-256 hashes against public/metagraph/r2-manifest.json.
METAGRAPH_ALLOW_R2_DOWNLOAD=1 npm run r2:download
Health & Freshness Monitoring#
GET /health is the readiness + freshness probe (no auth, lightweight, edge-cached
60s). It reports binding wiring and the age of the published data:
{
"status": "ok",
"bindings": { "assets": true, "r2": true, "kv": true },
"freshness": {
"published_at": "…",
"age_hours": 1.2,
"max_age_hours": 48,
"stale": false
}
}
published_atcomes from the KVmetagraph:latestpointer, which the
event-driven data publish (ADR 0007) advances on each human-input registry merge
and at least once daily (the 07:17 UTC floor).- When the data is older than
max_age_hours(default 48 — two missed daily floors;
override withMETAGRAPH_HEALTH_MAX_AGE_HOURS),statusbecomesdegradedand the
route returns HTTP 503. Point an uptime monitor athttps://api.metagraph.sh/health
so a silently-broken data-refresh pages instead of serving stale data unnoticed. - A present-but-stale pointer trips it; a missing pointer (local/dev) stays
ok.
Adapter Data-Quality Guard#
npm run validate:adapters rejects an adapter snapshot that degraded to broken
GitHub auth / all-HTML-fallback (Finding 1). It warns in ordinary PR validation
and fails (exit 1) when METAGRAPH_PRODUCTION_BUILD=1 or
METAGRAPH_REQUIRE_ADAPTER_AUTH=1 — so the scheduled publish and sync-subnets runs
refuse to ship degraded adapter data after a token break.
RPC Proxy (enabled)#
The read-only Subtensor RPC proxy (POST /rpc/v1/finney, /rpc/v1/finney/wss) is
ENABLED (METAGRAPH_ENABLE_RPC_PROXY: "true" in wrangler.jsonc) and live —
verified in production: system_health / chain_getHeader return 200 with a
valid JSON-RPC result, and a denied method (author_submitExtrinsic) returns
rpc_method_blocked. To disable in an incident, set the flag to "false" and
redeploy (or use an env override).
Enforced in the Worker:
- Method allowlist — read-only
SAFE_RPC_METHODSonly;DENIED_RPC_PREFIXES
(author_,state_call,sudo_,payment_,contracts_) and heavy reads
(state_getMetadata) stay blocked. - State-query methods (#4344/9.2) —
state_getStorage/state_getKeysPagedare
allowed through a second, narrowerSAFE_RPC_STATE_QUERY_METHODSallowlist (still
denyingstate_getPairs, which has no caller-side pagination). Each call is
param-validated (hex key/prefix format + length cap), thestate_getKeysPaged
page-size is clamped (not rejected) toMAX_STATE_QUERY_KEYS_PAGE_SIZE, and the
decoded upstream response is capped atMAX_STATE_QUERY_RESPONSE_BYTES(256 KB).
Metered by their ownSTATE_QUERY_RATE_LIMITERbudget (20 req/60s per client IP,
429 rpc_state_query_rate_limited), on top of the general RPC rate limit below. - Upstream SSRF guard — only
TRUSTED_RPC_UPSTREAM_ORIGINS, https/wss, no private IPs. - Load balancing — weighted-random across all eligible+safe pool endpoints.
- Body cap 64 KB, upstream timeout 10 s, single JSON-RPC object only.
- Rate limit — the
RPC_RATE_LIMITERbinding: 100 requests / 60 s per client IP
(returns429 rpc_rate_limited). Enforced on Cloudflare; skipped locally.
Enablement prerequisites (satisfied — kept here for re-enable / audit):
- Cloudflare WAF (dashboard). Zone rules scoped to
http.request.uri.path contains "/rpc/": a Rate Limiting rule (coarse pre-Worker
cap to absorb distributed abuse), a custom rule blocking non-POST/ oversized
bodies, and the zone's Managed Ruleset / Bot Fight Mode. The Worker's own
RPC_RATE_LIMITER(100 req/60s per IP) is defense-in-depth beneath the WAF. - Pool eligibility.
curl https://api.metagraph.sh/api/v1/rpc/pools— at least one
endpoint per pool must be"pool_eligible": true(else503 rpc_endpoint_unavailable).
Currently: finney-rpc 4/5, finney-wss 4/4, finney-archive 8/8 eligible. - Flag.
METAGRAPH_ENABLE_RPC_PROXY: "true"inwrangler.jsonc(deploys via Workers Builds). - Smoke (re-run after any change):
POST /rpc/v1/finneysystem_health→200;
author_submitExtrinsic→403 rpc_method_blocked; a burst past 100/60s →429.
Rollback#
Rollback is pointer-first:
- point KV
metagraph:latestat a known-good R2 run prefix; - verify
/api/v1/build,/api/v1/contracts,/api/v1/health,/api/v1/endpoint-pools, and/api/v1/rpc/pools; - disable
METAGRAPH_ENABLE_RPC_PROXYimmediately if proxy behavior is suspect.
Known Non-Blocking Drift#
sync:subnets:dry-run can report chain metadata changes, such as subnet names. These should become reviewed sync PRs, not silent direct pushes.