Clever Semantic Versioning

W3C Member Submission

More details about this document
This version:
https://www.w3.org/submissions/2024/SUBM-semantic-versioning-20241127/
Latest published version:
https://www.w3.org/submissions/semantic-versioning/
Editor:
Jeffrey Phillips Freeman (CleverThis)
Author:
Jeffrey Phillips Freeman (CleverThis)
Kyle Hird (CleverThis)
Contributor:
Jeffrey Phillips Freeman (CleverThis)
Kyle Hird (CleverThis)
Brent Edwards (CleverThis)
Rui Hu (CleverThis)
Stanislav Hejny (CleverThis)
Luis Mendes (CleverThis)
Madeline Pace (CleverThis)
Josi Rosenfeld (CleverThis)
Bilal Ben Mahria (CleverThis)
Hamza Khyari (CleverThis)
Aditya Chhabra (CleverThis)
Adnaan Nazir (CleverThis)
Aleena Umair (CleverThis)
Eugen Thaci (CleverThis)
Feedback:
Git ( pull requests, new issue, open issues)

Abstract

Clever Semantic Versioning is a specification for versioning software and related artifacts. It ensures versions are predictable and meaningful by adding semantics to versioning. Unlike the widely known specification at SemVer.org, it extends versioning beyond APIs, refining its scope to address gaps and ambiguities, making it more suited to modern development workflows.

Status of This Document

This section describes the status of this document at the time of its publication. A list of current W3C publications can be found in the W3C technical reports index at https://www.w3.org/TR/.

By publishing this document, W3C acknowledges that the Submitting Members have made a formal Submission request to W3C for discussion. Publication of this document by W3C indicates no endorsement of its content by W3C, nor that W3C has, is, or will be allocating any resources to the issues addressed by it. This document is not the product of a chartered W3C group, but is published as potential input to the W3C Process. A W3C Team Comment has been published in conjunction with this Member Submission. Publication of acknowledged Member Submissions at the W3C site is one of the benefits of W3C Membership. Please consult the requirements associated with Member Submissions of section 3.3 of the W3C Patent Policy. Please consult the complete list of acknowledged W3C Member Submissions.

1. Overview

Given a version number MAJOR.MINOR.PATCH-EXTRA+META, increment the:

  1. MAJOR when making backward incompatible changes

  2. MINOR when adding functionality in a backward compatible manner.

  3. PATCH when making backward compatible bug fixes.

  4. EXTRA for pre-releases or other additional versioning parameters.

The EXTRA version follows a natural ordering (specified below) and MAY contain alphanumeric characters, dots, and additional dashes.
The META version consists of metadata, which is non-ordered and does not increment.

2. Clever Semantic Versioning Specification

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD","SHOULD NOT", "RECOMMENDED","NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

  1. A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor version, and Z is the patch version. X, Y, and Z MUST be representable in a thirty-two-bit unsigned integer, i.e. strictly less than 4,294,967,296.
  2. Once a versioned package has been released, the contents of that version MUST NOT be modified. Any modifications MUST be released as a new version.
  3. Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The artifact SHOULD NOT be considered stable.
  4. Version 1.0.0 defines the artifact. The way in which the version number is incremented after this release is dependent on the version class of the component.
  5. 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 documented behavior or improves performance characteristics while adding no new functionality.
  6. Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backward compatible functionality is introduced to the component. It MUST be incremented if any public functionality is marked as deprecated and it MUST be incremented if new functionality is exposed publicly through the versioned component. It MAY include patch level changes. Patch version MUST be reset to 0 when minor version is incremented. The minor version MUST NOT increment if the major version is eligible to be incremented at this time.
  7. Major version X (X.y.z | X > 0) MUST be incremented if any backward incompatible changes are introduced to the component being versioned. It MAY also include minor and patch and minor level changes. Patch and minor versions MUST be reset to 0 when major version is incremented.
  8. Extra version MAY be denoted by appending a hyphen and a series of dot separated identifiers immediately following the patch version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes. Extra versions have a lower precedence than the associated normal version. An extra version containing only purely numeric identifiers represents a subversion and will follow the same format and rules as a normal version (see dependent version class below). Any other extra version indicates a pre-release and that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version.
  9. Build metadata MAY be denoted by appending a plus sign and a series of dot separated identifiers immediately following the patch or extra version. Identifiers MUST comprise only ASCII alphanumerics and hyphens [0-9A-Za-z-]. Identifiers MUST NOT be empty. Build metadata MUST be ignored when determining version precedence. Thus two versions that differ only in the build metadata, have the same precedence.
  10. A version number MUST be no longer than 255 characters, including extra version and build metadata.
  11. Precedence refers to how versions are compared to each other when ordered.
    1. Precedence MUST be calculated by separating the version into major, minor, patch and extra identifiers in that order (Build metadata does not figure into precedence).
    2. Precedence is determined by the first difference when comparing each of these identifiers from left to right as follows: Major, minor, and patch versions are always compared numerically.
    3. When major, minor, and patch are equal, an extra version has lower precedence than a normal version.
    4. Precedence for two extra versions with the same major, minor, and patch version MUST be determined by comparing each dot separated identifier from left to right until a difference is found as follows:
      1. Identifiers consisting of only digits are compared numerically.
      2. Identifiers with letters or hyphens are compared lexically in ASCII sort order.
      3. Numeric identifiers always have lower precedence than non-numeric identifiers.
      4. A larger set of extra identifiers fields has a higher precedence than a smaller set, if all of the preceding identifiers are equal.
  12. Select the subcategory below that best describes the artifact. They are ordered in descending priority, so pick the first category that matches your software type.
