Release checklist
The steps to cut a commission release. Written to be run by a human or an agent, in order, top to bottom. Every step is a command or a decision with a stated answer — no step says “verify things look right”.
The compatibility promises this checklist enforces are in
compatibility.md. The entries it publishes are in
../CHANGELOG.md CHANGELOG.md.
Automation status: run by hand today. relay-52 wires it into a workflow; anything below marked (manual) is a decision that stays with a human even after that lands.
0. Preconditions
- Working tree is clean:
git status --porcelainprints nothing. - On
main, up to date with the remote. - No commission task for this release is still in flight:
commission board --project commissionshows nothingin_progressthat the release is supposed to contain.
1. Decide the number (manual)
Read the ## Unreleased section of the changelog and apply
compatibility.md:
- Any entry under
### Breaking→ major. - Any new command, flag, endpoint, MCP tool, or config key → minor.
- Fixes and internals only → patch.
- Release candidates are
1.0.0-rc.N, and are held to the 1.x contracts.
A schema version bump on its own does not force a major — see the database section of the compatibility policy.
Write the number down; every later step uses it.
2. Green build
-
bun test— all pass. This includestests/version.test.ts, which is what guarantees the number you are about to publish is reported identically by the CLI, MCP, HTTP, and package manifest. -
bunx tsc --noEmit— clean. -
bun run build— producesdist/commission. -
./dist/commission doctoron a scratch database exits 0:COMMISSION_DB=$(mktemp -d)/commission.db ./dist/commission doctor
3. Bump the version
The version lives in exactly one place: the version field in
package.json. src/version.ts derives from it and every surface derives from
src/version.ts. Do not edit src/version.ts, and do not add a literal
anywhere else — tests/version.test.ts fails if you do.
- Edit
package.json→version. -
bun test tests/version.test.ts— confirms all four surfaces moved together.
4. Close the changelog section
- Rename
## Unreleasedto## X.Y.Z — YYYY-MM-DD. - Add the
Schema version N · config version Mline, taking the numbers fromMIGRATIONS.lengthinsrc/db/ddl.tsandCONFIG_VERSIONinsrc/config/schema.ts.GET /v1/versionreports both if you would rather ask the binary. - Re-read every entry as someone upgrading (manual). Delete anything
that reads like a commit message. Confirm each
### Breakingentry carries its migration inline. - Open a fresh empty
## Unreleasedabove it.
5. Upgrade rehearsal
This is the step that catches the mistakes the test suite cannot.
- Take a database created by the previous release — keep one per
release under
~/.commission/upgrade-fixtures/— copy it, and check what the new binary intends to do to it before it does it:./dist/commission migrate --check --db /tmp/upgrade.db. It exits 2 and lists exactly the migrations this release adds. - Run the new binary against the copy:
COMMISSION_DB=/tmp/upgrade.db ./dist/commission board. - It migrates without error, prints the backup path and its restore command
on stderr, and
./dist/commission doctorreports the expected schema level.commission migrate --checknow exits 0. - The backup it wrote is a working database at the previous level, and the restore command it printed puts it back.
- Task counts, statuses, and evidence match what the old binary reported.
- If the release adds a migration: confirm it is appended, never edited
in place, and that no released migration’s text changed
(
git diff <previous-tag> -- src/db/ddl.tsshows additions only), and thattests/migrations.test.tshas a step covering it — the suite fails if it does not. - A
.commission.jsonfrom the previous release still validates:./dist/commission config validate.
6. Documentation
-
bun run generate:config— regenerate the config reference; commit any diff, or confirm there is none. - README install instructions name the new version if they pin one.
- If a surface changed, compatibility.md reflects it — especially a new exit code, a new enum member, or a config version bump.
7. Cut it
- Commit:
Release X.Y.Z. - Tag:
git tag -a vX.Y.Z -m "Release X.Y.Z". - Push the commit and the tag.
Pushing the tag is what builds and publishes. .github/workflows/release.yml
takes it from there: it builds all five platform binaries on their own runners,
refuses to continue if any of them cannot run init through done on its own
platform, publishes SHA256SUMS, and creates the GitHub release with this
version’s changelog section as the body plus a generated table of binary sizes
and measured cold-start times. How that works, and what it does and does not
guarantee, is release-engineering.md.
- Watch the run. A red leg means that platform’s binary does not work, not that CI is flaky — read the failing smoke step before re-running.
- Confirm the release body carries the artifact table and that
SHA256SUMSlists all five files. - Update the distribution channels (relay-52).
8. Verify what shipped
Against the published artifact, not your working tree:
- The installed binary reports the new number:
commission --version. -
GET /v1/versionon a served instance returns the samecommissionvalue. - The MCP handshake advertises it:
serverInfo.versionfromcommission mcp. - Install from a clean machine or container by following the README
verbatim, and run
commission initthroughcommission doneonce.
9. Close the loop
-
commission donethe release task with the tag as evidence:commission evidence commission-NN release=vX.Y.Z commit=<sha>. - Note anything that went wrong on the task. A release checklist that never changes is a release checklist nobody is following.
If a release is bad
Do not delete or move the tag — someone has already installed it.
- Fix forward. Cut
X.Y.Z+1with the fix, and add a### Fixedentry naming the broken release explicitly. - If the bad release corrupts data or cannot be upgraded past, say so at the top of the new release’s changelog entry, with the recovery steps.
- Commission never downgrades a database. If a release migrated a database and must be backed out, the recovery path is restoring a backup, and the changelog entry has to say that in those words.
This page is docs/release-checklist.md in the Commission
repository, rendered in place — the site keeps no copy of it. The repository is private, so there is no edit link to follow.