Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify minor and patch versions #588

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

magjac
Copy link

@magjac magjac commented Jul 4, 2020

This is not a "substantial" change to the specification, hence not an RFC. It just clarifies aspects of the MINOR and PATCH versions that could easily be misunderstood when reading a few of the sections in isolation, but becomes clear when reading the whole document and the intention is understood.

In short, these changes make clear that changes that are neither changes to the API nor bug fixes MAY be released as a PATCH version. It is only backwards compatible changes that MUST be released as a MINOR version (at least) (although this exact sentence is not part of the changes). Such a change could be e.g. a performance improvement in the private code. Without the changes in this PR it's easy to think that only bug fixes MAY be released as PATCH versions (again; if you read the sections in isolation).

This change is an attempt to minimize the changes needed to add these clarifications while still keeping the text as short and concise as possible. With a larger change, it would be possible to make the text even shorter by removing the references to bug fixes. Let me know if you prefer this and I will change this PR accordingly.

Here are some references to issues opened in the past because of the currently somewhat ambiguous formulation:

@alexandrtovmach alexandrtovmach added RFC Request for comments state for next version update Update current idea/rule labels Jul 15, 2020
@Tieske
Copy link
Contributor

Tieske commented Jul 16, 2020

It might be easier if the definitions are defined positively instead of negatively;

  1. a MAJOR version is a promise to the user
  2. each MINOR version is an additional promise
  3. a PATCH version, is a sequential improved implementation of the promises made

(such that it distinguishes between the promises made and the implementation of those promises)

@yukihiko-shinoda
Copy link

Hi, I recently got interested in this issue.
If my talk is not appropriate for this thread, take me to appropriate issue.

I think that some case should be not PATCH but MINOR.
And it needs to clarify what is the intention of dividing MINOR and PATCH,
and the place for it is here or #339 .

Test case

I summarized the discussion so far into a test case:

Update content Expect
Refactor for readability #146 #215 #415 MINOR / PATCH
Refactor for performance #146 #415 PATCH
Update minimum version of dependency #213 #337 #341 #522 #526 #534 #560 PATCH
Update test code (is it required to deploy?) #313 PATCH
Enhance document #215 MINOR
Fix document ?
Fix / Update CI /CD pipeline ?

(If I had mistake, please point out)

However, is this really good from the user's perspective?
Can users pinning with minor versions keep Safety?

Note that I don't think that this update have to be able to solve all cases digitally right now.
The important thing is to approach to the correct answer.

What is the intention of dividing MINOR and PATCH

Isn't this to notice users the difference of kind of risk?
It's obvious if we go back to Why Use Semantic Versioning.

Why Use Semantic Versioning?

Why Use Semantic Versioning? | Semantic Versioning 2.0.0 | Semantic Versioning

  • becomes easy to communicate your intentions to the users of your software
  • can make dependency hell a thing of the past
  • can safely specify dependency
  • provide you with a sane way to release and upgrade packages without having to roll new versions of dependent packages, saving you time and hassle

What kind of risk does each version intend?

Shouldn't user understand as following?

Version Risk
MAJOR New bugs or issues may be effect when update, API you are using may be unavailable when update
MINOR New bugs or issues may be effect when update
PATCH New bugs or issues may be effect when update, Bugs may be effect when keep using current version

Test case from user's perspective

Update content Expect
Refactor for readability #146 #215 #415 MINOR
Refactor for performance #146 #415 depend on impact
Update minimum version of dependency #213 #337 #341 #522 #526 #534 #560 PATCH
Update test code (is it required to deploy?) #313 MINOR
Enhance document #215 MINOR
Fix document PATCH
Fix / Update CI /CD pipeline MINOR

Because users pinning with minor versions want to keep Safety.
Safety means that "to avoid risk that bugs may be effect when keep using current version".

Sample of how user use PATCH and MINOR version

@magjac
Copy link
Author

magjac commented Oct 25, 2020

@alexandrtovmach I noticed that you added the RFC label to this PR. Would you like to comment on why? As I've specifically stated in the description, I designed it to not require an RFC according to https://github.com/semver/semver/blob/master/CONTRIBUTING.md.

This PR does not include:

  • Changes to the meaning of the specification.

This PR does include:

  • Small wording clarifications that do not impact the semantics of the specification.

I'm here talking about the PR itself, not what other users have written in it.

If you disagree, please let me know why and I will close it and perhaps come back with another PR the does not require an RFC.

I also noticed the update label that means "Update current idea/rule". Does this mean you want me to make an update or what does it mean?

@Tieske
Copy link
Contributor

Tieske commented Oct 25, 2020

Small wording clarifications that do not impact the semantics of the specification.

It does impact the semantics, as it severely reduces the scope to being API only.

As for the changes themselves, I would rather describe them more abstract;

  • MAJOR is a promise to the user
  • MINOR is an additional promise, without compromising the MAJOR one
  • PATCH is a sequentially improved implementation of the (additional) promises made

@magjac
Copy link
Author

magjac commented Oct 25, 2020

It does impact the semantics, as it severely reduces the scope to being API only.

@Tieske Not at all. The API is what semver is all about. I suggest you read https://github.com/semver/semver/blob/master/semver.md#introduction.

@Tieske
Copy link
Contributor

Tieske commented Oct 25, 2020

@magjac been a while since I looked at it and the spec is indeed littered with API references. So apologies for the noise.
The comment was based on the previous efforts, to always keep it open for other use than just software projects.