Example versions without the optional EXTRA or META components:

1.9.0, 1.10.0, 1.11.0

Example versions utilizing the optional EXTRA component but without META:

1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92, 1.0.0-x-y-z

Example versions utilizing the optional EXTRA and META components:

1.0.0-alpha+001, 1.0.0+20130313144700, 1.0.0-beta+exp.sha.5114f85, 1.0.0+21AF26D3117B344092BD

Example version precedence:

1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0 < 2.0.0-alpha < 2.0.0 < 2.1.0 < 2.1.1

2.1. Version Classes

While the general meaning of a PATCH, MINOR, and MAJOR version are defined in the specification above the specific interpretation is not always clear depending on the class of resources you happen to be versioning. An API, Schema, or even an application would all interpret when to increment a version a bit differently. Therefore we have tried to define explicitly versioning rules for the various classes of resources of interest. Any class not covered in this specification is technically not covered by it, but it is still recommended that the general principles outlined in the specification above be adhered to when possible.

When picking a version class we only care about exposed components. Internal APIs, internal data, and dependencies SHOULD NOT affect versioning. The exposed components being versioned, and the versioning class being used, SHOULD always be explicitly stated by the project owners.

When an artifact covers several exposed components that are either of different versioning classes, or just make sense to version separately then they SHOULD always be versioned separately. The overall artifact version can be determined by the hybrid versioning class mentioned below.

2.1.1. API Versioning

When versioning software with a public API such as libraries, and web endpoints it MUST match the following criteria:

  1. The resource MUST declare a public API.

  2. The API MUST be declared as code or specification documentation.

For any artifact of this type the meaning of incrementing the components of a version are as follows:

This specification guarantees backward compatibility with SemVer.org version 2.0 and only version 2.0. However, forward compatibility with future versions is not guaranteed. Implementers SHOULD ensure their systems are designed with this limitation in mind.

2.1.2. UI Versioning

When versioning User Interfaces which MAY have any nature of input whether it be command-line, GUI, or some other interface, the following paradigm SHOULD be used. The following criteria MUST be satisfied:

  1. The resource MUST have a user interface of some kind, of which both command-line and GUI are acceptable.

For any artifact of this type the meaning of incrementing the components of a version are as follows:

2.1.3. Dataset Versioning

When versioning datasets, the schema (see Schema Versioning below) MAY be versioned alongside the dataset or separately. A dataset MAY include such things as a RDBMS database, a Semantic Web Knowledge Graph, or an XML file. Such Datasets MUST describe the following:

  1. Public structured data for which access is being provided.

For any artifact of this type the meaning of incrementing the components of a version are as follows:

Anytime the underlying schema experiences an increase in any of its version's parts then the dataset MUST at least increment its version corresponding part, or a more significant part.
Backward compatibility for datasets may depend on the specific use case. In general, a dataset change is considered backward compatible if it does not alter existing data structures, remove information, or require modifications to existing queries consuming the dataset.

2.1.4. Schema Versioning

When versioning schemas for reading or interacting with datasets—such as RDBMS Schemas, Semantic Web Ontologies, and XML Schemas—the schema MUST describe the following:

  1. Public structured data whose schema is being defined.

  2. You are versioning the schema independently of the dataset or you are versioning the schema and not the dataset.

