Semantic Versioning & Deprecation Gate¶
Versioning policy — instantiates Representation-Independent Interface Contract
Governs how the contract may change over time, encoding compatibility in the version number and giving clients a deprecation window before anything breaks.
A contract is not a single event; it changes, and every change is a chance to break someone. Semantic Versioning & Deprecation Gate governs that change over time. It is the policy that decides what kind of change a given edit is — a bug-fix, a backward-compatible addition, or a break — encodes that judgement in the version number itself, and, when a break is unavoidable, runs it through a deprecation window so clients get warning and a migration path before anything is removed. Its defining move is operating on the time axis the other mechanisms ignore: they judge one implementation against the contract at one moment; this one judges each version of the contract against the last and manages the population of clients across the transition.
Example¶
An open-source date-handling library is preparing a release. Three changes are on deck: a bug fix to a leap-second calculation, a new formatRelative function, and the removal of a long-criticised parseLoose function. The gate classifies each against the compatibility rule. The bug fix (which changes an output some client might rely on) and the removal are breaking; the new function is additive. Under semantic versioning that forces a MAJOR bump — but the gate does not just stamp a number.
For parseLoose it opens a deprecation window: the function stays, but now emits a warning pointing at its replacement, and the release notes announce a removal date two minor versions out. The maintainers consult their consumer inventory — download stats and public dependents — to size who is affected and whether the window is long enough. Only after the window elapses does a later MAJOR actually delete the function. The number told the truth, and no client was surprised.
How it works¶
- Classify the change. Diff the new contract against the old and sort every change into fix / backward-compatible-addition / break — the classification the version number will encode.
- Make the number tell the truth. Map the classification onto PATCH / MINOR / MAJOR so a client can predict the risk of upgrading from the number alone.
- Deprecate before removing. A breaking removal is staged: mark the old surface deprecated, emit warnings, publish a replacement and a removal date, and delete only after the window.
- Size the blast radius. Use the consumer inventory — who depends on what, and on which version — to set window length and prioritise migration help for the changes that hit the most clients.
Tuning parameters¶
- Compatibility strictness — how much counts as "breaking." Purists treat any observable change, even a bug fix, as breaking (because someone depends on the old behaviour); pragmatists draw the line at documented behaviour. Stricter means more MAJORs and fewer surprises.
- Deprecation window length — how long a deprecated surface survives before removal. Longer eases migration and slows the codebase's evolution; the dial is set by how many consumers there are and how fast they move.
- Warning intensity — from a quiet changelog note, to a runtime warning, to a hard compile error on the deprecated path. Louder drives migration faster and annoys more people.
- Inventory reach — how completely consumers are known: internal callers only, or the public dependent graph. Better reach lets the window and messaging be targeted rather than guessed.
When it helps, and when it misleads¶
Its strength is predictability for people the code has never met: a version number becomes a promise a client can plan an upgrade around, and a deprecation window converts a breaking change from an ambush into a scheduled, survivable migration. It is what lets a contract evolve at all without fracturing its ecosystem.
Its failure modes are about the number lying. Version theater — bumping digits by ritual while never actually diffing behaviour — produces numbers that do not predict compatibility, which is worse than none because clients trust them. MAJOR-phobia ships genuine breaks as minor or patch to avoid the optics of a major, and clients upgrade into a wall. The classic misuse is choosing the bump to fit a marketing calendar or dodge a major, then back-filling the justification — the classification run backwards from the desired number. And because even a bug fix is breaking for someone, the gate can never be perfectly safe, only honest. The discipline is to derive the bump from an actual behavioural diff — ideally the output of the conformance tests — rather than from intent, and to let the evidence, not the calendar, pick the number.[1]
How it implements the components¶
Semantic Versioning & Deprecation Gate realises the evolution side of the contract — it governs change across versions and the clients living through it:
versioned_contract_record— it maintains the versioned history of the contract and the compatibility promise each version number encodes.client_dependency_inventory— it tracks who consumes which version, the inventory that sizes a change's blast radius and sets the deprecation window.
It does not test whether a given change is actually compatible — that evidence comes from the test siblings (Property-Based Conformance Test, Reference-Implementation Differential Test) — and it does not prove a replacement substitutable under real load, which is Substitutability Trial / Canary's job.
Related¶
- Instantiates: Representation-Independent Interface Contract — it lets the contract change over time without breaking the clients that depend on it.
- Consumes: the conformance tests (Reference-Implementation Differential Test, Property-Based Conformance Test) supply the behavioural diff that classifies a change as breaking or additive.
- Sibling mechanisms: Substitutability Trial / Canary rolls out the version this gate blessed · Compatibility Matrix · Representation Leakage Probe · Reference-Implementation Differential Test
References¶
[1] Semantic Versioning 2.0.0 encodes the compatibility promise in the number itself — PATCH for fixes, MINOR for backward-compatible additions, MAJOR for breaking changes. The gate's whole job is to make the number tell the truth about the behavioural diff behind it. ↩