@magjac
Copy link
Author

magjac commented Apr 4, 2021

I noticed that @alylynn1426 approved these changes a while back. Could we get them merged now?

@ljharb
Copy link
Contributor

ljharb commented Apr 4, 2021

@magjac the approval is gray, not green, which means that isn’t a repo collaborator, just a normal user.

@magjac
Copy link
Author

magjac commented Apr 4, 2021

Oh, I see. Let's hope a collaborator has time to look at it then. It should be pretty uncontroversial. If not, I'd like to know why.

Copy link

@Vienna-88kasun Vienna-88kasun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update

@alexandrtovmach
Copy link
Member

@magjac I've putted RFC label to all PRs that changes body of specification, so nothing personal =)
I'm unsure, that this specification is community driven right now, and have some thoughts about it, maybe we can have two versions official and community driven. For now, I can't merge it 😢

@magjac
Copy link
Author

magjac commented Apr 10, 2021

Thanks @alexandrtovmach. I'm not really in favor of having two versions of the specification. I don't expect this PR to be merged right now, but I would like to have some comments on it from the maintainers. Do you agree or disagree that this just clarifies what the spec already says? Do you agree that the specification would benefit from this clarification or not?

Do you have a process for RFCs or does this just mean that my suggestion is postponed indefinitely?

@magjac
Copy link
Author

magjac commented Jul 4, 2021

This MR is now celebrating it's first anniversary without a single comment from anybody of the seven people in "the SemVer team".

@alexandrtovmach Can you please remove the RFC label from this MR? I've already stated why I think it's incorrect. If you disagree, please point me to what it is in the Semver Governance Model that makes you think that this MR needs to follow the RFC process.

If you do not remove the RFC label, I'm going to close this MR, because I don't think that the seven members of the SemVer team will ever reach consensus to merge it, given that none of them has even commented it for a whole year.

I think that would be a pity however since, unlike many other old and open MRs, this MR just makes the specification clearer and more easy to understand without changing anything about it's true meaning, which shouldn't be controversial.

@Tieske
Copy link
Contributor

Tieske commented Jul 5, 2021

Though I'd rather see the different wording of promises and implementations as mentioned (twice?? what was I thinking) above, I think this should be merged, as it is indeed just small changes in wording, non controversial, and making it more clear.

Also wrt to the progress, I think @magjac has a point, despite that I think that specs like SemVer should be slow moving, a simple thing like this is taking too long now.

semver.md Outdated
1. MINOR version when you add functionality in a backwards compatible
1. MINOR version when you add functionality to the API in a backwards compatible
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where but to the API could you possibly add functionality?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, but since this is the terminology used by the specification elsewhere, I thought it was appropriate here as well.

  1. MAJOR version when you make incompatible API changes,

where but to the API could you possibly make incompatible changes?

I can remove this change if it makes it easier to get this PR merged. The important part is to make clear that you can make patch-level changes which are not bug fixes. The specification's ambiguity regarding this has made people come to the wrong conclusion that changes that are neither changes to the API, nor bug fixes MUST be released in a MINOR version. My proposed wording that you commented on makes this mistake almost impossible so IMHO it's strictly better with it than without.

@magjac
Copy link
Author

magjac commented Dec 4, 2021

@jwdonahue Since you're one of very few people who actually bothers to comment on PRs, could I interest you to have a look at this one? It doesn't actually change any meaning of the spec. It just tries to make a few things clearer that has confused a lot of people in the past. It has, IMHO, wrongfully been tagged RFC.

I haven't been able to get a comment from any of the maintainers although this PR has been open for more than a year so a comment from you would be highly appreciated.

@jwdonahue
Copy link
Contributor

Depending on what the API is, it may actually be possible to fix it in a backwards compatible way. I think that limiting patch bumps to changes in implementation code is over-restrictive. Consider how you would apply SemVer to correct spelling or grammatical errors in the SemVer spec. The text is nothing if not an interface, but it does have a kind of interface/implementation duality to it as well.

Not all functional additions involve the API. Consider adding telemetry to an application. Sure it's a potentially visible program output, but that doesn't mean it's a supported API. I add/remove telemetry to help improve quality and reduce support costs, but I reserve the right to modify or even remove it. It's not part of the API as I have defined it for my product. Adding or removing telemetry features doesn't fix any bugs, but they are functional changes that carry more risk than your average bug fix, so I will bump the minor version field.

I think this proposal is too focused on the API. We already know that the spec is overly API focused as it is, when the reality is that all of the maintainers and most of the implementers are packaging tool owners. Most of us version collections of interfaces, implementations and data, not API's.

I think you're focused on some of the weak points in the spec, but also some of the hardest sections to change without inadvertently breaking something. Few of us really love these bits of the spec, but most of us are loathe to change them much, because it is so hard to get consensus for any specific change. I don't think minor tweaks are valuable enough to take the risk. What is needed in these areas of the spec is to refocus it on the inherent contractual nature of whatever is conjured in the minds of the reader, by the API placeholders in this document. That would require a major version bump however, and it is unlikely the maintainers would be interested in it.

@magjac
Copy link
Author

magjac commented Dec 4, 2021

Depending on what the API is, it may actually be possible to fix it in a backwards compatible way. I think that limiting patch bumps to changes in implementation code is over-restrictive.

I think that you may have misunderstood. This PR is in no way suggesting that. It's main objective is to clarify that it's not only bug fixes that MAY be released as patch releases. Other changes that are not changes to the API MAY also be released as such.