For any artifact of this type the meaning of incrementing the components of a version are as follows:

2.1.5. Hybrid Versioning

When versioning artifacts that contain multiple resources that SHOULD be versioned separately, which is required when you have public interfaces that represent two or more of the version classes listed here, then you MUST use hybrid versioning. To use Hybrid Versioning the following criteria MUST be met.

  1. The artifact MUST include two or more publicly exposed components that can be defined by one of the versioning classes outlined here.

  2. The exposed components MUST be of either different versioning classes, or are versioned separately.

When versioning an artifact with multiple hybrid versions each versioned public component receives an independent version according to the rules of its versioning class. In addition the overall artifact gets an additional version, this version will increment one of its parts depending on the most significant version change across all its other interfaces, incrementing at most one version step. The specific parts of the version behave as follows:

Example hybrid version jumps based on the version changes in its other components:

Versioning Table
Composite Artifact Component 1 Component 2
1.0.0-alpha → 1.0.0-beta 2.6.7-alpha → 2.6.7-beta 1.8.3+102 → 1.8.3+111
1.0.0-alpha → 1.0.1-beta 2.6.7-alpha → 2.6.7-beta 1.8.3+102 → 1.8.4
1.0.0-alpha → 1.1.0 2.6.7-alpha → 2.6.7 1.8.3+102 → 1.10.3
1.0.0-alpha → 1.1.0 2.6.7-alpha → 2.6.7+112 1.8.3+102 → 1.10.3+113

2.2. Dependent Artifact Versioning

On occasion you have software that needs to be versioned relative to the to the version against which it is written. Example projects and schema-extensions are good examples of this. Such software SHOULD have the following criteria:

  1. Its version only makes sense relative to the base projects version.

  2. The version of the base project will always be treated as a more significant digit than the version of this project.

When using this versioning paradigm the EXTRA field is used to embed this projects encoding. The EXTRA field effectively embeds a second version that follows all the same rules as a standalone normal version. The fully expanded format for a version with this paradigm would now be MAJOR_BASE.MINOR_BASE.PATCH_BASE which expands to:

MAJOR_BASE.MINOR_BASE.PATCH_BASE-MAJOR.MINOR.PATCH+META_BASE

For any artifact of this type the meaning of incrementing the components of a version entirely depend on the versioning class itself.

Example Dependent Artifact Versioning:

1.2.3-4.5.6 > 1.2.2-5.6.7

3. Backus–Naur Form

    <valid semver> ::= <version core>
                     | <version core> "-" <extra>
                     | <version core> "+" <build>
                     | <version core> "-" <extra> "+" <build>
    
    <version core> ::= <major> "." <minor> "." <patch>
    <major> ::= <numeric identifier>
    <minor> ::= <numeric identifier>
    <patch> ::= <numeric identifier>
    <extra> ::= <dot-separated extra identifiers>
    <dot-separated extra identifiers> ::= <extra identifier>
                                              | <extra identifier> "." <dot-separated extra identifiers>
    <build> ::= <dot-separated build identifiers>
    <dot-separated build identifiers> ::= <build identifier>
                                        | <build identifier> "." <dot-separated build identifiers>
    <extra identifier> ::= <alphanumeric identifier>
                               | <numeric identifier>
    <build identifier> ::= <alphanumeric identifier>
                         | <digits>
    <alphanumeric identifier> ::= <non-digit>
                                | <non-digit> <identifier characters>
                                | <identifier characters> <non-digit>
                                | <identifier characters> <non-digit> <identifier characters>
    <numeric identifier> ::= "0"
                           | <positive digit>
                           | <positive digit> <digits>
    <identifier characters> ::= <identifier character>
                              | <identifier character> <identifier characters>
    <identifier character> ::= <digit>
                             | <non-digit>
    <non-digit> ::= <letter>
                  | "-"
    <digits> ::= <digit>
              | <digit> <digits>
    <digit> ::= "0"
             | <positive digit>
    <positive digit> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
    <letter> ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
              | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
              | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d"
              | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n"
              | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
              | "y" | "z"
          

4. Acknowledgments

We would like to give special thanks to the SemVer project for providing an early open-source version of the SemVer specification that highly influenced the development of this specification.

We would also like to thank the CleverThis company and the CleverLibre non-profit organization for donating resources and staff for the completion of this specification. With particular thanks to Jeffrey Phillips Freeman for his leadership in this initiative.