I think the key idea here is that if a change is "breaking" or not it has nothing to do with whether or not the change seems a minor or major change, and has nothing to do with the breadth of scope or complexity of change is.
Instead, the only thing that determines if a change is break is: does the code that used to work before the change no longer work after the change?
It is up to you how strict it is to be. For example, is it okay to break the code that explicitly I shouldn't have worked, as originally, a list did not appear as allowing nulls, but due to an error, was it not verifying them correctly? That depends on you in your change management policy: some believe that mistakes are fine if they break the code, some say that if there were any conceivable code that would have worked before (even if you have no proof that such code really exists), Then change should be considered breaking. Again, that depends on your policy to decide how to handle it.
If you have a policy that says the major versions may be failing but the minor versions may not, then yes, any change that is defined as a change means that you cannot include it in a minor version. If that is the only thing that changes, then yes, that means you would have to make a major version change to include it.
This problem is created because you have combined two orthogonal things: if a change is minor or major and if it is breaking or not. Because one depends on the other, it means that something has a smaller scope but is broken, it promotes a major change. However, this is not a mistake, it is an intentional feature of this style of semantic versions.
However, there is a way to avoid some of this in the future, which is this: if a class is generic or diffuse in what it allows and admits (and List is an example as diffuse as it can find), if you want to be more demanding than that, it is often better to serve it by creating a container or inheriting a class, that is, a
PickyList with all kinds of rules about what he accepts and what he doesn't. It can even include a warning that
add() the rules may change over time due to changes in external rules (common in regulatory environments or when external restrictions are not defined in the same code; imagine having a class that is added to a portfolio of financial market orders, for example ), and thus all consumers of this The function must ensure that it is not assumed that add will succeed and handle errors / failures properly.
In the end, remember the wisdom behind why important changes must be handled with care and an additional burden: code breakdown and hard-to-update libraries are a huge problem in IT today. The level of difficulty that important projects have when trying to keep the updated versions every few years is unpleasant and, frankly, crazy. "Managing the hell of the software version" has joined "capacity for Google" in my list of skills that every software developer must have and yet never appears in the job description.
Anything you do to fight the good fight against the rot of the code and the infernal version of the infinite march of "breaking change with questionable benefits or necessity" is a sacrifice towards the greater good, and I thank you for your service in this valuable cause.