I've had numerous discussions with people who incorrectly think that changes that are not bug fixes MUST always be released as at least a minor version, even if they're not changes to the API, e.g., a performance improvement or just internal refactoring.

I think this proposal is too focused on the API

It's exactly as focused on the API as the spec itself currently is. This PR is orthogonal to what is being versioned or what the term API means.

@jwdonahue
Copy link
Contributor

@magjac it was very late. The two sentences you quoted are two distinct thoughts and probably belong in separate paragraphs.

It's exactly as focused on the API as the spec itself currently is. This PR is orthogonal to what is being versioned or what the term API means.

Ya, I think that was my main criticism. If it's already too focused on "API" and doesn't fix the "exactly what are we versioning" problem, then how is this an improvement?

MINOR version when you add functionality to the API in a backwards compatible

You add a reference here to a weakly defined term in the spec. Not all functional additions/changes are at the interface level. It is generally accepted that in addition to the breaking/non-breaking change semantics, there's a High.Medium.Low risk overlay inherited from long standing practice. You can and should bump minor if you make substantially higher risk implementation changes, even if you did not add any new interface surface.

PATCH version when you make backwards compatible bug fixes or other changes
not affecting the API

Another new reference to API. Given the broad and incomplete definition of API in the spec, it could be argued that any visible change in behavior is an API change, therefore; under your proposed wording, bug fixes are banned. But then there's #6:

Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards compatible bug fixes are introduced. A bug fix is defined as an internal change that fixes incorrect behavior.

Which pretty much says what you proposed above. But you change to that:

Patch version Z (x.y.Z | x > 0) MUST be incremented if only backwards
compatible bug fixes or other changes not affecting the API are introduced. A
bug fix is defined as an internal change that fixes incorrect behavior.

Just makes things worse by adding yet another reference to API. Let's consider what the patch version really means from both software component publisher and consumer perspectives.

  • Publisher bumps the patch number when they fix something that has to be released outside the normal update cadence, or when that cadence does not yield any new interface surface. They see it as a medium risk, low reward activity.
  • Consumer pulls patch updates as soon as they are released, in order to improve stability and security of their systems, or to pass it along to their consumers. They see it as a low risk, high reward activity.

Now add your changes and think through the dynamics:

  • Publisher bumps the patch number for any random non-interface affecting change they wish. They see it as a medium risk, low reward activity.
  • Consumer stops pulling patch updates automatically, they see it as a medium to high risk and potentially low reward activity.

So if you overload patch for anything but bug fixes, you break the SemVer contract. But not all bug fixes are in the implementation code. Some of them are in the documentation, which is part of the API. If you correct the spelling in a comment describing an interface, it does not increase or diminish the interface surface, but it does modify it. Hence my dislike of the existing and proposed wording.

@magjac
Copy link
Author

magjac commented Dec 5, 2021

@jwdonahue

From the specification:

Once you identify your public API, you communicate changes to it with specific increments to your version number.

This tells me that the version numbering is all about the API and nothing but the API, even if the API term is loosely defined. Therefore any references to the API that is added to the specification cannot make it more focused on the API, since is already 100 % focused on the API.

That said, the the main objective of this MR wasn't to clarify that changes refers to the API, since I thought this was obvious and uncontroversial. It was just a means to be able to clarify what MAY be released as a patch level change.

From the same paragraph in the specification as above:

backwards compatible API additions/changes increment the minor version

From the very top level of the specification:

  1. MINOR version when you add functionality in a backwards compatible manner,

My interpretation of this and reading the rest of the specification is that the intention of the minor version is to signal to the consumer that the functionality of the API may have been modified in a way that might add value to the consumer. My assumption has always been that any changes that are not in this category MAY be released as patch version. You write:

So if you overload patch for anything but bug fixes, you break the SemVer contract.

If you are correct, my assumption is clearly incorrect. To test this I would like to hear your and others' opinions about how each change mentioned below should be released, since IMO none of them fit in any of the categories in the initial specification:

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards compatible manner, and
  3. PATCH version when you make backwards compatible bug fixes.

The changes:

  1. Adding comments to the code base which are unrelated to the API.
  2. Changing the implementation of an internal function to make it more efficient.
  3. Renaming internal variables to make the code more readable.
  4. Refactoring the code to make it build faster.

None of these make incompatible API changes, adds functionality in a backwards compatible manner or makes backwards compatible bug fixes. This tells me that this part of the specification is ambiguous and needs to be clarified. As I see it, with your interpretation, (2) needs to be modified and with my interpretation, (3) needs to be modified.

@magjac
Copy link
Author

magjac commented Mar 5, 2022

@ljharb Could I interest you in giving your opinion on how the exemplified changes in my previous comment should be released?

@ljharb
Copy link
Contributor

ljharb commented Mar 5, 2022

Minor isn’t for added value; it’s for added features. Everything adds value, or else why change it at all - iow, the value to the consumer is irrelevant.

Patch absolutely can have things that aren’t bug fixes - patch is, by design, the catch-all for everything that’s not a breaking change nor an addition. However, you could argue that “missing comments” are a bug, altho that’s a pretty silly argument.

@magjac
Copy link
Author

magjac commented Mar 5, 2022

Minor isn’t for added value; it’s for added features. Everything adds value, or else why change it at all - iow, the value to the consumer is irrelevant.

I agree. That was an unnecessary restriction.

