So what should upstream do? After all, the premise must be that the upstream does not control or even know about all the clients! The entire point is to separate the concerns, so how could upstream know if a bug fix is a breaking change if it passes the internal regression tests?
Of course they can't know without asking downstream, and hence the use of release candidates.
I don't and wouldn't even really use it anyways. Easier to just follow semver and bump minor instead of patch if there's a remote possibility of anything breaking
Regarding patch releases, the only thing that has "absolutely no chance of breaking anything" is no change at all – keeping the exact same version. Deciding what constitutes a patch-release bug fix is a matter of exercising good judgement about what won't (reasonably) break people's code. That could definitely be clarified in the SemVer spec. Asking yourself "is there a chance that this change might screw someone over?" and if so, how crazy was what they were doing?
- patch: forwards and backwards compatible – only bug fixes, no new features, no changing existing features.
- minor: backwards compatible – new features allowed, but old code should keep working.
- major: all bets are off.
This is pretty much what the SemVer spec says, and it's hard to imagine what else you could do. The significance of forwards compatibility for patch versions is that if you bump a patch version and find that it was problematic, you should be able to revert back to a lower patch version without breaking new code that's been written since the bump.
The thing is, it's still a judgement call what constitutes a bug fix. If you're fixing a segfault, that's a no brainer – no one (sane) was relying on something segfaulting. If you're changing a behavior from one potentially reasonable behavior to the one that was actually documented, then, yeah, that might not be "just a bug fix" – people might be relying on it. So we're super conservative about "fixing" even fairly bad behavior in patch releases. Still, the only way to make sure an application keeps working exactly the same is to use the same exact versions – down to the patch level.
The FerVer "spec" is barely coherent, I'm not sure how anyone could consider that something to follow. SlimVer basically just gets rid of things in SemVer that you don't have to use anyway. Pre-release versions – especially release candidates – are incredibly useful. You tag 1.2.3-rc1 and if no issues crop up in a week, then that becomes your 1.2.3 release (1.2.3-rc1 and 1.2.3 are exactly the same); if issues do crop up, then you fix them and tag 1.2.3-rc2 in a week and repeat.
I also think that pre-1.0 versions are useful: just treat the minor version like a major version. For 0.1.2 => 0.1.3 you only fix bugs but for 0.1.3 => 0.2.0 anything goes. There's no point in doing feature-only, backwards compatible releases while you're still working out the API for something, and 0.x releases are for precisely that kind of exploratory period.