Skip to content

P2: Declare 1.0.0 + versioning & schema stability policy (#178) - #198

Merged
dkijania merged 4 commits into
mainfrom
chore/v1-and-schema-policy
Aug 25, 2026
Merged

P2: Declare 1.0.0 + versioning & schema stability policy (#178)#198
dkijania merged 4 commits into
mainfrom
chore/v1-and-schema-policy

Conversation

@dkijania

Copy link
Copy Markdown
Contributor

What & why

Part of the production-readiness epic (#163). Closes #178.

The package was pre-1.0 (0.0.6) with no documented stability guarantees — public consumers need them.

Changes

  • Bump to 1.0.0 in package.json.
  • docs/versioning.md — SemVer applied to the GraphQL schema / HTTP endpoints / config: a precise definition of breaking vs additive changes, a deprecation policy (@deprecated + one minor & 90 days before removal), and how the existing graphql-inspector "Check Schema" gate enforces it via the expected-breaking-change label.
  • Linked the policy from the README.

Important: this PR does not publish anything

The version bump is package.json-only — no git tag, so no release is cut. Publishing is tag-triggered (npm version + git push --follow-tags) and remains a deliberate maintainer action. Treat merging this PR as the decision to declare 1.0; if you're not ready for that, hold the PR (the policy doc stands on its own). Sequence it after the other production-readiness PRs so 1.0.0 ships with them.

Testing

Docs + version only. prettier --debug-check . clean; build sane. No code changed.

🤖 Generated with Claude Code

@dkijania dkijania added documentation Improvements or additions to documentation production-readiness Work toward making the API production-ready / publicly available P2 GA polish / hygiene labels Jun 29, 2026
@SanabriaRusso

Copy link
Copy Markdown
Collaborator

Thanks for pinning this down — a written stability contract is exactly what public consumers (the mina-explorer, o1js) need before 1.0, and the graphql-inspector "Check Schema" tie-in is a great enforcement hook.

One high-value addition: the policy defines what is breaking and how to deprecate, but doesn't codify the practice this repo already relies on to protect existing clients — shipping backward-incompatible query/response changes OFF by default behind an env flag. We already do this with ENABLE_BLOCK_TRANSACTION_DETAILS (src/server/server.ts, default off — gates block-detail / parentHash output) and ENABLED_QUERIES (src/resolvers.ts — allowlists exposed queries). That's what lets the Explorer survive changes: it fires fallback query chains and degrades on the exact "Cannot query field" validation error, so any change to default response shape or exposed fields must be opt-in, or it silently blanks Explorer pages. Codifying it makes it a rule rather than a convention:

### Flag-gating behavior changes
Changes that alter default response shape/content or exposed query surface ship disabled by default behind an environment flag (e.g. ENABLE_BLOCK_TRANSACTION_DETAILS, ENABLED_QUERIES). This keeps existing clients — notably the mina-explorer, which relies on stable default responses and "Cannot query field" fallbacks — working after upgrade. A flagged, default-off change is minor; flipping such a default (or removing the flag) to change out-of-the-box behavior is major.

Two small doc nits while you're in here:

  1. The endpoint list references /readiness and /metrics, which arrive via P1: Add readiness probe distinct from liveness (#169) #187 and P1: Expose Prometheus metrics at /metrics (#173) #191 — worth a note to reconcile at merge, since 1.0 ships after them.
  2. For output fields the breaking direction is non-null → nullable (nullable → non-null is safe); the current "nullable → non-null" wording is right for arguments/inputs but reversed for output fields. graphql-inspector classifies these correctly regardless, but since this doc's job is to define "breaking" precisely, the prose is worth matching.

dkijania added a commit that referenced this pull request Jul 17, 2026
Codifies the practice the repo already relies on but never wrote down:
changes to default response shape or exposed query surface ship
default-off behind an env flag (ENABLE_BLOCK_TRANSACTION_DETAILS,
ENABLED_QUERIES), flagged-off being minor and flipping the default major.
This is the rule the schema checker cannot enforce — an unflagged change
to a default response isn't schema-breaking, so nothing errors; the
mina-explorer just blanks pages while health checks stay green.

Also fixes the breaking-change direction for output fields. The doc said
"a nullable field/argument to non-null" is breaking, which holds for
arguments but is reversed for output fields: there the break is non-null
→ nullable (clients may now receive null), while nullable → non-null only
strengthens the guarantee. The two are mirror images — the client supplies
arguments and consumes fields — so the rules are now stated separately.

Addresses review feedback on #198.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkijania

Copy link
Copy Markdown
Contributor Author

Thanks @SanabriaRusso — both done in 30863c7.

Flag-gating policy. Added as its own section, close to your wording. I kept your reasoning about why rather than just the rule, because it's the part that makes it stick: the schema checker structurally cannot catch this. An unflagged change to a default response isn't schema-breaking — nothing errors, "Check Schema" stays green, health checks stay green, and the Explorer just blanks pages. A convention that only holds when someone remembers it is exactly the thing worth writing down.

Verified both cited flags exist as described before codifying them: ENABLE_BLOCK_TRANSACTION_DETAILS (src/server/server.ts:11) and ENABLED_QUERIES (src/resolvers.ts:61).

Nullability direction. Fixed, and split by position rather than patched, since the two are genuine mirror images:

  • Output fields: breaking is String!String — clients may now receive null. The reverse only strengthens the guarantee.
  • Arguments/inputs: breaking is StringString! — it rejects callers that legitimately omitted it. The reverse is safe.

The old single line was right for arguments and backwards for fields. Since this doc's whole job is to define "breaking" precisely, stating one rule and applying it to both positions was the bug.

On /readiness and /metrics — no change needed here: the merge plan puts this in wave 4, after #187 and #191, so they'll exist by the time 1.0 ships. Flagging that this doc and #197's runbook now both anchor on 1.0.0 as the version where those endpoints appear, so they agree.

@SanabriaRusso

Copy link
Copy Markdown
Collaborator

Verdict: MERGEABLE

Docs + a one-line version bump; no runtime code, no schema change (Check Schema / GraphQL Inspector both green at 30863c7). Nothing here can break mina-explorer or mina-explorer-api at runtime. The substance below is about what the policy promises and release hygiene, plus one mechanical prerequisite.

What I checked


Mechanical prerequisite (must be done before merge)

The PR is against a stale base — its package.json hunk is 0.0.6 → 1.0.0 while main is 0.0.9, so it will not merge as-is. When you rebase, also do the lockfile: the PR touches only README.md, docs/versioning.md, package.json, so post-merge package-lock.json would still read 0.0.9. I tested this — npm ci does not fail on a root-version mismatch, so it's hygiene rather than a break, but fix it in the same commit:

// package-lock.json — two places
  "version": "1.0.0",          // line 3 (top level)
      "version": "1.0.0",      // packages[""].version

Simplest is npm version 1.0.0 --no-git-tag-version on the rebased branch, which writes both files.

The 1.0.0 / registry mismatch is worth a note in the PR body

Three states diverge and the PR body's "merging this PR is the decision to declare 1.0" doesn't reconcile them:

value
git tags v0.0.1v0.0.9 (v0.0.9 at e353bbc)
npm registry 0.0.6 only — published by hand, per #208
GitHub releases latest is v0.0.8 (pre-release); no release for v0.0.9
this PR 1.0.0

Consequences worth calling out:

  1. npm publishing from CI has never worked: trusted publisher is not configured (v0.0.9 tagged but unpublished) #208 must be resolved first, or v1.0.0 fails to publish exactly like v0.0.9 did. The npm trusted-publisher config on @o1-labs/mina-archive-node-graphql has never existed; publish-npm.yml:52 (npm publish --provenance --access public) has never succeeded end to end. Which makes this line in the new doc currently false:

    CI then builds and publishes the npm package (with provenance) and the Docker images.

    Either land npm publishing from CI has never worked: trusted publisher is not configured (v0.0.9 tagged but unpublished) #208's fix first, or soften to "CI builds and publishes … once the npm trusted publisher is configured (see npm publishing from CI has never worked: trusted publisher is not configured (v0.0.9 tagged but unpublished) #208)".

  2. The documented release command cannot produce a v1.0.0 tag. docs/versioning.md (Releasing) and README.md:86 both say npm version <major|minor|patch>. Once package.json is already 1.0.0 on main, every level bumps past it (1.0.1 / 1.1.0 / 2.0.0). Releasing 1.0.0 then requires a hand-rolled git tag v1.0.0 && git push --follow-tags, which contradicts the doc it's introducing. Cleanest fix: drop the package.json change from this PR entirely and let npm version major (from 0.0.9) create both the bump and the tag at release time. The doc stands on its own and stops being self-contradictory. If you'd rather keep the bump, add a one-liner to the Releasing section:

    > `package.json` on `main` already carries the next version to be released. For that
    > release only, tag it directly (`git tag v1.0.0 && git push --follow-tags`) rather than
    > running `npm version`, which would bump past it.
  3. Consider noting that 0.0.70.0.9 were tagged but never published, so npm consumers see 0.0.6 → 1.0.0. A short "Migrating from 0.0.6" bullet list (CORS default, rate limiting, Node 22, actions semantics, boolean env parsing) would save a downstream reader from diffing the whole range.


Recommended addition: name error-message text as part of the stable surface

This is the highest-value change to the doc. The policy covers types/fields/arguments, which graphql-inspector already enforces — but the load-bearing contract for both known consumers is error text, which nothing enforces and nothing documents. Suggested section, drop it after "Flag-gating behaviour changes":

## Error messages and validation behaviour

GraphQL **validation and parse errors are part of the public contract.** Clients use
them for capability detection: they probe for a field or filter and fall back based on
the error text.

Covered by this policy:

- Validation and parse errors MUST be returned in `errors[]` of the response body with
  their verbatim `graphql-js` wording — notably `Cannot query field "X" on type "Y".`,
  `Unknown argument "X" on field "Y".`, `Unknown type "X".`, and unknown-input-field
  errors that name the field (e.g. `inBestChain`).
- `errors[]` MUST still be present in the body when the HTTP status is non-2xx; clients
  parse the body regardless of status code.
- Error masking (graphql-yoga `maskedErrors`) applies to **unexpected thrown runtime
  errors only**. Widening it to cover validation or parse errors — or replacing their
  text with a generic string, an error code, or a redacted message — is **breaking
  (major)**.

Known consumers matching on this text today: [mina-explorer]
(`src/services/api/bestChainFilter.ts``message.includes('inBestChain')`) and
mina-explorer-api (`app/upstream/graphql.py``"Cannot query field"`,
`"Unknown argument"`, `"Unknown type"`; `app/upstream/archive.py``"inBestChain"`).
As with flag-gating, breaking this doesn't fail loudly: the schema checker stays green,
health checks stay green, and the Explorer serves empty views.

Two more categories the "breaking changes" list is missing

Both are things the very next release actually does, so they're not hypothetical. Add under "Operational contract":

- Raising the minimum supported Node.js runtime — the `engines` range, the Docker base
  image, or the Node version CI publishes against — is **major**. It can make the
  published package uninstallable, or the image unrunnable, for a consumer on the
  previous LTS. (#194 moves the repo to Node 22; note that `package.json` declares no
  `engines` field today, only `volta.node` — adding one is worth doing at 1.0 so the
  constraint is machine-checkable rather than implied.)
- Enabling by default any behaviour that can reject, throttle, or block a
  previously-accepted request — rate limiting, request-size caps, query-cost limits, an
  origin allowlist — is **major**, whether or not the schema changes. (#184, #185.)

Non-blocking nits

  • Flag-gating has no carve-out for correctness fixes. As written, "changes that alter default response shape or content … ship disabled by default behind an environment flag" would forbid fix: resolve fromActionState/endActionState by chain position, not zkapp_field interning key #209 (fixes fromActionState/endActionState resolution — it changes actions content by design and ships unflagged, correctly). Suggest: "Correcting a result that was demonstrably wrong is a bug fix, not a flagged change; call it out explicitly in the release notes with the before/after shape."
  • Deprecation step 2 points at an artifact that doesn't exist. "Note the deprecation in the changelog/release notes" — there is no CHANGELOG.md in the repo, and the latest GitHub release is v0.0.8 (pre-release; v0.0.9 has none). Either commit to GitHub Releases as the channel ("announced in the GitHub release notes for the minor that introduces the deprecation") or add the changelog file. Otherwise the 90-day clock has no visible start.
  • "at least one minor release and 90 days" needs a start marker. Whichever is later, presumably — worth stating, and worth saying the @deprecated(reason:) string should carry the removal target (e.g. reason: "Use X. Removed in 2.0.0, no earlier than 2026-11-15.") so the deadline lives in the schema the consumer already reads.
  • Stale version in docs: docs/getting-started.md:79 still says docker pull ghcr.io/o1-labs/archive-node-api:0.0.6. Since this PR is the one declaring 1.0.0, bump it to 1.0.0 (or latest) here rather than leaving a doc pointing at the last actually-published artifact. The README npm badge is dynamic (shields.io/npm/v), and the Dockerfile carries no version label, so those two need nothing.

Automated second-pass review — focus: downstream compatibility with mina-explorer / mina-explorer-api.

SanabriaRusso
SanabriaRusso previously approved these changes Aug 18, 2026

@SanabriaRusso SanabriaRusso left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving on the basis of the second-pass review comment above: no mid-to-high severity security, compatibility, or degradation issue found, and the downstream contract with mina-explorer / mina-explorer-api holds — GraphQL validation error text reaches errors[].message verbatim, the browser SPA's cross-origin access is preserved, and the real consumer query shapes (including the 2000-block analytics query and the 500-row page crawl) still pass.

Two things this approval does not mean:

  • It does not close the non-blocking items in the review comment. Several are worth fixing before or shortly after merge; they are written up there with patches.
  • It does not by itself mean the branch is ready to merge. main requires branches to be up to date, so this needs an update-branch (or a rebase, if the branch is conflicting) first, and a few PRs in this series have cross-PR ordering constraints called out in their review comments.

Automated second-pass review — focus: downstream compatibility with mina-explorer / mina-explorer-api.

dkijania added a commit that referenced this pull request Aug 20, 2026
Codifies the practice the repo already relies on but never wrote down:
changes to default response shape or exposed query surface ship
default-off behind an env flag (ENABLE_BLOCK_TRANSACTION_DETAILS,
ENABLED_QUERIES), flagged-off being minor and flipping the default major.
This is the rule the schema checker cannot enforce — an unflagged change
to a default response isn't schema-breaking, so nothing errors; the
mina-explorer just blanks pages while health checks stay green.

Also fixes the breaking-change direction for output fields. The doc said
"a nullable field/argument to non-null" is breaking, which holds for
arguments but is reversed for output fields: there the break is non-null
→ nullable (clients may now receive null), while nullable → non-null only
strengthens the guarantee. The two are mirror images — the client supplies
arguments and consumes fields — so the rules are now stated separately.

Addresses review feedback on #198.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkijania
dkijania force-pushed the chore/v1-and-schema-policy branch from 40a2a0d to 57e398d Compare August 20, 2026 21:16
dkijania added a commit that referenced this pull request Aug 24, 2026
Codifies the practice the repo already relies on but never wrote down:
changes to default response shape or exposed query surface ship
default-off behind an env flag (ENABLE_BLOCK_TRANSACTION_DETAILS,
ENABLED_QUERIES), flagged-off being minor and flipping the default major.
This is the rule the schema checker cannot enforce — an unflagged change
to a default response isn't schema-breaking, so nothing errors; the
mina-explorer just blanks pages while health checks stay green.

Also fixes the breaking-change direction for output fields. The doc said
"a nullable field/argument to non-null" is breaking, which holds for
arguments but is reversed for output fields: there the break is non-null
→ nullable (clients may now receive null), while nullable → non-null only
strengthens the guarantee. The two are mirror images — the client supplies
arguments and consumes fields — so the rules are now stated separately.

Addresses review feedback on #198.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkijania
dkijania force-pushed the chore/v1-and-schema-policy branch from 57e398d to f1ef5bf Compare August 24, 2026 17:24

@SanabriaRusso SanabriaRusso left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every round-1 finding is addressed, and the two carry-forward items are the ones that matter most downstream. Approving.

Verified fixed

  • Release-state claim. I re-checked live rather than trusting the doc: the package is @o1-labs/mina-archive-node-graphql; npm view … versions returns only 0.0.6, dist-tags is { latest: '0.0.6' }, and issue #208 is still open. f1ef5bfc correctly makes both statements conditional ("once npm trusted publishing is configured"), and the Migrating from npm 0.0.6 section accurately records that 0.0.7–0.0.9 were tagged but never published. Nothing untrue remains.
  • Version bump is internally consistent. package.json 0.0.9 → 1.0.0 against main's actual 0.0.9 (round 1 saw it diffing from a stale 0.0.6), and package-lock.json updated in both places — top-level "version" and packages[""].version.
  • Release procedure is coherent with the repo sitting at 1.0.0 — the "initial 1.0.0 release only" carve-out replaces npm version with a direct tag, which resolves round 1's self-contradiction.
  • "Error messages and validation behaviour" is exactly the section that was missing, and it is the strongest part of this PR. Pinning verbatim graphql-js wording and declaring that widening masking over validation/parse errors is major turns both consumers' capability detection into a real contract instead of a lucky accident.
  • Both missing breaking-change categories are enumerated — minimum Node runtime (covering engines, the base image, and CI's publishing Node, which is the one people forget) and default-on request-rejecting behaviour (rate limiting, size caps, cost limits, stricter CORS). Those are precisely what #194 / #184 / #185 do next. #194 now ships engines: { "node": ">=22.12.0" }, so that category is immediately concrete.
  • Nullability direction is right in both cases: output String!String breaking, input StringString! breaking, with the mirror-image rationale spelled out.

One addition worth making to the error-text section

The section names Cannot query field. Verifying against the consumers, the contract is actually three literal strings, all equally load-bearing. mina-explorer-api matches on all three (app/upstream/graphql.py:33-42):

SCHEMA_ERROR_MARKERS: tuple[str, ...] = (
    "Cannot query field",
    "Unknown argument",
    "Unknown type",
)

A match on any of them classifies the response as UpstreamSchemaError, which drives tier fallback and poisons that consumer's capability cache — so a change to Unknown argument or Unknown type wording is exactly as breaking as one to Cannot query field, and the failure is sticky rather than per-request. Worth naming all three explicitly so a future reader does not assume only the first is protected. (mina-explorer keys on Cannot query field alone — transactions.ts:488,556,698,977, ZkAppsPage.tsx:183.)

Ordering: round 1's "#208 must land before #198" constraint no longer applies to the merge — the doc's caveat is now truthful, so this can go in. It moves to the release: #208 must be resolved before v1.0.0 is pushed, or the publish job fails ENEEDAUTH exactly as it did for v0.0.9. The Docker half of the pipeline is fine — GHCR has images through 0.0.9 and publishes on refs/tags/v*.

Non-blocking nits

  1. The initial-release command does not work as written. docs/versioning.md:

    git tag v1.0.0 && git push --follow-tags

    git tag without -a/-s creates a lightweight tag, and git push --follow-tags pushes only annotated tags. Followed verbatim, nothing is pushed and no release fires. (The npm version path above it is fine — npm creates annotated tags.) Fix:

    git tag -a v1.0.0 -m 'v1.0.0'   # annotated: --follow-tags ignores lightweight tags
    git push --follow-tags
  2. docs/getting-started.md now pulls a tag that does not exist yet. GHCR's tag list for o1-labs/archive-node-api is currently 0.0.1-test, latest, 0.0, 0, 0.0.1, 0.0.2, 0.0.4, 0.0.5, 0.0.8, 0.0.6, 0.0.9 — no 1.0.0. It resolves the moment v1.0.0 is tagged, but between merge and release that copy-pasteable command fails. Either land this immediately before cutting the tag, or add "(available from the 1.0.0 release onward)".

  3. The Enforcement section overstates what CI enforces. Check Schema and approve-label: expected-breaking-change are real (.github/workflows/graphql-inspector.yaml), but main's required status checks are ["Run-Tests", "Linting"] only — a breaking-schema PR goes red without being blocked. Either add Check Schema to branch protection (preferable, since the whole policy leans on it) or soften to "flags the PR red; treat a red Check Schema as requiring the expected-breaking-change label and a major bump."

  4. The stable-endpoint list names /readiness and /metrics, which arrive with #187 and #191. Fine as long as both land before v1.0.0 is tagged — worth stating explicitly next to the "these controls arrive in 1.0.0" framing used elsewhere in the batch.

Downstream: strongly positive, and the main reason to land this. The new error-message section converts mina-explorer's inBestChain probe and mina-explorer-api's three-marker capability detection from an undocumented accident into a written major-version contract, and the flag-gating section names the exact silent-degradation mode (green health checks, blank Explorer pages). No runtime behaviour changes in this PR.

dkijania added a commit that referenced this pull request Aug 24, 2026
Codifies the practice the repo already relies on but never wrote down:
changes to default response shape or exposed query surface ship
default-off behind an env flag (ENABLE_BLOCK_TRANSACTION_DETAILS,
ENABLED_QUERIES), flagged-off being minor and flipping the default major.
This is the rule the schema checker cannot enforce — an unflagged change
to a default response isn't schema-breaking, so nothing errors; the
mina-explorer just blanks pages while health checks stay green.

Also fixes the breaking-change direction for output fields. The doc said
"a nullable field/argument to non-null" is breaking, which holds for
arguments but is reversed for output fields: there the break is non-null
→ nullable (clients may now receive null), while nullable → non-null only
strengthens the guarantee. The two are mirror images — the client supplies
arguments and consumes fields — so the rules are now stated separately.

Addresses review feedback on #198.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkijania
dkijania force-pushed the chore/v1-and-schema-policy branch from f1ef5bf to 8db560a Compare August 24, 2026 20:04
dkijania added a commit that referenced this pull request Aug 24, 2026
Codifies the practice the repo already relies on but never wrote down:
changes to default response shape or exposed query surface ship
default-off behind an env flag (ENABLE_BLOCK_TRANSACTION_DETAILS,
ENABLED_QUERIES), flagged-off being minor and flipping the default major.
This is the rule the schema checker cannot enforce — an unflagged change
to a default response isn't schema-breaking, so nothing errors; the
mina-explorer just blanks pages while health checks stay green.

Also fixes the breaking-change direction for output fields. The doc said
"a nullable field/argument to non-null" is breaking, which holds for
arguments but is reversed for output fields: there the break is non-null
→ nullable (clients may now receive null), while nullable → non-null only
strengthens the guarantee. The two are mirror images — the client supplies
arguments and consumes fields — so the rules are now stated separately.

Addresses review feedback on #198.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkijania
dkijania force-pushed the chore/v1-and-schema-policy branch from 8db560a to 4aac67f Compare August 24, 2026 20:21
dkijania added a commit that referenced this pull request Aug 24, 2026
Codifies the practice the repo already relies on but never wrote down:
changes to default response shape or exposed query surface ship
default-off behind an env flag (ENABLE_BLOCK_TRANSACTION_DETAILS,
ENABLED_QUERIES), flagged-off being minor and flipping the default major.
This is the rule the schema checker cannot enforce — an unflagged change
to a default response isn't schema-breaking, so nothing errors; the
mina-explorer just blanks pages while health checks stay green.

Also fixes the breaking-change direction for output fields. The doc said
"a nullable field/argument to non-null" is breaking, which holds for
arguments but is reversed for output fields: there the break is non-null
→ nullable (clients may now receive null), while nullable → non-null only
strengthens the guarantee. The two are mirror images — the client supplies
arguments and consumes fields — so the rules are now stated separately.

Addresses review feedback on #198.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkijania
dkijania force-pushed the chore/v1-and-schema-policy branch from 4aac67f to 0230e50 Compare August 24, 2026 20:54
dkijania and others added 4 commits August 25, 2026 20:42
The package was pre-1.0 (0.0.6) with no documented stability guarantees, which
public consumers need.

- Bump version to 1.0.0 (package.json only — no tag; the actual release/publish
  remains a deliberate maintainer step via `npm version` + tag push).
- Add docs/versioning.md: SemVer applied to the GraphQL schema / HTTP endpoints /
  config, a precise definition of breaking vs additive changes, a deprecation
  policy (@deprecated + one minor & 90 days before removal), and how the existing
  graphql-inspector "Check Schema" gate enforces it via the
  expected-breaking-change label.
- Link the policy from the README.

Closes #178.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QSuak9smCHbp4N17xjjLF6
Codifies the practice the repo already relies on but never wrote down:
changes to default response shape or exposed query surface ship
default-off behind an env flag (ENABLE_BLOCK_TRANSACTION_DETAILS,
ENABLED_QUERIES), flagged-off being minor and flipping the default major.
This is the rule the schema checker cannot enforce — an unflagged change
to a default response isn't schema-breaking, so nothing errors; the
mina-explorer just blanks pages while health checks stay green.

Also fixes the breaking-change direction for output fields. The doc said
"a nullable field/argument to non-null" is breaking, which holds for
arguments but is reversed for output fields: there the break is non-null
→ nullable (clients may now receive null), while nullable → non-null only
strengthens the guarantee. The two are mirror images — the client supplies
arguments and consumes fields — so the rules are now stated separately.

Addresses review feedback on #198.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkijania
dkijania force-pushed the chore/v1-and-schema-policy branch from 0230e50 to c561a2c Compare August 25, 2026 18:43
@dkijania
dkijania merged commit 7361526 into main Aug 25, 2026
9 checks passed
@dkijania
dkijania deleted the chore/v1-and-schema-policy branch August 25, 2026 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation P2 GA polish / hygiene production-readiness Work toward making the API production-ready / publicly available

Projects

None yet

Development

Successfully merging this pull request may close these issues.

P2: Cut 1.0.0 + schema stability / deprecation policy

2 participants