Patch absolutely can have things that aren’t bug fixes - patch is, by design, the catch-all for everything that’s not a breaking change nor an addition. However, you could argue that “missing comments” are a bug, altho that’s a pretty silly argument.

Excellent. That is my interpretation too. Do you think that this is already unambiguous in the spec? I don't think so and that's why I filed this PR.

@jwdonahue, you wrote:

So if you overload patch for anything but bug fixes, you break the SemVer contract.

Does this mean that you disagree with mine and @ljharb's interpretation?

@ljharb
Copy link
Contributor

ljharb commented Mar 5, 2022

It’s both already unambiguous in the spec and also how every single ecosystem has interpreted it, with zero exceptions, afaik.

@jwdonahue
Copy link
Contributor

@magjac, just to be clear, I object to all references to "API" in the current spec as it is currently written as well as in your changes. I think for all practical purposes, SemVer is used to version packages, not API's. The biggest problem I have with API is that no one can agree on whether it applies to just the interfaces or the implementations thereof. There are some who think that any observable behavior is the API.

I have consistently argued that how you apply SemVer depends heavily on exactly whatever it is you are versioning and the spec explicitly allows the publisher to decide that. Yet virtually all SemVer implementations apply it to the contents of one form of packaging or another, some of which may actually be interfaces, implementations or data. It is difficult to make changes to the current spec without breaking somebody.

Considering the subject matter, the SemVer spec is very terse. There is a great deal of room for interpretation, and that's probably how it managed to thread the needle between at least a dozen development silos. I think it has to stay like that until the SemVer version ambiguity problem is resolved. There have been effectively three syntactic and two semantic versions of SemVer and there is no effective way to distinguish between any of them. Until that problem is solved, all major and minor changes to the spec should be off the table.

I do not believe that these proposed changes can be considered patch level changes.

@Tieske
Copy link
Contributor

Tieske commented Sep 14, 2023

I object to all references to "API" in the current spec

100% agree.

As for the other parts, most of this is because people "stick a version" on to something without explicitly specifying what it is they are versioning. What is the scope covered by the version. @Jayman2000 example of adding 2 levels is a clear example of that. Adding levels is specific to the context of your version. SemVer will never be able to solve that. You'll have to specify it for your specific product.

@Jayman2000
Copy link

@jwdonahue

As for your game example of adding levels; it's way more nuanced than can or should be laid out in the spec. I don't know the details of your particular game, or it's API's, but adding new levels to a hypothetical game could warrant anything from a major to patch level bump, even if there weren't any "API" changes. Only the publisher and consumers of that particular game and its API's could make a reasonable determination thereon.

I don’t really want the spec to lay out a situation like that. Here’s what I want to know: what does the current version of the spec allow? If I release an update that only adds new levels, am I allowed to bump the patch version? Am I allowed to bump the minor version? Am I allowed to bump the major version?

That’s what I mainly care about. This PR was just a potential way of getting there.


@Tieske

As for the other parts, most of this is because people "stick a version" on to something without explicitly specifying what it is they are versioning. What is the scope covered by the version. @Jayman2000 example of adding 2 levels is a clear example of that.

I disagree. In the example, I had already explicitly specified what I was versioning before I got to the point where it was time to release something. I said

I’m interested in this change because I’m interested in using SemVer on a video game. The API in my case will be a list of classes that can be used when creating custom levels.

What I was trying to say there was “The software using Semantic Versioning is the game, and the public API that that software declares is a list of classes that can be used when creating custom levels.” If I’m not explicitly specifying what I’m versioning in this situation, then how would I explicitly specify what I’m versioning?

Adding levels is specific to the context of your version. SemVer will never be able to solve that. You'll have to specify it for your specific product.

I don’t understand this part. What do you mean by “context of your version”? What does it mean “to solve that”?

@jwdonahue
Copy link
Contributor

jwdonahue commented Sep 14, 2023

@Jayman2000 , is it literally the case that your "API" is defined as a list of classes?

API:
Class1
ClassC
ClassD

Or is it actually something else entirely?

If your definition of API is that weak, then ya, you can make any change you like to whatever those class identifiers happen to reference, but I don't think that's going to be very useful to your customers.

@jwdonahue
Copy link
Contributor

jwdonahue commented Sep 14, 2023

@Jayman2000

I don’t really want the spec to lay out a situation like that. Here’s what I want to know: what does the current version of the spec allow? ...

It allows exactly what it says it allows. You seem to be in favor of it allowing something else.

... If I release an update that only adds new levels, am I allowed to bump the patch version? ...

I already stated that I cannot answer that question without more context.

... Am I allowed to bump the minor version? Am I allowed to bump the major version?

The spec doesn't prevent you from doing anything. If you want to bump one of the versions, go for it. It does not prohibit any particular kind of bump, but it does say what you should bump under certain circumstances and that version triple fields to the right of the field you bump, should be reset to zero. If you claim to be applying SemVer style semantics to your versioning, your customers will have certain expectations based on your statements and their read of the spec. Just don't do anything that will surprise your customers and you should be fine.

@Jayman2000
Copy link

@Jayman2000 , is it literally the case that your "API" is defined as a list of classes?

API: Class1 ClassC ClassD

Or is it actually something else entirely?

If your definition of API is that weak, then ya, you can make any change you like to whatever those class identifiers happen to reference, but I don't think that's going to be very useful to your customers.

No, the API is not literally a statement that says “ClassA, ClassB and ClassC are identifiers that exist, and they do indeed refer to classes.” It would be more like this:

  • ClassA is a class. It has these members.
  • ClassB is a class. It has these members.
  • ClassC is a class. It has these members.

