In a shared policy rule library, what makes a change a major SemVer bump rather than a minor one?
answer
- compatibility means verdicts, not signatures
- did something that passed now fail
- purely additive can still be breaking
- loosening a check is not breaking
- the number cannot describe strictness
basics
~20 sAnything that turns a previously passing input into a failure: a new blocking rule, a tightened condition, or a stricter default. Changes that cannot newly fail anything — a fix that only loosens a check, a rule shipped switched off — are minor or patch.
solid answer
~50 sThe consumers of a rule library are pipelines, not compilers, so compatibility here is about **verdicts**, not function signatures. A change is major if input that used to pass can now fail: adding a blocking rule, tightening an existing one — say the container-resources rule moving from requiring `requests` to requiring requests and limits — or making a default parameter stricter. A change is minor or patch if nothing that passed before can now fail: a rule shipped disabled by default, documentation, or a fix that stops a rule flagging cases it should not have. That last case matters: SemVer describes compatibility, not security strictness, so a loosening fix is a patch even though it weakens the ruleset. Consumers therefore need a per-rule changelog alongside the number, and a major bump reads as "schedule remediation time", not "update your call sites".
go deeper
Recall the three parts of a version and that major signals a change that can break the teams consuming the library. You are not expected to classify borderline rule changes yet.
Explain that a rule library's compatibility surface is the set of inputs it rejects, so a purely additive rule is a breaking change while a fix that only loosens a check is not.
Demonstrate the release judgment: evaluate the candidate version against real manifests, count what newly fails, pick the bump from that number, and write the per-rule changelog consumers plan work from.
Own the contract with consuming teams: what a major bump obliges them to do, how much notice they get, and why a version number can never tell them whether the ruleset got stricter or weaker.
## What the version number is describing Semantic versioning splits a version into MAJOR.MINOR.PATCH: major for changes that are incompatible for consumers, minor for backward-compatible additions, patch for backward-compatible fixes. Applying it to code libraries is familiar — an incompatible change breaks the build at a call site. A rule library has no call sites. Its consumers are pipelines and gates that feed it documents and receive verdicts, so its **compatibility surface is the set of inputs it rejects**. Read it that way and the classification becomes mechanical: if input that passed under the old version can fail under the new one, the change is breaking, whatever it looks like in the source. ## Worked through one rule Take the rule that containers must declare CPU and memory resources. | Change | Can something that passed now fail? | Bump | | --- | --- | --- | | v1.9 → v2.0: rule now requires `limits` as well as `requests` | Yes — every manifest with requests only | MAJOR | | Add a new blocking rule for a different property | Yes — anything violating it | MAJOR | | Add a rule that ships switched off unless a consumer enables it | No | MINOR | | Make a default threshold stricter | Yes | MAJOR | | Fix a rule that wrongly flagged init containers | No — it only stops failing things | PATCH | | Improve the message a rule prints when it denies | No | PATCH | The row people get wrong is the third-from-last pair. "We only *added* a rule, we removed nothing" feels additive and therefore minor. For a rule library it is the single most breaking thing you can do: every consumer's green pipeline can turn red on their next run, with no change on their side. ## The subtlety SemVer cannot express A fix that removes a false positive is a patch, because no passing input starts failing. But it also makes the ruleset weaker in security terms — after the fix, some genuinely bad input that used to be caught may now sail through, if the "false positive" was actually a correct denial mis-triaged. So the version number tells a consumer **how disruptive an upgrade is, and nothing about whether posture got stronger or weaker**. That is why the number is never enough on its own: ship a changelog written per rule, saying for each changed rule id what it now rejects that it did not before, and what it now accepts that it used to reject. Consumers plan work from the changelog and take the version number as a schedule signal. ## Deciding the bump with evidence Before tagging a release, the useful measurement is blast radius: evaluate the candidate version against a corpus of the manifests and plans currently in use across the estate, and count how many newly fail. Zero new failures on real input is a strong signal the change is genuinely additive-but-inert; hundreds of new failures tells you the bump is major *and* tells you how much remediation work you are about to hand out, which is the number the release conversation actually turns on. ## Immutability is not optional Whichever number you land on, a published version is frozen. Re-publishing different content under a version that consumers already resolve destroys the one property versioning exists to provide: the same pin evaluating the same document twice gives the same verdict. It also poisons any record of the form "this change was evaluated with v2.3", because v2.3 no longer means one thing. Fix forward with a new version, always. ## What consumers do with the number Because the breakage manifests as red builds rather than compilation errors, the contract with consuming teams is different from a code library's. A minor or patch bump can be taken automatically — bots raise the pin bump, nobody reads it. A major bump needs notice, a changelog, and usually a window in which the new rules are visible but not yet the authority in the pipelines that will be worst hit. Getting that contract written down is what makes teams willing to stay near-current instead of pinning at whatever version they onboarded with and never moving again.
- A fix stops a rule flagging init containers. Which bump is that?A patch. Nothing that passed before starts failing, so it is backward compatible for every consumer and can be taken automatically. Note what the number hides: the ruleset got weaker, and only a per-rule changelog says so. If the flagging was actually correct, the fix quietly removes coverage under the safest-looking version bump you have.
- Why can a strictly additive change break every consumer at once?Because consumers consume verdicts, not interfaces. A new blocking rule leaves every existing rule untouched and still turns green pipelines red on the next run for anything violating it. Nothing on the consumer side changed, which is exactly why it needs the loud version signal.
- How would you estimate whether a candidate release deserves a major bump?Evaluate it against a corpus of the manifests and plans actually in use and count newly failing ones. Zero says the change is inert in practice; a large number says major, and also tells you how much remediation work the release hands out, which is the number the release decision really turns on.
saying these in an interview costs you the question
- Calls adding a new blocking rule minor because nothing was removed
- Reads the version number as describing security strictness
- Re-publishes changed rule content under an existing version
- Bumps major for a fix that only stops false positives