Drift check: harden classifier and add coverage/infra-failure buckets#27
Merged
dkijania merged 1 commit intoMay 27, 2026
Conversation
Two-layer schema-drift checker for the SDK: 1. Introspection diff: compare src/mina_sdk/schema/graphql_schema.json to the live __schema; now also detects argument-type changes (e.g. UInt64 -> TokenId) and inputField-type changes that the previous version silently passed. 2. Live query check: parse src/mina_sdk/daemon/queries.py, send each operation with sentinel variables, classify GraphQL errors as either schema drift (parse/validation) or runtime (auth, value- validation). Drift patterns are matched against the message BEFORE the path-based runtime fallback - Mina attaches `path` to many validation errors, so a path-first short-circuit silently drops real drift to the runtime bucket. Bare "expected type" was removed from drift patterns (false-positives on value coercion); a regex for the "expected on field X, found Y" shape now routes those to runtime explicitly. Hardening from internal review: - httpx.Client with 30s timeout (was bare httpx.post call per request) - HTTP status check (non-2xx -> error; was relying on raise_for_status in one path and silently treating empty errors[] as OK in another) - normalize_schema raises on error envelopes - no silent fake-empty schema that then flags every type as REMOVED - _name_of sort key safe against null / non-dict entries - kind nil-guard avoids spurious "<None> -> X" diffs - _OP_RE filters to bodies that actually start with an operation keyword, so unrelated triple-quoted constants don't get probed - _VARS_RE anchored to body start, so inner field-arg parens like `bestChain(maxLength: 1)` can't bind - Connection / HTTP errors counted as infra failures, not "drift"; always exits 1 (we can't trust the result either way) - SKIPped ops (stale sentinel table) fail in --strict Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #26 — review/merge that one first; rebase this on master afterward.
Summary
Two-layer schema-drift checker:
UInt64 → TokenId) and inputField-type changes that the previous version silently passed. The exact bug fixed in Fix GET_ACCOUNT_WITH_TOKEN type + refresh schema snapshot #26 is the kind of drift this layer is supposed to catch.src/mina_sdk/daemon/queries.py, sends each operation with sentinel variables, classifies GraphQL errors. Drift patterns are matched against the message before the path-based runtime fallback (Mina attachespathto many validation errors, so the previous path-first short-circuit dropped real drift to runtime). Bare"expected type"was removed from drift patterns (false-positives on value coercion); a regex for the"expected on field X, found Y"shape routes those to runtime.Hardening (from internal review)
httpx.Clientwith 30 s timeouterrorskey)normalize_schemaraises on error envelopes — no silent fake-empty schema that flagged every type as REMOVED_name_ofsafe againstnull/ non-dict entries in introspection arrayskindnil-guard avoids spurious<None> -> Xdiffs_OP_REfilters to bodies that actually start withquery|mutation|subscription, so unrelated triple-quoted constants don't get probed_VARS_REanchored to body start so inner field-arg parens likebestChain(maxLength: 1)can't bind--strictTest plan
compatible-latest-lightnetin--strict: exit 0, 11 ok, 0 drift, 2 runtime, 0 skipped, 0 infra-failures.🤖 Generated with Claude Code