It might also include information about what each class inherits from.


It allows exactly what it says it allows. You seem to be in favor of it allowing something else.

What does it say that it allows? Also, I’m in favor of being able to release an update to a video game that only adds levels while still following SemVer. If that requires changing the spec, then OK. If that doesn’t require changing the spec, then OK.

I already stated that I cannot answer that question without more context.

I’m sorry. I didn’t understand that you had said that. What more context do you need? If you want, I can develop and release example game to provide more context.

The spec doesn't prevent you from doing anything. If you want to bump one of the versions, go for it. It does not prohibit any particular kind of bump,[…]

I disagree. The spec does prohibit particular kinds of bumps. Here are some quotes from the spec:

  • Patch version Z (x.y.Z | x > 0) MUST be incremented if only backward compatible bug fixes are introduced.

    This prohibits you from breaking backwards compatibility or adding features in 1.0.1.

  • Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backward compatible functionality is introduced to the public API. It MUST be incremented if any public API functionality is marked as deprecated.

    This prohibits you from adding features in 1.0.1. This also prohibits you from deprecating API functionality in 1.0.1.

  • Major version X (X.y.z | X > 0) MUST be incremented if any backward incompatible changes are introduced to the public API.

    This prohibits you from breaking backwards compatibility in 1.1.0.

[…]but it does say what you should bump under certain circumstances and that version triple fields to the right of the field you bump, should be reset to zero.

It doesn’t say that you should bump under certain circumstances, it says that you MUST bump under certain circumstances. It also doesn’t says that anything should be reset to zero. It says that some things MUST be reset to zero:

  • Patch version MUST be reset to 0 when minor version is incremented.

  • Patch and minor versions MUST be reset to 0 when major version is incremented.

@jwdonahue
Copy link
Contributor

@Jayman2000 , first, the spec can't force anybody to do anything or prevent them from doing anything (like breaking something), it's just a document full of guidelines. The fact that a prescriptive statement exists requiring a particular version bump under some particular circumstance, says nothing about other circumstances. Yes, the whole point of a patch version bump is for backwards compatible (BC) changes only. There's good reasons for that. But then, if you recompile without making any changes at all, you still have to bump something in the version string, because you can't have two packages with the same version string. My point was that you can bump any of the version fields for no reason at all, or for whatever reason(s) you may have, but if you claim to be SemVer compliant, then your customers will have certain expectations. As long you do not violate those expectations, your fine.

Read the spec and keep in mind that what it does not say, is almost as important as what it does say. There is no prohibition against bumping the patch for reasons other than bug fixes. It can be bad form to do so, but as long you don't break anybody, it's fine.

As for your refined game example:

  • ClassA is a class. It has these members.
  • ClassB is a class. It has these members.
  • ClassC is a class. It has these members.

If that's all your versioning, then as long as you don't change that supposed interface, every repackaging of it is definitely just a patch bump and maybe doesn't even require that. But I think it's a very weak contrivance since in your own statements, you added levels to something somewhere that you apparently consider part of whatever it is you're actually versioning. So you're probably not versioning that specific API. You're probably versioning a collection of interfaces and implementations of one form or another, in which case, the details of what you changed and how they impact your customers, comes into play.

Good theoretical contrivances for the purposes of discussing the many nuances surrounding semantic versioning of any kind, including SemVer, are not going to be trivial. Trivial examples are best suited for elucidating a single aspect, and then only at the expense of ignoring many other nuances.

As I have already said repeatedly, the vague what-if example you provided does not contain enough information to determine the appropriateness of any particular action wrt to SemVer and version bumps. I won't discuss it further without a lot more detail and this is probably the wrong forum for that anyway.

@jwdonahue
Copy link
Contributor

Regarding whether patch should be reserved explicitly for the purpose of bug fixes:

Statements in the summary, introduction and FAQ, are not part of the spec. To the extent that they are part of the SemVer canon, I will say that dogma is not a hill worth dying on (IMO).

6. Patch version Z (x.y.Z | x > 0) MUST be incremented if only backward compatible bug fixes are introduced. A bug fix is defined as an internal change that fixes incorrect behavior.

Says what you MUST do if you only introduced compatible bug fixes. It is mute on whether it is appropriate to bump the patch for any other kind of change, but then we have 7 and 8, which prescribe triggers for the minor and major fields respectively.

I have read the document hundreds of times and spent many hours pondering its language and meaning. As far as I can tell, none of the clauses in the spec are all-encompassing wrt what might trigger any particular version bump, though 7 and 8 are each explicitly more encompassing than the clauses they follow.

There is no explicit or implied prohibition against version bumps, for reasons not explicitly stated in the spec, but if you are seen to make too many arbitrary version bumps, your customers may fill up your mailbox or issues queues with their complaints.

I think there are many of us who prefer that bug fixes generally be released as patches first, and of course; included in subsequent minor and major updates, where relevant. Bug fixes should generally be the safest kind of changes to accept and there are a lot of systems out there that will snap them up automatically, especially if the component has an appreciable security surface. So it's in all our interests to discourage patch bumps that are not bug fixes, but it's probably also in our interest not to forbid them.

@ljharb
Copy link
Contributor

ljharb commented Sep 14, 2023

It is indeed prohibited to add new things in a patch, because adding new things MUST be a minor or higher.

@jwdonahue
Copy link
Contributor

