Release-engineering policy
Five canonical policies for versioning, release tagging, deprecation cycles, breaking changes, and rollback procedures.
Five policies govern how apothem releases.
1. Semantic versioning
The project ships under Semantic Versioning 2.0.
Version numbers take the form MAJOR.MINOR.PATCH[-PRERELEASE][+BUILD].
| Bump | Triggers |
|---|---|
| MAJOR | Breaking changes to artifact schemas, mandate identifiers (CM-N / TM-N / CP-N), or hook contracts |
| MINOR | New rules, delegated workers, commands, skills, hook events, or non-breaking schema extensions |
| PATCH | Clarifications, anti-pattern additions, doc fixes, edits that do not change behavior |
Candidate tags use the format vX.Y.Z-rc.N (release candidate)
or vX.Y.Z-alpha.N / vX.Y.Z-beta.N (early-access).
2. Release tags
Every release lands a signed git tag of the form vMAJOR.MINOR.PATCH
on main. The tag triggers .github/workflows/release.yml which
builds, signs, generates SBOM and SLSA-3 provenance, and
publishes the GitHub Release page.
Tag conventions:
- Format —
vMAJOR.MINOR.PATCHexactly. Norelease-prefix, no-finalsuffix. - Annotation — every tag is an annotated tag (
git tag -a -s) carrying the release-notes summary in the tag message. - Signature — every tag is GPG-signed. The release workflow additionally produces a Sigstore keyless cosign signature on each artifact and a SLSA-3 provenance record, both attached to the GitHub Release page.
Release model: additive
Releases are additive. Each release adds one commit on main and one tag;
main is never force-pushed, and no published tag, GitHub Release or npm
version is deleted, moved or reused. Every release keeps its tag, its GitHub
Release and its npm version, and all of them stay published. npm versions are
immutable: a published name@version can never be replaced, and an
unpublished number can never be used again. Pinned installs and reproducible
builds depend on every published tag. The
release-cycle and
release-recovery runbooks both follow this
model.
The repository's release-facade rule (the Release Facade section of the contributor instructions) states this model. Its current-version-only requirement, mirrored in the freshness-facade rule, covers what public surfaces say. It does not limit which releases stay published.
3. Deprecation policy
The current public support line is the latest released minor. When the project has multiple public minors, the SECURITY.md supported-versions matrix is the source of truth for any additional critical-fix-only support windows.
Deprecation cadence:
- Announcement — a deprecated symbol or behavior is
announced in the
CHANGELOG.md### Deprecatedsection of the release in which the deprecation lands. The release notes mirror the deprecation announcement. - Grace window — deprecated symbols stay available for a minimum of one full minor cycle before removal.
- Removal — removal lands in a
MAJORbump. Each removed symbol carries aCHANGELOG.md### Removedline and a migration guide entry under How-to-guides.
Runtime floors
Apothem declares two runtime floors: requires-python = ">=3.10" in
pyproject.toml and "engines": {"node": ">=18"} in package.json.
- Every declared floor is tested. The Python floor runs in the CI
qualitymatrix and theCI Matrixworkflow. Thenpm Shimworkflow runs the npm shim on the Node floor and on every later LTS major: it checks the missing-prerequisite error,node bin/apothem.mjs --version, a dry-run install in an isolated home directory, and the packed tarball throughnpx. A runtime that is not tested is not declared. - End of life is disclosed. When a runtime that is still a declared floor reaches upstream end of life, the installation guide says so and names the versions to prefer. Python 3.10 reached end of life on 2026-10-01; Node.js 18 and 20 on 2025-04-30 and 2026-04-30. All three remain supported floors.
- Raising a floor is a deprecation. It follows the cadence above: an
announcement under
### Deprecated, at least one full minor cycle in which the old floor stays tested, then the release that raises it records the change.requires-python,engines.node, the installers' version probes, and the CI matrices change together in that release.
4. Breaking-change policy
Breaking changes require:
- An RFC issue — opened against the
rfcsissue label describing the breaking change, the migration path, and the rollback strategy. - A 30-day comment window — the RFC stays open for at least 30 days before merge. Maintainers may extend the window when feedback warrants.
- A MAJOR bump — the release that lands the breaking change bumps the MAJOR component.
- A migration guide — the change ships with a How-to-guides entry walking the operator through the migration.
5. Rollback policy
If a release exhibits a regression that blocks adoption:
- Revert — the offending commit(s) are reverted on
main. - Fix-forward release — a follow-up release lands as
vMAJOR.MINOR.PATCH+1carrying the revert plus any incremental fixes. The previous bad release is not deleted from GitHub Releases, and its npm version stays published (npm versions are immutable) and is marked withnpm deprecate. A### Yankedannotation inCHANGELOG.mddocuments the situation so reproducible builds remain anchored. - Communication — a security-advisories notice (when security-relevant) or a GitHub issue pinned for the incident (when reliability-relevant) accompanies the rollback.
See also
- CHANGELOG.md — the canonical release ledger.
- SECURITY.md — supported-versions matrix and reporting channels.
- cicd-pipeline.md — the CI check classes that gate every release.
- deployment-checklist.md — the per-release production-readiness sweep.
Outward Conformity Registry — When Operating on Host Projects
Fifteen-mandate registry (M1–M15) specifying conformity requirements for all artifacts generated in host projects, cross-mapped with ecosystem-internal mandates.
Badge policy
Specify dynamic and static badge sources for the README, covering GitHub-native workflow status, shields.io endpoint JSON, and static badge forms.