The middle field was the Stalwart generation a build targeted — 16 for 0.16 — and Stalwart 1.0 leaves it with no honest value. 2.1 sorts below the 2.16 already deployed, so every image tag, About screen and /api/health would have read as a downgrade. Borrowing someone else's numbering was the mistake.
Which Stalwart a build needs is already stated better elsewhere — the README badge says "Requires Stalwart 0.16 or newer; tested against 0.16.19", and KNOWN-ISSUES is precise per feature. One digit could never carry that.
Nothing derived behaviour from the version, so this is labelling only: the Stalwart generation is detected at runtime from urn:stalwart:jmap, not from the version string.
Why the PR number moved after the +
It is provenance, not a rank. At the rate this repo merges — 100 PRs in the 8 days to 2026-08-30 — it climbs without bound and says nothing about how new a build is; a year of that is 2.16.4500.
SemVer ignores everything after the + when comparing versions, which reads correctly here: two builds from the same day differ in where they came from, not in age. Nothing depends on that comparison anyway — images are pruned oldest-first by creation time, and a rollback names a git ref.
Details
The date is the commit's own, not today's, so rebuilding an old commit gives the version it had the first time. It comes from the commit object with its timezone, so two machines agree.
A commit that did not arrive through a PR carries its short SHA: 2026.8.30+g1fa6578. It no longer claims the previous PR number.
Docker tags turn the + into - as they already did: 2026.8.30-pr129.
package.json is no longer the source of anything and sits at 0.0.0 — what an unversioned build reports, and meant to look wrong.
Leading zeros are stripped, since a version field may not carry them: September is 2026.9.5.
Tests
The formatter is a pure function now, so the rules are testable without staging a repo to produce them. It had no tests while it was the thing naming every image we ship; there are eight now, covering the PR and SHA paths, leading zeros, determinism, same-day builds, the IHASMAIL_VERSION override, and that it sorts forward from 2.16.129.
Typecheck clean; 366 web tests and 90 server tests pass.
Not in this PR
The docs site still documents the old scheme in install.md, immutable.md and rebranding.md (ihasmail:2.16 tags, 2.16.57 examples). That is the ihasmail.org repo and wants a matching change, sequenced to land with this one.
`2.16.129` → `2026.8.30+pr129`.
## Why now
The middle field was the Stalwart generation a build targeted — `16` for 0.16 — and Stalwart 1.0 leaves it with no honest value. `2.1` sorts *below* the `2.16` already deployed, so every image tag, About screen and `/api/health` would have read as a downgrade. Borrowing someone else's numbering was the mistake.
Which Stalwart a build needs is already stated better elsewhere — the README badge says "Requires Stalwart 0.16 or newer; tested against 0.16.19", and KNOWN-ISSUES is precise per feature. One digit could never carry that.
Nothing derived behaviour from the version, so this is labelling only: the Stalwart generation is detected at runtime from `urn:stalwart:jmap`, not from the version string.
## Why the PR number moved after the `+`
It is provenance, not a rank. At the rate this repo merges — 100 PRs in the 8 days to 2026-08-30 — it climbs without bound and says nothing about how new a build is; a year of that is `2.16.4500`.
SemVer ignores everything after the `+` when comparing versions, which reads correctly here: two builds from the same day differ in where they came from, not in age. Nothing depends on that comparison anyway — images are pruned oldest-first by creation time, and a rollback names a git ref.
## Details
- The date is the **commit's own**, not today's, so rebuilding an old commit gives the version it had the first time. It comes from the commit object with its timezone, so two machines agree.
- A commit that did not arrive through a PR carries its short SHA: `2026.8.30+g1fa6578`. It no longer claims the previous PR number.
- Docker tags turn the `+` into `-` as they already did: `2026.8.30-pr129`.
- `package.json` is no longer the source of anything and sits at `0.0.0` — what an unversioned build reports, and meant to look wrong.
- Leading zeros are stripped, since a version field may not carry them: September is `2026.9.5`.
## Tests
The formatter is a pure function now, so the rules are testable without staging a repo to produce them. It had **no tests** while it was the thing naming every image we ship; there are eight now, covering the PR and SHA paths, leading zeros, determinism, same-day builds, the `IHASMAIL_VERSION` override, and that it sorts forward from `2.16.129`.
Typecheck clean; 366 web tests and 90 server tests pass.
## Not in this PR
The docs site still documents the old scheme in `install.md`, `immutable.md` and `rebranding.md` (`ihasmail:2.16` tags, `2.16.57` examples). That is the `ihasmail.org` repo and wants a matching change, sequenced to land with this one.
**Merged** 2026-08-30 as coffey-labs/ihasmail@826a13ab39e1
<sub>Rebuilt from: GH Archive, git history, session transcript.</sub>
This repo is archived. You cannot comment on issues.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
2.16.129→2026.8.30+pr129.Why now
The middle field was the Stalwart generation a build targeted —
16for 0.16 — and Stalwart 1.0 leaves it with no honest value.2.1sorts below the2.16already deployed, so every image tag, About screen and/api/healthwould have read as a downgrade. Borrowing someone else's numbering was the mistake.Which Stalwart a build needs is already stated better elsewhere — the README badge says "Requires Stalwart 0.16 or newer; tested against 0.16.19", and KNOWN-ISSUES is precise per feature. One digit could never carry that.
Nothing derived behaviour from the version, so this is labelling only: the Stalwart generation is detected at runtime from
urn:stalwart:jmap, not from the version string.Why the PR number moved after the
+It is provenance, not a rank. At the rate this repo merges — 100 PRs in the 8 days to 2026-08-30 — it climbs without bound and says nothing about how new a build is; a year of that is
2.16.4500.SemVer ignores everything after the
+when comparing versions, which reads correctly here: two builds from the same day differ in where they came from, not in age. Nothing depends on that comparison anyway — images are pruned oldest-first by creation time, and a rollback names a git ref.Details
2026.8.30+g1fa6578. It no longer claims the previous PR number.+into-as they already did:2026.8.30-pr129.package.jsonis no longer the source of anything and sits at0.0.0— what an unversioned build reports, and meant to look wrong.2026.9.5.Tests
The formatter is a pure function now, so the rules are testable without staging a repo to produce them. It had no tests while it was the thing naming every image we ship; there are eight now, covering the PR and SHA paths, leading zeros, determinism, same-day builds, the
IHASMAIL_VERSIONoverride, and that it sorts forward from2.16.129.Typecheck clean; 366 web tests and 90 server tests pass.
Not in this PR
The docs site still documents the old scheme in
install.md,immutable.mdandrebranding.md(ihasmail:2.16tags,2.16.57examples). That is theihasmail.orgrepo and wants a matching change, sequenced to land with this one.Merged 2026-08-30 as coffey-labs/ihasmail@826a13ab39
Rebuilt from: GH Archive, git history, session transcript.