Skip to content

3.6 Releases & Versioning

A version tells everyone, in one glance, what is running and how much it changed. We use the same scheme for services, installed clients and libraries, and we build each version only once: what reaches prod is byte for byte what was tested in stage.

3.6.1 Version Numbers

Versions follow Semantic Versioning: MAJOR.MINOR.PATCH, for example 2.4.1.

Part Increases when Example
MAJOR A change breaks something that callers rely on: an API contract, a file format, a client behavior 2.4.1 → 3.0.0
MINOR Something new is added and everything old still works 2.4.1 → 2.5.0
PATCH A fix, with nothing new 2.4.1 → 2.4.2

A version is a Git tag vMAJOR.MINOR.PATCH on a commit of main. Tags are never moved or deleted.

3.6.2 Builds and Releases

flowchart LR merge[Merge into main] --> build[Build once<br/>image by digest] build -- release approved --> stage[Stage<br/>commit SHA] stage -- tag vX.Y.Z --> approve{Second person<br/>approves} approve --> prod[Prod<br/>vX.Y.Z]
  • Every merge into main builds the artifact once and labels it with the commit SHA. It reaches stage when a release of it is prepared and approved (see Branching & Promotion).
  • A release is cut by tagging a commit that is already in stage. The pipeline promotes that same artifact, identified by its digest, to prod after a second person approves. Nothing is rebuilt.
  • Installed clients and libraries are published only from a tag, and client builds are signed.
  • The release notes are the titles of the pull requests merged since the previous tag, so a pull request title is written for the reader of the release notes.

3.6.3 Changes That Must Stay Compatible

  • Database migrations are backward compatible with the previous release: add first, switch the code, remove in a later release. A rollback of the code must never need a rollback of the database. An applied migration is never edited: a change is always a new migration.

    One-time baseline before the first real stage release (decided 2026-11-11)

    Before the first real release to stage, every system folds its migrations into one clean baseline, a single first migration per system, and the stage databases are wiped once so that the baseline applies to empty databases. It happens once and is the only exception to the rule above; from then on systems add only new migrations and never edit an applied one. The baseline carries the complete grants of every component's own SQL role (Application Delivery).

  • API changes that break callers are a new major version of that API, served alongside the old one until no caller uses it.

  • Events published to other systems only gain fields; a breaking change is a new event name.

3.6.4 Seeing What Runs

The Moonitoring Console shows, for every service in every environment, the version that is running (the tag, or the commit SHA before a tag exists), the image digest, and when it was deployed.