docs(decisions): only a Changed — BREAKING forces a minor (ADR-0061) - #307
Merged
Merged
Conversation
Three accepted records say a behavioural break takes a minor, and the shipped history contradicts them twice. ADR-0028's post-v2.0 commitment 3 calls a patch "no-breaking por definición"; ADR-0050 says "never in a patch"; ADR-0052 F4 says a breaking entry "gets a minor bump". But 2.5.2 and 2.5.3, both 2026-09-13 and both after all three, each shipped two `Fixed — BREAKING` entries as a patch. Counted across every `BREAKING` heading in CHANGELOG.md: all three `Changed — BREAKING` live in 2.5.0, a minor, and none has ever shipped in a patch; fourteen `Fixed — BREAKING` shipped in both tiers. And 2.5.0's ten did not cause its minor — the three `Changed` in the same release already did. No release has ever taken a minor *for* a `Fixed — BREAKING`. The split is not arbitrary: `Fixed` says the documented behaviour was not being delivered and now is, so the consumer relied on something never promised; `Changed` withdraws a promise that was kept. D1 records that. D2 states the amendment to ADR-0028 commitment 3 explicitly rather than leaving it implicit — the rest of that ADR stands, including the 8-12 minors/year cap and the migration guide a breaking minor owes. D5 records that 2.5.2 and 2.5.3 are applications of the rule, not errors. The cost is stated, not mitigated: a label now carries the release tier and nothing verifies it. No test parses CHANGELOG.md and publish.yml never reads `[Unreleased]`. Also applied here, since it is the same ruling: #286's entry gains its `BREAKING` label. A save in flight at shutdown is now cut short when the budget expires instead of running under a token nothing could cancel — observable to an operator, which is the threshold #284 was labelled under. It is a `Fixed`, so it does not move the pending release's tier; 2.6.0 is already a minor from the two `Changed — BREAKING` it carries. ADR-0048 D7 reads like a third tier rule and is not: its "not a patch" means an inline code change, settled by its own next sentence, and the case it names shipped as a `Changed — BREAKING` in a minor anyway. ADR-0027's constraint on removing public MIT types is untouched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The contradiction
Three accepted records say a behavioural break takes a minor:
no-breaking por definición." In force since v2.0.0 shipped 2026-05-06.
BREAKINGCHANGELOG entry and a minor bump."The shipped history contradicts them twice. Counted across every
BREAKINGheading inCHANGELOG.mdon 2026-09-24:Fixed — BREAKINGChanged — BREAKING[Unreleased]Both patches landed after all three records.
The pattern nobody had written down
All three
Changed — BREAKINGare in 2.5.0, a minor; none has ever shipped in a patch. FourteenFixed — BREAKINGshipped in both tiers. And 2.5.0's ten did not cause its minor — the threeChangedin the same release already forced it. No release has ever taken a minor for aFixed — BREAKING.The four
BREAKINGmarkers that appear outside a heading (:532,:1415,:1488,:1848) eachsit under a
Fixed — BREAKINGheading and elaborate it, so the headings are a complete index.The split is not arbitrary.
Fixedsays the documented behaviour was not being delivered and nowis — the consumer relied on something never promised.
Changedwithdraws a promise that was kept.The decision
Changed — BREAKINGforces a minor. A release whose breaking entries are allFixed — BREAKINGmay be a patch.8–12 minors/year cap, the annual major, the LTS line, and the migration-guide obligation on a
breaking minor. ADR-0027's constraint on removing public MIT types is untouched.
change. An entry that cannot say which documented behaviour it restores is a
Changed.The cost is stated rather than mitigated: a label now carries the release tier and nothing
verifies it. No test parses
CHANGELOG.md, andpublish.ymlreads only## [<version>]headings.The mitigation is D3 plus the callout text a reviewer can check against the diff — deliberately a
review property, because a parser over prose headings would fail toward blocking a correct release.
Also in this PR
#286's CHANGELOG entry gains its
BREAKINGlabel — the ruling that was left open. A save inflight at shutdown is now cut short when the host's budget expires instead of running under a token
nothing could cancel; that is observable to an operator, which is the threshold #284 was labelled
under. It is a
Fixed, so it does not move the tier: 2.6.0 is already a minor from its twoChanged — BREAKING.Plus the serial coupling every ADR-adding PR carries:
README.md58 → 59 ADRs, its claim-registryrow, and the catalog row in
docs/decisions/README.md.One apparent counterexample, resolved
ADR-0048 D7 reads "a route fix that changes the meaning of a public property is an API decision,
not a patch". Its next sentence settles the sense — "never applied inline" — so "patch" there is
an ad-hoc code change, not a release tier. The case it names resolves it anyway:
SpeechmaticsOptions.BaseUrishipped as one of 2.5.0's threeChanged — BREAKING, in a minor. Afourth time the unwritten rule was followed.
Debt this surfaces, recorded not resolved
ADR-0028 obliges a minor carrying a breaking change to ship a migration guide. 2.6.0 will be one and
only
docs/guides/audiosocket-wire-format-migration.mdexists, written for #302. #291'sAriOutboundListenerchange has none.Verification
Tests/Verbara.Sdk.OpenTelemetry.Tests— 31 passed, includingThePublishedAdrCount_ShouldMatchTheDecisionsOnDiskandTheDecisionCatalog_ShouldListEveryAdrOnDiskTests/Verbara.Sdk.Governance.Tests— 129 passedopenspec validate --all --strict— 13 passed, 0 failed🤖 Generated with Claude Code