0001. Monotonic 0.0.x versioning and suite lockstep#
Status: Accepted
Date: 2026-08-29 (practised since 0.0.51; written down 2026-09-10)
Deciders: maintainer
Context#
pain001 is one of five packages that ship together: the core, an MCP
server, a language server and two loader plugins. Users install the
members separately and combine them, and the failure they hit when the
numbers diverge is a version they cannot reason about: is
pain001-loader-xlsx==0.0.54 meant to work with pain001==0.0.60? By
0.0.62 the five packages had drifted to four different numbers with no
breakage, which is exactly why it went unnoticed.
The project is pre-1.0 and its public surface (CLI flags, CSV column contract, generated XML, plugin protocols) still moves.
Options considered#
Independent SemVer per package with compatibility ranges. Precise, but every member needs its own release judgement and the ranges are what users cannot reason about.
One number across the suite, advancing one
0.0.xstep at a time. Coarse, but a version pin on one package is a pin on all, and a release is one coordinated event.Jump to 1.0 and use minor/patch semantics. Premature while the output contract and plugin protocol are still being shaped; a 1.0 promise that has to be broken is worse than none.
Decision#
Option 2. Every member ships the same 0.0.x number; releases advance
by exactly one step; 0.1.0 follows 0.0.999, never 0.0.60. The
maintainer decides when the next number opens for work; contributors
never bump it. Inside the line, breaking changes are still called out
in the CHANGELOG and announced one release ahead (see the stability
section of the README).
Consequences#
pain001/suite.pylists the members;scripts/check_suite_consistency.pyqueries PyPI daily and fails when any member lags the core or declares a floor the core has not published.tests/test_suite_conformance.py, a byte-identical file vendored in every repository, checks that the version is restated consistently and that the CHANGELOG’s newest heading is the declared version.A change that adds a message type or alters the required-field set is a five-repository release. That cost is accepted because the alternative was users guessing.
scripts/preflight_release.pyadditionally checksCITATION.cffand theSECURITY.mdsupport table.