Platform Release Version
Purpose
Section titled “Purpose”This contract defines one deliberate SemVer cycle from local development through
test and Production. It prevents a released base version from producing new
alpha images and prevents image tags, runtime configuration, and /version
from describing different releases.
Version formats
Section titled “Version formats”| Environment or purpose | Required format | Example |
|---|---|---|
| Root base version | MAJOR.MINOR.PATCH | 0.1.2 |
| Local | MAJOR.MINOR.PATCH-local.0 | 0.1.2-local.0 |
| Test | MAJOR.MINOR.PATCH-alpha.RUN.ATTEMPT | 0.1.2-alpha.2.1 |
| Staging | MAJOR.MINOR.PATCH-rc.NUMBER | 0.1.2-rc.1 |
| Production | MAJOR.MINOR.PATCH | 0.1.2 |
Build metadata introduced with + is forbidden because it cannot be preserved
unchanged in a Docker tag. Numeric pre-release identifiers have no leading
zeroes. RUN, ATTEMPT, and NUMBER are positive integers.
RUN is the one-based position of the ci workflow run on main inside the
stable root-version line. A new MAJOR.MINOR.PATCH base therefore starts at
RUN=1. The final CI job derives that position from the bounded GitHub Actions
history and the stable package.json version at each Main commit; it does not
depend on a mutable counter. ATTEMPT uses GITHUB_RUN_ATTEMPT. Failed or
cancelled runs may leave gaps, and retrying the same CI run creates a new
immutable alpha tag with the same RUN and the next ATTEMPT.
Sources of truth
Section titled “Sources of truth”Three values describe the release state:
- root
package.jsonis the stable base of the prepared test and Production release line; sens-platform-infra/environments/production/release.yamlis the desired Production version in GitOps;https://api.iot-sens.schlossers.at/versionis the version currently served by the live Productionplatform-api.
Use pnpm version:status to read and validate all three without changing any
file. Failure to read GitHub or the live API, malformed YAML or JSON, a
pre-release value in Production, or invalid SemVer fails closed.
Release state
Section titled “Release state”A released state has the same stable version in all three sources. A human then
chooses major, minor, or patch. The resulting version PR changes only the
root package.json and opens the next alpha line:
Released 0.1.1 -> choose patchPrepared base 0.1.2 -> 0.1.2-alpha.1.1, 0.1.2-alpha.2.1, ... -> Ops portal prod-releaseProduction 0.1.2 -> alpha publication blocked until the next version is chosenBefore Production promotion, a human may reclassify an open line upward. The new target is always calculated from the aligned GitOps/live Production baseline, not by incrementing the already prepared base:
Production 0.1.2 + prepared patch 0.1.3 -> choose minor: 0.2.0 -> choose major: 1.0.0The same or a lower SemVer class is rejected. Reclassification is also blocked while GitOps and the live API differ, because that state can represent an in-progress promotion or rollback.
Automatic test publication requires the root base version to be greater than both GitOps Production and live Production. GitOps and the live API may differ briefly during a Production sync; the prepared base must still be newer than both. The controller’s stable-image workflow dispatch is not subject to this alpha guard. It uses the supplied stable tag and does not read the CI workflow history or increment the alpha run.
Historical global alpha run numbers
Section titled “Historical global alpha run numbers”Alpha tags published before the release-local counter was introduced remain
immutable and valid. New release lines use the main CI history and start
visibly at alpha.1.1; no historical tag is renamed or overwritten.
Bump semantics
Section titled “Bump semantics”The next version is deterministic:
patchincrements Patch exactly once;minorincrements Minor exactly once and resets Patch to zero;majorincrements Major exactly once and resets Minor and Patch to zero.
For example, major from 0.1.1 produces 1.0.0. Downgrades and skipped
versions such as 0.1.1 to 0.1.5 are invalid. An unchanged version remains
valid for ordinary feature pull requests.
Run a local bump only after selecting its type explicitly:
pnpm version:statuspnpm version:next patchThe GitHub Actions workflow Prepare next version performs the same check and
opens a review PR. It never merges the PR. At most one open branch with prefix
prepare-version- may have an active version PR.
Deployment identity
Section titled “Deployment identity”For platform-api, the Helm value services.platformApi.image.tag supplies
both the container image tag and SENS_PLATFORM_VERSION. The configured value
must match the runtime environment’s release channel. GET /version returns
that exact value without transformation.
Deployment and smoke checks must therefore preserve this equality:
platform-api image tag = SENS_PLATFORM_VERSION = GET /versionPublished release tags are immutable. Before a build, the image workflow checks an existing tag’s OCI revision and version labels. A retry for the same commit converges without another push. A tag owned by another commit fails the workflow instead of overwriting the artifact.
Local Compose and direct TypeScript starts derive <package.json>-local.0
unless the operator provides a valid explicit local-channel override.
Drift, failure, and recovery
Section titled “Drift, failure, and recovery”If GitOps and the live API differ, do not prepare another bump. Complete or
repair the current Production promotion first, then rerun
pnpm version:status. If both Production sources agree and package.json
contains exactly the next patch, minor, or major target, the line is open and
may only be reclassified upward. During a normal release, wait for the validated
Production desired-state commit, sync sens-platform-production in Argo CD,
wait for Synced and Healthy, and verify that GitOps and /version report the
same stable version.
An incorrect image or runtime channel prevents platform-api from starting.
Restore a previously known-good immutable tag or forward-fix the GitOps release
selection; do not bypass runtime validation. A rollback may make GitOps and
live temporarily diverge. New bumps and alpha publication remain blocked until
the desired and live states are intentionally reconciled.
Version changes never require a StatefulSet or PVC mutation. If Argo CD reports a forbidden StatefulSet specification update, compare rendered and live immutable fields and restore the compatible desired state. Do not delete the StatefulSet or its PVC as a version-release workaround.