jwdonahue commented Sep 14, 2023

It is indeed prohibited to add new things in a patch, because adding new things MUST be a minor or higher.

Only if you add something new to the defined "API" and then only because of 7 & 8. This is where the API/Package duality of the spec comes into play. SemVer is mostly implemented by packaging tools and the thing we are versioning is consequently more than just the API in many cases, but the rules mostly apply to that which affects the API and in many cases, its implementation. It is possible to add things to a package that really have no impact on what the API does, but maybe the publisher wants to ensure that the change is adopted quickly. The spec does not say thow shalt only bump patch for bug fixes.

@jwdonahue
Copy link
Contributor

@ljharb , consider what happens if I recompile the product using the latest tools. There are cases where a publisher will want to repackage and publish those new bits. Now they must have a new version, but they've added nothing to the product and haven't fixed any bugs. Perhaps it's a baseline release in preparation of adding features that only the new tooling could enable. It wasn't a bug and there's no new features, but the product is somehow better, or the publisher just needs to expand the user base prior to future releases. Whether you call it a bug fix or a new feature can be rather subjective at times.

@ljharb
Copy link
Contributor

ljharb commented Sep 14, 2023

It can, but once the determination is made, semver dictates what you're permitted to do.

@jwdonahue
Copy link
Contributor

There's even a FAQ (https://semver.org/#what-should-i-do-if-i-update-my-own-dependencies-without-changing-the-public-api) that strongly implies one reason to bump the patch that isn't a bug fix.

@ljharb
Copy link
Contributor

ljharb commented Sep 14, 2023

If you're updating the dependencies at all, then they must have had at least a patch change you need, otherwise why would you bother? The important point is what kind of change it is for your project - and once that determination is made, semver is quite specific.

@jwdonahue
Copy link
Contributor

I might also want to stay current. Not every update I take is to fix a bug that's passed through to my customers, I just don't want to allow my product to get stale. I call that a patch, not a bug fix.

Hmm... maybe we should update 6 and the summary. The fact that non breaking changes that do not add to the API surface or include functional changes to it, is implied by the current wording of the spec and surrounding language, maybe that should be made more explicit?

@ljharb
Copy link
Contributor

ljharb commented Sep 15, 2023

Sounds like a good improvement; I’ll include it in my upcoming rewrite.

@Jayman2000
Copy link

Jayman2000 commented Sep 15, 2023

If that's all your versioning, then as long as you don't change that supposed interface, every repackaging of it is definitely just a patch bump and maybe doesn't even require that.

Hmm... maybe we should update 6 and the summary. The fact that non breaking changes that do not add to the API surface or include functional changes to it, is implied by the current wording of the spec and surrounding language, maybe that should be made more explicit?

These two quotes answer my question, thank you. Sorry for all the trouble. I wasn’t trying to be obtuse or to create a “gotcha” situation. I just didn’t do a very good job of asking my question.

@magjac
Copy link
Author

magjac commented Sep 17, 2023

The fact that non breaking changes that do not add to the API surface or include functional changes to it, is implied by the current wording of the spec and surrounding language, maybe that should be made more explicit?

@jwdonahue @ljharb I'm glad you seem to agree that this is necessary, since this is exactly what this PR tries to do and the reason I submitted it.

@jwdonahue
Copy link
Contributor

jwdonahue commented Sep 17, 2023

I don't think this PR improves things. What is needed is some explicit language around packages, interfaces, implementations, behaviors. and config/meta/other data. And all that needs to be as short and simple as possible, while remaining silo agnostic. The intro and summary need complete rewrites, dropping all language regarding dependency hell, and adding some discussion around ingestion safety and what that means in various contexts.

On top of that, the FAQ needs to be expanded upon, and it wouldn't hurt if there was a "sanctioned" annotated version of the spec. Perhaps several annotated versions targeting each of several of the major silos and what the spec means in relation to common and best practices in each of them.

I have taken some stabs at some of that in the past and always ran into the issue that it can't really be done without breaking somebody. A comprehensive rewrite will require a major version bump, even if we try really hard not to break too many things.

@Jayman2000
Copy link

I don't think this PR improves things.

Thank you for making your strong objections to the term API and to the phrase “Bug fixes or other changes not affecting the API” known. Without your input, we may have never realized this PR’s drastic unintended consequences. At the same time, @magjac did not say that this PR improves things in their most recent comment. Instead, they said

[…]this is exactly what this PR tries to do and the reason I submitted it.

We’re trying our best here, but we’re really struggling. Do you have any suggestions for how we could clarify that patch versions are not limited to bug fixes?

@jwdonahue
Copy link
Contributor

@Jayman2000 wrote:

Do you have any suggestions for how we could clarify that patch versions are not limited to bug fixes?

Yes, I wrote:

What is needed is some explicit language around packages, interfaces, implementations, behaviors. and config/meta/other data.

And as I have also stated here and in many other threads on this board, that it is hard to do those things without a substantial rewrite. It requires bumping the major version, which cannot be done until the SemVer version disambiguation problem is solved. I did start some work on the later a few years back with VersionMeta and VersionSchema. I even stood up a an LLC to wrap the ensuing products in, but I've been to focused on padding my retirement funds the past few years to make much progress on those. I am not here to throw sand into the works, I am here to prevent more of it from clogging the works before we can replace the mechanism.

