6 min read
Gate Classification
How StateAnchor classifies API changes into ERR, WARN, and INFO lanes
Every change StateAnchor detects in your API spec is classified into one of three lanes before the gate evaluates it. The lane determines whether the sync proceeds or blocks. This page documents the classification rules and the rationale behind each.
The three lanes
ERR -- Always blocks
Breaking changes with no consumer migration path available at the call site. If any ERR-lane change is present, the gate blocks. There is no threshold to configure -- one breaking change is enough. The only way through is a reviewed drift exception with a named approver.
WARN -- Threshold-based
Degradation changes that may or may not break consumers depending on usage patterns. Whether they block depends on a configurable threshold: the gate blocks when the count of WARN-lane changes meets or exceeds the threshold. Teams that want a stricter posture can lower the threshold. Teams that accept more risk can raise it.
INFO -- Never blocks
Additive changes that cannot break existing consumers. INFO-lane changes are logged for visibility but never block or warn. If only INFO-lane changes are present, the gate always proceeds.
Classification reference table
Every change kind StateAnchor recognizes, its default lane, and the rationale behind the classification. Fourteen ERR, eight WARN, and eight INFO kinds -- expanded in April 2026 from an oasdiff / openapi-diff / Optic consensus audit.
variant_removed) is ERR -- consumers branching on the removed variant break immediately. Adding a variant (variant_added) is WARN -- consumers with exhaustive match logic may hit an unhandled case but existing code still works. See stateanchor.yaml reference for discriminator workarounds.stateanchor.yaml uses OpenAPI 3.0 schema syntax. oneOf / anyOf compositions are supported in gate classification (when the engine sees them via a referenced OpenAPI spec), but the stateanchor.yaml format does not yet accept them as top-level schema definitions. If you need unions at the spec root, declare them in the underlying OpenAPI file and reference from stateanchor.yaml.| Change Type | Lane | Why It Classifies This Way |
|---|---|---|
endpoint_removed | ERR | Consumers calling this endpoint will get 404s immediately. No migration path exists at the call site. |
field_removed | ERR | Any consumer reading or sending this field will break silently or throw. Covers both body fields and parameter removal. |
type_changed | ERR | A field or parameter changing type (e.g., string → number) breaks every parser that expected the original type. |
auth_changed | ERR | Existing auth tokens, API keys, or required scopes stop working. Every consumer must update credentials or auth flow. |
enum_value_removed | ERR | Consumers that match on the removed value will hit an unhandled case, causing logic failures. |
variant_removed | ERR | A variant was removed from a oneOf / anyOf union. Consumers branching on the removed variant will hit an unhandled case or parse failure. |
required_param_added | ERR | A new required parameter was added on an existing operation. Calls that omit it are rejected by the server. |
optional_param_now_required | ERR | An existing optional parameter was flipped to required. Callers that never sent it now fail validation. |
param_removed | ERR | A parameter in use by active consumers was removed. The server no longer recognises the field. |
response_field_removed | ERR | A response property was removed. Consumers reading it receive undefined or a parse error. |
response_field_type_changed | ERR | A response field type changed incompatibly (e.g., number → string). Downstream type-checked code breaks. |
response_schema_type_changed | ERR | The overall response schema type changed (e.g., object → array). Every consumer parser fails. |
success_status_removed | ERR | A 2xx/3xx status code was removed. Callers that branch on specific status codes break. |
validation_constraints_tightened | ERR | A validation bound was tightened (min^, maxv, minLength^, maxLengthv, narrower regex). Existing valid payloads may now fail. |
opaque_token_scheme_changed | ERR | The auth scheme type changed (e.g., Bearer → API-Key). Every existing auth token is invalid against the new scheme. |
error_response_shape_changed | ERR | The 4xx/5xx response schema shape changed. Error-handling code that parsed the old shape will fail silently or throw. |
required_added | WARN | A new required field or parameter was added on a new operation path. Existing call sites for existing operations are unaffected; new call sites must include the field. (Flipping an existing optional parameter to required is ERR -- see optional_param_now_required.) |
field_renamed | WARN | A schema $ref target changed, which the engine treats conservatively as a rename. Consumers using the old shape lose data silently. |
optional_field_removed | WARN | Scanner-detected: an optional body field disappeared. Consumers reading it get undefined instead of data. Not emitted by the pure diff engine. |
response_field_required | WARN | Scanner-detected: a response field was flipped from optional to required. Not emitted by the pure diff engine. |
response_constraints_relaxed | WARN | A validation bound on a response field was relaxed (e.g., max raised, maxLength raised, enum broadened). Relaxing response constraints can break consumers that rely on strict validation of server output. |
response_enum_value_added | WARN | A new enum value was added to a response field. Consumers with exhaustive match or switch logic over the enum will hit an unhandled case. |
deprecation_violation | WARN | A field or endpoint marked deprecated was removed before the sunset window expired. |
variant_added | WARN | A new variant was added to a oneOf / anyOf union. Consumers with exhaustive match or switch logic will hit an unhandled case. |
evaluator_disagreement_high | WARN | Closure-phase evaluators significantly diverged on the IR. Human review recommended. |
endpoint_added | INFO | New endpoints cannot affect existing consumers. Purely additive. |
field_added_optional | INFO | New optional fields or parameters are backward-compatible by definition. Existing consumers ignore them. |
description_changed | INFO | Description text is informational only. No consumer code reads description strings at runtime. |
endpoint_key_collision | INFO | Two endpoints in the spec normalize to the same key (e.g., trailing-slash variants). Advisory only; the first occurrence wins. |
deprecated_flag_added | INFO | An operation or field was marked deprecated -- a signal to consumers without any contract break. |
constraints_relaxed | INFO | A validation bound was relaxed (max^, minv, maxLength^, minLengthv, broader enum). Previously valid payloads remain valid. |
optional_status_code_added | INFO | A new success or error code was added alongside existing ones. Consumers that do not branch on it are unaffected. |
metadata_changed | INFO | Tags, examples, externalDocs, or other non-behavioural metadata changed. No runtime impact. |
The evidence chain
Every finding StateAnchor produces includes four pieces of evidence:
- kind -- the classification type (e.g.,
field_removed,type_changed) - endpoint -- the specific API endpoint affected (e.g.,
GET /users/{id}) - field -- the specific field or parameter within the endpoint
- evidence -- a human-readable explanation of what changed and why it matters
The full finding chain is visible in every share link. When a gate blocks, the share page shows every finding with its complete evidence so reviewers can assess the change without needing access to the repo or the diff.
Exception ledger
If your team has acknowledged a specific drift item -- for example, you know a field removal is safe because no active consumer uses it -- you can suppress it via the exception ledger in your project settings. Suppressed items reduce the effective breaking score but remain visible in the audit trail.