What a surgical, intentional break looks like under a merge gate
Delimit's merge gate ran against the public Supabase Auth (GoTrue) OpenAPI on 2026-05-06. The change set between commit 40d07b5f (2026-03-02) and 63949cac (2026-04-28) spans 57 days. One commit touched the spec in the window. The advertised info.version field was latest on both ends. This page is the signed, replayable attestation that fell out, written up so any reader can audit the same evidence bytes.
github.com/supabase/auth, and the analysis is reproducible byte-for-byte from the same commits. This is the smallest published change set in the cadence so far: a single commit, a single architectural shift, a small breaking surface. We did not contact Supabase, did not coordinate this report with Supabase, and have no relationship to the project beyond reading the public spec.What we did
We cloned github.com/supabase/auth, extracted openapi.yaml at two points: the current HEAD of the spec at the time of analysis (commit 63949cac, 2026-04-28, the WebAuthn RP config hardening commit) and a baseline roughly 57 days earlier (commit 40d07b5f, 2026-03-02, the OIDC discovery-cache commit, which was the prior spec-touching commit). Each spec is roughly 134 KB of YAML and declares 43 paths, 59 operations, and 15 component schemas. We ran delimit lint in its standard configuration, with no policy overrides. The diff engine classified each change against its 27-type taxonomy. The semver classifier walked the breaking-vs-non-breaking partition and produced a bump recommendation. Everything below is mechanical output, annotated.
One commit touched the spec in the entire 57-day window. That is unusual for a window of this length on an active project, and it tells you something true about the surface: the public Supabase Auth contract is held tightly, and the maintainers are not casually churning fields on it. The single commit that did land is precisely the kind of change a pre-merge gate is designed to surface.
Headline numbers
The endpoint count is identical across the window: zero added, zero removed. The schema count is identical: 15 on both ends. The change volume is two field removals on a single MFA endpoint, and both removals are required-field drops, which is what makes the gate's independent semver classification major regardless of what the version string says. The advertised info.version field is latest on both ends. A major-class break shipped under an unchanged version string. The merge gate is designed to catch exactly this asymmetry before publish, not after.
Findings
2 breaking, 0 additive, 1 flagged as spec hygiene. Each finding cites the exact change-type from the 27-type taxonomy, the surface affected, and the consumer impact. The hygiene finding here is unusual: it is a real-world change that the engine did not flag as breaking, surfaced honestly so the reader understands the engine's sensitivity boundary rather than over-trusting a clean lint pass.
- breakingfinding F1change type: field_removed (required field dropped)surface:
/factors/{factorId}/verify:POST request.webauthn.rpIdThe required string field rpId was removed from the webauthn object on the MFA verify endpoint. rpId is the WebAuthn relying-party identifier (typically the registrable domain). Code that constructs verify-request bodies against the prior shape and includes rpId will now find that the field is silently ignored by the server, and clients that omit it will succeed where they previously failed schema validation. The HEAD commit message states the source of truth has moved to the server-side env var GOTRUE_WEBAUTHN_RP_ID. The visibility is the artifact: any reviewer reading the attestation sees the required-field removal without having to read the linked PR.
- breakingfinding F2change type: field_removed (required field dropped)surface:
/factors/{factorId}/verify:POST request.webauthn.rpOriginsThe required array field rpOrigins (with minItems: 1) was removed from the same webauthn object on the verify endpoint. rpOrigins is the list of allowed origins the WebAuthn assertion may have originated from. Source of truth has moved to the server-side env var GOTRUE_WEBAUTHN_RP_ORIGINS. F1 and F2 are paired: they ship in the same commit and they describe the same architectural shift. The gate flags them as two separate field_removed entries because the change-type taxonomy is field-granular by design, which is what gives a downstream consumer the exact mapping they need to update.
- spec hygienefinding C1change type: field_removed (object dropped, parent optional)surface:
/factors/{factorId}/challenge:POST request.webauthnOn the sibling MFA challenge endpoint, the entire webauthn object was removed from the request body, including its own internal rpId and rpOrigins fields. The diff engine did not flag this as breaking because the webauthn object itself was optional on the parent (the request body did not list webauthn under required), and the engine fires field_removed conservatively on required-field drops. The runtime shift is identical to F1 and F2: consumers that were sending a webauthn block on challenge will find it silently ignored. We surface this as a hygiene-class observation rather than re-classify it ourselves, because honesty about engine sensitivity is more useful to the reader than over-classification. A pre-merge reviewer reading the attestation would catch the symmetry on inspection.
What this report is not
Not a defect claim. Not a security advisory. Not a judgment of the Supabase Auth team's release process. The change in this window is plainly an intentional security hardening: WebAuthn relying-party configuration moves from the client-supplied request body to server-controlled environment variables (GOTRUE_WEBAUTHN_RP_ID, GOTRUE_WEBAUTHN_RP_ORIGINS, GOTRUE_WEBAUTHN_RP_DISPLAY_NAME), which is the right place for that configuration to live and is the shape any reasonable WebAuthn deployment ends up at. The breaking changes flagged above are the cost of that move, made paid down in one commit, and the commit message explicitly documents that the removed fields are now silently ignored on the wire.
The findings above do not say Supabase made a mistake. They say: here is exactly which two required fields shifted, here is the sibling endpoint where the same shift landed without a required marker to flag on, and here is what a downstream consumer pinned to the prior shape will need to re-map. That visibility is the artifact. The merge gate's job is making the shape of an intentional break visible in pre-merge review and confirming that the version string downstream consumers see matches the change class. On this surface the version string did not move, and the gate's independent classification did. An attestation reader can verify both facts without re-running the analysis.
The attestation artifact
A Delimit attestation is a bounded evidence record at a single commit pair. The same Delimit version run against the same two commits produces the same bytes; that is the replayable property. The attestation does not opine on whether a change should have shipped, only on what shipped and how the change-type taxonomy classifies it.
For the precise list of checks, the explicit out-of-scope list, and the reproducibility guarantee, see the attestation methodology v1. This report is the OpenAPI-diff surface of the same primitive that powers the merge gate for AI-written code.
Reproduce locally
Anyone can re-run the analysis above against the same two commits and verify the same diff comes out. The full command sequence:
# Install the CLI npm install -g delimit-cli # Clone the repo (full history; we walk back ~57 days) git clone https://github.com/supabase/auth cd auth # Extract the two specs at the cited commits git show 40d07b5f:openapi.yaml > /tmp/old.yaml git show 63949cac:openapi.yaml > /tmp/new.yaml # Run the merge gate delimit lint /tmp/old.yaml /tmp/new.yaml
If the bytes you get differ from the bytes in this report, that is itself a finding worth reporting; raise it on the Delimit repo and we will look. Each spec is roughly 134 KB; the lint pass completes in well under one second on a standard laptop.
For your own API surface
If you ship a public API and want this kind of pre-merge attestation in your CI pipeline, install delimit-cli and run delimit lint <old> <new> against your own specs. The GitHub Action is on the Marketplace at delimit-ai/delimit-action. Free for individual maintainers. Pro tier $10/month for teams.
The signed, replayable attestation is the artifact your reviewers, auditors, or downstream consumers can read without rerunning the gate.