The problem starts with the introduction of "API" in the document summary and the statement that it's up to the publisher to define what that is. While the introduction and FAQ are not part of the specification, they do contain content required for the interpretation of the spec. Basically, the spec is not 100% self contained. This would never be accepted by a proper standards body. Summaries, introductions and FAQs are meant to be written after and refer to a specification that is complete without the presence of those things.

While Dependency hell problems had been around for as long as humans have assembled things with parts they did not make locally, it became a really serious problem in the Web development world around the turn of the century; due to many factors related mostly to the explosion of high complexity, interdependent systems and newbs in the development community. This was doing damage to brands, personal reputations and the economy like buckshot fired into a crowd, so the shotguns came out to fight the problems on every front we could think of.

I don't think the original SemVer document was ever intended to be a proper formal spec. I think it was intended to encourage more consistent use of the simplest syntax and basic rules that could be applied to convey a modicum of useful information to consumers of software products. It may have been entirely focused on GitHub's own internal developers at the time Tom Preston-Werner wrote the original.

It was probably strongly motivated by the fact that most (all?) Jav* runtime environments were incapable of side-by-side deployments of different versions of the same code, and the fact that one product running in the environment could be broken by another product's seemingly unrelated dependency updates. This was not a common problem in the Ada, assembly, C/C++ and Pascal worlds, where diamond point dependency issues dominate and usually surfaced at compile/link times and pace is slower. In the Java* environments, you could build, test, deploy and run an app for a long time before someone came along and patched some unrelated app that brought in an unanticipated breaking change that would bring down several other apps. It basically recreated the DLL hell problem in a new format.

I am sure there's a lot more, and more detailed history to the beginnings of SemVer, but I don't have the time to dive into that here or probably ever. The point is, the spec is, probably intentionally, loose, leaving it open to interpretation. Many of us see that as a benefit. It's probably the primary reason that something like SemVer has been adopted so widely. That wide adoption however is the reason you can't really tighten the spec much, without breaking somebody. There are details around how it is applied and enforced that varies from one silo to the next. They all encourage semantic versioning and the SemVer syntax and the spirit of the SemVer semantics, but the devils in the details. Many, support other syntaxes and semantics as well.

So yes, I do have ideas on how to fix the problems, but I don't think there's an easy fix involving a few tweaks in wording here or there. As it stands, the document is open to a fairly wide range of interpretations and those that disagree on one point or another, tend to have skin in the game in different silos where their opinions are very relevant. So we compromise and live with the implications because there are risks involved with more explicit language.

@Jayman2000
Copy link

Do you have any suggestions for how we could clarify that patch versions are not limited to bug fixes?

Yes, I wrote:

What is needed is some explicit language around packages, interfaces, implementations, behaviors. and config/meta/other data.

Why is any of that needed in order to clarify that patch versions are not limited to bug fixes? Why couldn’t you change point 6 to say this:

  1. Patch version Z (x.y.Z | x > 0) MUST be incremented if only backward
    compatible bug fixes are introduced. A bug fix is defined as an internal
    change that fixes incorrect behavior. It MAY be incremented if other changes are made, but those changes can’t be minor or major level changes.

@jwdonahue
Copy link
Contributor

You reference clauses 7 and 8 in 6, both of which are about API changes, so you really do have to take all three in conjunction with each other, and you've basically created a backdoor we can drive trucks through at the patch level. If someone defines their API as you did in the hypothetical above, then even breaking implementation changes would be allowed, because it wasn't part of the API. In order to fix this problem, we have to eliminate a bunch of ambiguity around what is an API, and what is "other changes".

Under the current language, it is implied by the text and common practice, that you can make NB changes that only require a patch bump, so nothing is really broken enough to be worth the effort of changing the text. The essential rule of thumb is; don't increase risks to consumers with patch level version bumps. What is actually a breaking or NB change is dependent on what it is you are versioning, and that varies between silos. In some environments, there are hard lines between interfaces and implementations, even to the point that they are versioned independently of each other, in others; it's very difficult to draw the line between interface and implementation.

In most, but not all cases, we're really applying a version number to a package; or collection of things, that could contain one or more interfaces, implementations and data sets. It seems to me to be extremely difficult to cover that range of use cases more explicitly, without requiring a major version bump on the SemVer version string. I think this, because I've tried it, and I always come back to the need to be more explicit about what an API is and that removes a commonly accepted feature of SemVer, namely, that anybody can define API to mean anything at all.

@jwdonahue
Copy link
Contributor

I think the reality is that there are very few corner cases where non-bug, non-breaking changes do not warrant at least a minor bump. As a consumer, I do not generally want to take on new bits that aren't bug fixes, until I can take the time to analyze what changed and its impact on my systems. So my automation ingests patch level changes and will even deploy them after a successful run through the test suite, but not minor bumps. Even if a minor bump passed my test suite, it's implied by the bump level that there are potential new pathways in that new code or data that my tests aren't exercising, and it's generally a good bet that my customers next bug report will have something to do with those new bits, if I don't test them.

I am generally opposed to explicitly allowing such patch changes to occur in the spec, until the whole spec is tightened up enough that that those few allowable cases are sufficiently explicated. The "new game level" example is a good case in point. You add code or data, but do you really know what might break your downstream consumers? If you broke my systems or test suite with a patch level bump, I'd be unhappy. If you did that more than once, I'd be looking for replacement components.

If your bits are or could be consumed in a security sensitive environment, any change that is not a bug fix, should get at least a minor bump. Since about 98% of code that gets written today, falls into that "could be used in a security sensitive environment" category, it's best to error on the conservative side and only use patch for bug fixes.

