Skip to content

chore(graphql): refresh the schema snapshot + pin it against drift - #714

Merged
islandbitcoin merged 2 commits into
mainfrom
chore/schema-drift-only
Aug 28, 2026
Merged

chore(graphql): refresh the schema snapshot + pin it against drift#714
islandbitcoin merged 2 commits into
mainfrom
chore/schema-drift-only

Conversation

@islandbitcoin

Copy link
Copy Markdown
Contributor

Split out of #713. That PR carried this plus ENG-533's app half; the ENG-533 half needs a design change and shouldn't hold this back. This half is independently reviewed-clean.

The snapshot had drifted 224 lines

app/graphql/public-schema.graphql is a hand-copied snapshot of the server SDL, and codegen types the entire app against it. Nothing ever compared it to the real schema.

Drift does not fail graphql-check — that validates our operations against the snapshot, so a new server field is simply invisible. The app can't ask for something that exists, and the symptom reads as "the backend never shipped it." Among what was missing: the idempotencyKey inputs (flash#494) and the allowance payload's singlePaymentLimit / minimum (flash#487).

Refreshed from lnflash/flash main — generated by that repo's write-sdl and gated by its own check:sdl, so authoritative without a running server. Re-ran codegen. All operations still validate, and the snapshot is now byte-identical to the server SDL.

The drift check, and why the two triggers differ

  • schedule / manual — strict. Any difference is drift someone must look at, and nobody's PR is blocked meanwhile.
  • pull_request — only REMOVALS fail. A removal can invalidate an operation this app sends, so it's worth stopping a merge. Additions are the server shipping something new: no app PR caused them and none can fix them. Failing on those would turn every app/graphql PR red the first time flash merges anything — and a red X everyone knows to ignore is worse protection than no check at all.

A fetch failure and real drift are also reported differently, so a repo rename or a raw.githubusercontent 5xx doesn't land in someone's inbox looking like a schema alarm.

Verified the check fails on a perturbed snapshot, not merely that it passes on a matching one.


91 suites / 897 tests green, tsc clean, graphql-check clean.

app/graphql/public-schema.graphql is a hand-copied snapshot of the
server's SDL, and codegen types the entire app against it. Nothing
checked it against the real schema, so it drifted 224 lines behind --
including the idempotencyKey inputs the send path needs (flash#494) and
the allowance payload's singlePaymentLimit and minimum (flash#487).

Stale-snapshot drift does not fail graphql-check: that validates our
operations against the snapshot, so a missing server field is simply
invisible. The app cannot ask for something that exists, and the symptom
reads as "the backend never shipped it".

Refreshed from lnflash/flash main (generated by its write-sdl and gated
by its own check:sdl, so authoritative without a running server), then
re-ran codegen. All existing operations still validate.

Adds .github/workflows/schema-drift.yml. The two triggers deliberately
do not judge alike:

  * schedule/manual -- strict. Any difference is drift somebody must go
    look at, and nobody's PR is blocked while they do.
  * pull_request -- only REMOVALS fail. A removal can invalidate an
    operation this app sends. Additions are the server shipping
    something new, which no app PR caused and none can fix; failing on
    those turns every app/graphql PR red the first time flash merges
    anything, and a red X everyone knows to ignore is worse than no
    check.

A fetch failure and real drift are also reported differently, so a repo
rename or a raw.githubusercontent 5xx does not land in someone's inbox
looking like a schema alarm.

Verified the check fails on a perturbed snapshot, not merely that it
passes on a matching one.

Split out of #713, which carried this plus ENG-533's app half. That half
needs a design change (client and server fingerprint different things)
and should not hold this back.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEoz7nBtdtsHyuYG5wNPQV
…n owner

Three review findings on the drift workflow:

1. The removal check was a textual grep over the unified diff, so any
   CHANGED line read as a removal -- a docstring rewording server-side
   would fail every app PR touching app/graphql as if an
   operation-breaking removal had happened, which is the cry-wolf
   failure the workflow's own comments argue against. Now judged by
   graphql-inspector (already a repo dependency, it backs
   graphql-check): exit codes verified empirically -- identical 0,
   additions 0, docstring rewording 0, field removal 1. The textual
   diff is kept for display only.

2. The strict weekly run's only output was a red run in the Actions
   tab, which GitHub shows to the workflow file's last committer and
   nobody else. The 224-line drift this workflow exists to catch sat
   unnoticed for exactly that reason. A strict failure now files (or
   updates) a tracking issue carrying the inspector output and the
   refresh instructions.

3. The remediation text never said to commit the regenerated
   generated.ts, so the next person's first attempt would bounce off
   check:codegen. It says so now.

All five decision paths simulated locally: identical passes, addition
warns on a PR and fails the schedule, removal fails both, docstring
edit passes a PR.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NEoz7nBtdtsHyuYG5wNPQV
@islandbitcoin
islandbitcoin merged commit c81c7c1 into main Aug 28, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant