arti/doc/dev/semver_status.md

2.9 KiB

Semver tracking

We no longer use this file for semver tracking. Instead, we use one semver.md file per crate.

When you make a change to a crate that affects source compatibility, please append a paragraph to that crate's semver.md, creating it as necessary.

Every line should begin with one of the following:

  • BREAKING
  • MODIFIED

A "BREAKING" change is one that may break other crates that depend on this crate directly.

A "MODIFIED" change is one the introduces a new API, such that crates using the new API will not work with older versions of the crate.

When we release a new version, we use these files to determine which crates need major-version, minor-version, or patch-level version bumps. We also use them to help write the "breaking changes" section of the changelog. They aren't user-facing, so they don't go into much detail.

Here is an example semver.md file:

BREAKING: Removed the obsolete `detect_thylacine()` function.

MODIFIED: New `Wombat::feed()` method.

MODIFIED: `Numbat` now implements `Display`.

BREAKING: The `Quokka` trait now inherits from Debug.

What is a breaking change?

We will add guidance to this section as we come up with it. For now, see SemVer compatibility in the Cargo book.

When types from lower-level crates appear in the APIs of higher-level crates

If a type (concrete type or trait) from a lower-level crate is returned (or accepted) by an API of a higher-level crate, then a breaking change to that lower-level crate is a breaking change for the higher-level crate, too.

This includes any case where a higher-layer type implements a public trait from a lower-layer; even if the type is not itself re-exported by the higher-layer crate.

Reasoning, and worked example:

Suppose tor_error::ErrorKind gets a breaking change, and we bump the major[1] for tor_error but not for arti_client. Obviously our new arti_client uses the new tor_error.

A downstream might use both tor-error and arti-client. If they do this in the usual way, a cargo update will get them the new arti_client but old tor_error. Now their program has two instances of tor_error: one whose ErrorKind is implemented by arti_client::Error, and one that the downstream application code sees. The effect is that the downstream application can no longer call .has_kind() on an arti_client::Error because they don't have the right HasKind method in scope.

Note that this does not depend on the nature of the breaking change, nor on the re-export of any names. It only depends on the exposure of the type and its trait implementations.

(The "semver trick" can sometimes be used to help multiple different versions of the same crate share global state, or perhaps, traits etc.)

[1] "Major" here includes the 2nd component in a 0.x version.