In practice, the following may be considered to be exceptions to the patch==bugfix clause:

  • Changes to documentation or code comments that do not imply any changes to the defined API.
  • Certain license changes that do not add any additional restrictions or break any automation (increasingly unlikely).
  • Super critical security fixes, even if it is known to break some use cases, if it is important that it gets ingested fast.
  • Recompiles that pass all internal test suites that you want to get more real-world coverage on.

I am sure I've missed a few.

@Jayman2000
Copy link

Under the current language, it is implied by the text and common practice, that you can make NB changes that only require a patch bump, so nothing is really broken enough to be worth the effort of changing the text.

OK. Instead of merging this PR or whatever language we come up with directly into SemVer 2.0.0, merge it into a separate branch for a new version that rewrites everything. That way we can actually make progress on this issue without having to wait for everything else to be rewritten.

I think the reality is that there are very few corner cases where non-bug, non-breaking changes do not warrant at least a minor bump.

OK, what about this?

  1. Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backward compatible functionality is introduced to the public API. It MUST be incremented if any public API functionality is marked as deprecated. It MAY be incremented if non-breaking changes are made. It MAY include patch level changes. Patch version MUST be reset to 0 when minor version is incremented.

@jwdonahue
Copy link
Contributor

@Jayman2000

Ya, eliminating "private code" from 7 probably helps.

Yes, anybody is allowed to fork the repo and work their own changes. If you do that, let me know where it is and we can discuss the proposed changes there, before submitting a PR over here. There's too many open PR's here already, that really have near zero chance of getting accepted.

@jwdonahue
Copy link
Contributor

I would add that a v3 probably wont fly without first pushing experimental features into each of the top three or four packaging tools and driving some adoption. Not even the most compelling specmanship is going to motivate the existing tool makers to accept the ecosystem disruptions and pay for new code as well. In some cases, they will have their own motivations to suppress some changes, so that's probably going to be a steep climb.

This particular thread falls into a large set of issues/PR's intended to clarify something about the current spec that has them confused or that they perceive to be a barrier to progress in their own work. As such, they mostly don't fall into a worthiness category that is likely to cause any changes to be taken. Generally, the documentation for each of the individual silos/tool-chains, should cover the realm of acceptable and best practices for their own ecosystems, and it really doesn't warrant a spec change.

@Jayman2000
Copy link

Yes, anybody is allowed to fork the repo and work their own changes. If you do that, let me know where it is and we can discuss the proposed changes there, before submitting a PR over here.

I’m not interested in working on the other aspects of SemVer v3 at the moment, but if someone else creates a branch for SemVer v3, then I’m willing to open a PR for this patch:

From bb5a84ad2b59d1174ec185b4bbbc6b955439b27c Mon Sep 17 00:00:00 2001
From: Jason Yundt <jason@jasonyundt.email>
Date: Tue, 19 Sep 2023 07:51:27 -0400
Subject: [PATCH] Explicitly allow more types of minor changes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Before this commit, the spec explicitly mentions a few different
categories of changes:

• adding backward compatible bug fixes
• adding new, backward compatible functionality to the public API
• deprecating public API functionality
• adding substantial new functionality or improvements to private code
• making backward incompatible changes to the public API

Unfortunately, some changes don’t fit clearly into any of those
categories, and the spec doesn’t say what users are allowed to do in
that situation. This commit makes that situation less likely.
---
🅭🄍1.0 This patch/email is dedicated to the public domain using the CC0
1.0 Universal Public Domain Dedication:
<https://creativecommons.org/publicdomain/zero/1.0/>

 semver.md | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/semver.md b/semver.md
index 22c9573..aeb16a7 100644
--- a/semver.md
+++ b/semver.md
@@ -81,9 +81,8 @@ change that fixes incorrect behavior.
 1. Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backward
 compatible functionality is introduced to the public API. It MUST be
 incremented if any public API functionality is marked as deprecated. It MAY be
-incremented if substantial new functionality or improvements are introduced
-within the private code. It MAY include patch level changes. Patch version
-MUST be reset to 0 when minor version is incremented.
+incremented if non-breaking changes are made. It MAY include patch level
+changes. Patch version MUST be reset to 0 when minor version is incremented.
 
 1. Major version X (X.y.z | X > 0) MUST be incremented if any backward
 incompatible changes are introduced to the public API. It MAY also include minor
-- 
2.42.0

I would add that a v3 probably wont fly without first pushing experimental features into each of the top three or four packaging tools and driving some adoption. Not even the most compelling specmanship is going to motivate the existing tool makers to accept the ecosystem disruptions and pay for new code as well. In some cases, they will have their own motivations to suppress some changes, so that's probably going to be a steep climb.

This particular thread falls into a large set of issues/PR's intended to clarify something about the current spec that has them confused or that they perceive to be a barrier to progress in their own work. As such, they mostly don't fall into a worthiness category that is likely to cause any changes to be taken. Generally, the documentation for each of the individual silos/tool-chains, should cover the realm of acceptable and best practices for their own ecosystems, and it really doesn't warrant a spec change.

I promise that I won’t submit the above patch as a PR to this repo’s master branch.

@Tieske
Copy link
Contributor

Tieske commented Sep 19, 2023

There's too many open PR's here already, that really have near zero chance of getting accepted.

Can we then simply close those please?

@jwdonahue
Copy link
Contributor

@Tieske I would if I could.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC Request for comments state for next version update Update current idea/rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants