How this is decided
Severity is deterministic
Every change is classified by a fixed rule, not by a language model. The same pair of specs always produces the same severities, so a wrong call is a bug in a rule that can be found and fixed, rather than an unreproducible generation.
A model is used for one thing only: rewriting explanatory prose where the templates read thin. It never assigns severity, and it never sets the headline.
The three direction flips
Producer-side tools ask “does this break my callers?” This feed sits on the calling end, where three rules invert. They are the reason it exists.
- A response property becoming optional is safe for a producer and a null dereference waiting to happen for you.
- A new enum value in a response is additive for a producer. It breaks exhaustive switches, strict parsers and generated client enums.
- A removed request parameter raises no error at all. The provider ignores it, your results change, and nothing goes red.
What we are actually reading
Specifications, not behaviour. Some providers update their spec weeks after shipping, and some never do. Everything here is spec-derived, and a change that never reached the spec will never reach this feed.
Shared schemas are diffed once each, not once per endpoint that references them, and the number of operations a component reaches is shown alongside it. Following references inline instead produced 4528 “breaking” changes for a single Stripe release, the same enum reported 2319 times.
Nothing publishes itself
A change below 85 confidence never reaches the feed, and cosmetic changes never do at any confidence. Everything else is held for human review first. Precision over recall, without apology: one false breaking change costs a reader permanently.
The ruleset
| Rule | Severity | What it does to calling code |
|---|---|---|
| operation.removed | breaking | This verb now 405s. The path still resolves, so a health check on the URL will not catch it. |
| path.removed | breaking | Requests to this path now 404. |
| request.enum.value-removed | breaking | A value you may have hardcoded is now rejected. |
| request.param.became-required | breaking | Calls that omit it are rejected. |
| request.param.removed ⇄ | breaking | No error is raised. The value is ignored and your results change silently, which is the hardest class of break to notice. |
| request.param.required-added | breaking | Every existing call that omits it is rejected. |
| request.property.became-required | breaking | Partial payloads are rejected. |
| request.property.removed ⇄ | breaking | Usually ignored rather than rejected, so the call succeeds and does something subtly different. |
| request.property.type-changed | breaking | Serialization mismatch. Integer-to-string moves are the usual cause and the usual outage. |
| response.enum.constraint-removed ⇄ | breaking | The documented set of values is gone, so anything can appear. Every exhaustive switch and generated enum over this field is now incomplete. |
| response.enum.value-added ⇄ | breaking | Producer-side tools call this additive. It breaks exhaustive switches, strict parsers and generated client enums. |
| response.property.became-optional ⇄ | breaking | Producer-side tools call this non-breaking. For a consumer it is a null dereference on an unknown future date. |
| response.property.removed | breaking | Reads of this field return undefined, and the failure surfaces wherever that value is used rather than at the call. |
| response.property.type-changed | breaking | Parse failure, or silent coercion depending on your client. |
| security.scheme-changed | breaking | The integration needs reworking, not patching. |
| security.scope-added | breaking | Existing tokens 403. This needs user re-consent, not a code change, so it cannot be fixed by deploying. |
| operation.deprecated | deprecation | Still works today. This is the earliest warning you will get before it is removed. |
| default.value-changed | behavioral | Behavior shifts for every call that omits the field. |
| pagination.default-changed | behavioral | Silent truncation. Code that does not paginate keeps working and quietly returns a different slice of the data. |
| response.property.now-always-null | behavioral | Nothing throws, since the field could already be null, but the value you read here is gone. Often a spec-generator artifact, so it is held for a person to check. |
| response.status-code.added | behavioral | An unhandled branch in your error handling. |
| response.status-code.removed | behavioral | Dead branch, or an undocumented response you still receive. |
| schema.composition-changed | behavioral | The set of shapes this value can take changed. Worth a look, but the structural diff cannot say precisely how. |
| schema.ref-retargeted | behavioral | Often a rename with an identical shape, sometimes a genuine retype. The structural diff cannot tell which, so this is held below the publish threshold on purpose. |
| security.requirement-removed | behavioral | The operation no longer demands this credential. |
| operation.added | additive | No action needed. |
| operation.undeprecated | additive | The operation is supported again. |
| path.added | additive | No action needed. |
| request.enum.constraint-removed | additive | A relaxation, not a break. Everything you could send before still works, and more is accepted now. |
| request.param.optional-added | additive | No action needed. |
| request.property.added | additive | No action needed unless it is required. |
| request.property.became-nullable | additive | A relaxation. Existing payloads are unaffected. |
| response.property.added | additive | No action needed unless you validate responses against a closed schema. |
| response.property.type-narrowed | additive | A tighter guarantee, not a break. Every value you can receive now was already possible, so existing handling still covers it; a null check here may now be dead code. |
| cosmetic.description-changed | cosmetic | None. |
| cosmetic.schema-renamed | cosmetic | The shape is identical. Only the name changed. |
| request.param.unlisted | cosmetic | The same parameter still exists as a shared component, or on other operations. This is a documentation drop, not a withdrawn argument. |
⇄ marks a rule producer-side tools classify the other way.