Skip to content

Add two-layer GraphQL schema drift checker#6

Merged
dkijania merged 1 commit into
fix/account-with-token-query-typefrom
feat/two-layer-drift-check
May 27, 2026
Merged

Add two-layer GraphQL schema drift checker#6
dkijania merged 1 commit into
fix/account-with-token-query-typefrom
feat/two-layer-drift-check

Conversation

@dkijania

Copy link
Copy Markdown
Collaborator

Stacked on #5 — review/merge that one first; rebase this on `main` afterward.

Summary

The JS SDK previously had no schema-drift detection. This adds parity with the Go / Python / Rust SDKs:

  1. Introspection diff (Layer 1): compare `schema/graphql_schema.json` (new snapshot from devnet) to the live `__schema`. Detects added / removed types, field-type changes, argument-type changes (e.g. `UInt64 → TokenId` — the exact bug fixed in Fix QUERY_ACCOUNT_WITH_TOKEN: token arg type is TokenId, not UInt64 #5), inputField-type changes, enum-value changes.
  2. Live query check (Layer 2): parse `src/queries.ts`, send each operation with sentinel variables, classify errors as schema drift vs runtime. Drift patterns matched against the message before the path-based runtime fallback (Mina attaches `path` to many validation errors). Bare `"expected type"` deliberately excluded — too many FPs on value coercion; `"expected on field X, found Y"` routed to runtime explicitly.

Design choices

  • `AbortController` with 30 s timeout on every `fetch`
  • HTTP status check (non-2xx → error with body snippet)
  • `normalizeSchema` throws on error envelopes (no silent fake-empty)
  • `nameOf` sort key safe against `null` / non-object entries
  • `kind` nil-guard avoids spurious ` -> X` diffs
  • `parseQueries` filters to bodies that start with an operation keyword
  • `parseVariableDecls` anchored to body start
  • Sentinel table supports `SignatureInput` (legitimate `null`) via a `NO_SENTINEL` symbol that distinguishes "no sentinel known" from "explicit null sentinel"
  • Connection / HTTP errors → infra failures bucket; always exit 1
  • `SKIP`ped ops (stale sentinel table) fail in `--strict`

CI

`.github/workflows/schema-drift.yml` mirrors the other SDKs: master / compatible / develop matrix against lightnet images; weekly cron + `workflow_dispatch` + PRs that touch `schema/` or the script. Exposes `npm run check:drift`.

Test plan

  • Clean run against `compatible-latest-lightnet` in `--strict`: exit 0, 13 ok, 0 drift, 4 runtime (QUERY_BLOCK / QUERY_TRANSACTION_STATUS hit application-level constraints; correctly classified as runtime), 0 skipped, 0 infra-failures.
  • Same negative cases as the Go / Python / Rust PRs (arg-type drift, inputField-type drift, unknown-field, unknown input type, unreachable port) all behave as expected.

🤖 Generated with Claude Code

The SDK previously had no drift detection — schema changes could ship
that subtly broke queries. This adds parity with the Go / Python /
Rust SDKs:

1. Introspection diff (Layer 1): compare schema/graphql_schema.json
   (new snapshot from devnet) to the live __schema. Detects added /
   removed types, field-type changes, argument-type changes (e.g.
   UInt64 -> TokenId), inputField-type changes, enum-value changes.

2. Live query check (Layer 2): parse src/queries.ts, send each
   operation with sentinel variables, classify errors as schema drift
   vs runtime (auth, value-validation). Drift patterns matched against
   the message before the path-based runtime fallback; bare "expected
   type" deliberately excluded (false-positives on value coercion);
   "expected on field X, found Y" routed to runtime explicitly.

Other design choices:
- AbortController with 30s timeout on every fetch
- HTTP status check (non-2xx -> error with body snippet)
- normalizeSchema throws on error envelopes (no silent fake-empty)
- nameOf sort key safe against null / non-object entries
- kind nil-guard avoids spurious "<undefined> -> X" diffs
- parseQueries filters to bodies that start with an operation keyword
- parseVariableDecls anchored to body start
- Sentinel table supports SignatureInput (legitimate `null` value)
  via a NO_SENTINEL marker that lets us distinguish "no sentinel
  known" from "explicit null sentinel"
- Connection / HTTP errors counted as infra failures, not "drift";
  always exits 1
- SKIPped ops (stale sentinel table) fail in --strict

Adds .github/workflows/schema-drift.yml mirroring the other SDKs:
master / compatible / develop matrix against lightnet images; weekly
cron + workflow_dispatch + PRs that touch schema/ or the script.
Exposes `npm run check:drift`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dkijania dkijania merged commit fb30ba5 into fix/account-with-token-query-type May 27, 2026
3 checks passed
@dkijania dkijania deleted the feat/two-layer-drift-check branch May 27, 2026 11:46
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