Skip to content

Nothing verifies the committed graph-node API schema snapshot; deploy to a throwaway graph-node in CI and diff #2852

Description

@thedavidmeister

crates/subgraph/schema/raindex.graphql is a graph-node API schema snapshot — it opens with graph-node's own directive definitions (@entity, @subgraphId), so it is the generated API schema, not a hand-written entity schema. Nothing in this repo produces it and nothing verifies it. It is hand-maintained.

crates/subgraph/build.rs registers it as truth:

cynic_codegen::register_schema("raindex")
    .from_sdl_file("schema/raindex.graphql")

So the generated client compiles against whatever that file says, right or wrong. A field that drifted, or one graph-node generates that the snapshot omits, is invisible at compile time and only surfaces when a query hits a real endpoint.

This is not hypothetical

rainlanguage/rain.metadata#297 is the same defect on the same kind of file, and the check built for it (rainlanguage/rain.metadata#298) found the committed snapshot was wrong on its first run — 292 lines missing: an entire Transaction_filter and Transaction_orderBy, every transaction* entry in the neighbouring filter and orderBy inputs, transaction/transactions on Query and Subscription, _Block_.parentHash, Timestamp, Aggregation_interval, and graph-node's directive definitions.

Raindex's schema is considerably larger than the metaboard's and is consumed by the app rather than only by tooling, so there is more surface to drift and more code compiled against it.

What to build

A CI job that deploys the subgraph to a throwaway graph-node, introspects it, and fails if the result differs from the committed snapshot.

rain.metadata#298 is the working reference. Its shape: anvil on the runner host, postgres + ipfs + graph-node in a compose file separate from any existing one that runs --abort-on-container-exit, deploy, introspect, print SDL through lexicographicSortSchema + printSchema, diff -u against the committed file, upload the derived file as an artifact.

Two findings from that PR worth carrying over rather than rediscovering:

  • Pin graphql as a direct dependency. graph-cli pins graphql at exactly 15.5.0; its own dep @float-capital/float-subgraph-uncrashable wants ^16.6.0. Whichever npm hoists is what require("graphql") returns, so npm's tie-break silently decides which printSchema writes the snapshot. For a byte comparison that is the whole assertion. A flip to 16.x reads as a schema change that never happened.
  • Give each introspection attempt a timeout. graph-node answers Subgraph … has not started syncing yet on the first attempt after deploy, so a retry loop is needed — but Node's fetch has no default timeout, and a graph-node that accepts the connection then stalls leaves the await pending forever, including inside response.json(). The retry loop never gets a turn and the job sits until the runner timeout with nothing in the log.

Adapt, do not copy

Record which parts of #298 needed changing for this repo. The intersection of the two is what gets upstreamed into a rainix reusable workflow, so that fixes reach every consumer on a RAINIX_SHA bump instead of being rediscovered per repo. Deriving that interface from one example is how rustfmt-conditional shipped a hook that assumed one repo layout and turned every virtual-workspace repo red.

Known likely difference: this repo has .github/workflows/deploy-subgraph.yaml and may keep a networks.json in tree, in which case #298's temp-tree-with-a-throwaway-networks.json step is unnecessary here. #298 needed it because rain.metadata's manifest is source-only and graph build --network writes address/startBlock back into it.

Prove it fails

Show the job red against a mutated snapshot, not only green against a correct one. A check that passes on bad input is the same as no check.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions