Breaking-change detection
A spec change that looks small on the wire can delete a method from thirteen SDKs. Renaming an
operationId, tightening a type, making an optional parameter required — each one compiles fine on
your side and breaks every caller who upgrades.
So Glotto classifies the change before you merge it. Every pull request that touches your spec gets a preview build, and that build carries an API-surface comparison against the last one: what changed, and for each change, whether a caller who upgrades keeps working.
What you get
On the pull request, in the preview-build comment:
| Target | Status | Files | Changes vs. base | API surface |
|---|---|---|---|---|
typescript |
✅ built | 42 | 3 changed | ⚠️ 1 breaking |
python |
✅ built | 39 | 3 changed | ⚠️ 1 breaking |
The API surface column is the classification. ⚠️ N breaking means at least one change would
break a caller who upgrades; N non-breaking means the surface moved but nobody’s code stops
working; and a clean comparison says so rather than staying silent.
Expanding the section beneath the table lists every change, breaking first, with the operation or model it belongs to. That ordering is the point: the breaking ones are the whole reason to read the list, and they are what a reviewer needs before approving.
What counts as breaking
The classification is about your callers, not about the diff:
- Breaking — a method or model disappears, is renamed, or changes shape in a way an existing
call site cannot survive. A removed operation, a renamed
operationId, a parameter that becomes required, a response field that changes type. - Non-breaking — the surface grew or was refined without invalidating existing code. A new operation, a new optional parameter, a new response field, a widened type.
Two things are deliberately not breaking, because they are the mechanisms for not breaking:
- An alias. Renaming
createRecordtoupsertRecordand declaringaliases: { createRecord: upsertRecord }keeps the old method name in every SDK, routed to the new operation — so the rename re-occupies the surface it vacated, and the classification says non-breaking. That is the honest answer: no caller breaks. - A transform. Corrections you apply to the spec before generation are part of the input, so the comparison sees the corrected surface on both sides.
What it compares against
The previous build of the same target. Glotto stores the spec revision every preview build was generated from, and the next build classifies against it — so the comparison always describes the change this pull request makes, not the accumulated drift since some fixed point.
Two consequences worth knowing rather than discovering:
- A target with no previous build has nothing to compare against, so its first preview reports no API surface rather than reporting everything as new. A brand-new target is not a breaking change to a caller who does not have it yet.
- Targets on different baselines get their own sections. A target added later has a different last-build than its siblings, and merging the two comparisons would produce a diff that accurately describes neither.
Making it impossible to miss
# glotto.yml
settings:
detect_breaking_changes: true
With this set, a breaking change is called out at the top of the preview comment, naming how many there are, instead of living in one table cell and a collapsed section. Leave it unset and the classification is still there — it is just quieter.
Set it once your first release is out and callers exist. Before that, everything is breaking and nothing is.
This is emphasis, not enforcement. Glotto does not set a commit status or a check run on your pull request, so nothing here can be made a required check and nothing blocks a merge. If you want that, make it a branch protection rule on your own side; what Glotto guarantees is that the information is on the pull request, correct, and impossible to overlook.
What this does not do
- It does not decide your version number. The classification is an input to that decision, not a substitute — a breaking change with an intentional major bump is a normal release, and Glotto does not guess which one you meant.
- It does not compare against an arbitrary point in history. The baseline is the last build, by design: a comparison against a ref you name would answer a different question, and answering it well needs a route we do not offer today.
- It does not classify behaviour, only surface. An operation that keeps its signature and changes what it returns at runtime is invisible here. That is what your contract tests are for.