A pre-tag checklist that the v0.8.21/v0.8.22 CHANGELOG gap proved we needed.
Step through this in order from a clean worktree on the release branch
(work/vX.Y.Z-...). Treat any unchecked box as a release blocker.
For deeper context on the underlying tools (preflight scripts, npm smoke,
publish-crates), see RELEASE_RUNBOOK.md.
For v0.9.0, also complete the dedicated
V0_9_0_RELEASE_ACCEPTANCE.md matrix before
tagging; it covers provider routes, WhaleFlow feature gates, GUI/runtime smoke,
remote workbench decisions, and credit hygiene that the generic checklist does
not enumerate.
-
CHANGELOG.mdhas a## [X.Y.Z] - YYYY-MM-DDheading at the top - The entry credits every external contributor, harvested PR author,
linked issue reporter, reproduction/log provider, reviewer, and
verification helper whose work materially shaped this version. Get the
commit list with:
git log vPREV..HEAD --no-merges --format="%h %an <%ae> %s" \ | grep -v '<your-email@…>'For each contributor, link both their display name and (when known)@github-handle. Then inspect linked issues and harvested PRs so reporters/helpers are not lost just because they did not author commits. - The entry uses the Keep a Changelog headers —
Added,Changed,Fixed,Security,Removed,Deprecated. AddKnown issuesonly if there is something material the user must work around. - The entry mentions all referenced issue/PR numbers as
#NNNNso the auto-linker on GitHub picks them up. - Run
scripts/sync-changelog.shto regeneratecrates/tui/CHANGELOG.md(the recent-releases slice embedded in the binary for/change). Do not edit that file by hand, and do not copy the full root changelog into it — older entries live indocs/CHANGELOG_ARCHIVE.md.
- Run
./scripts/release/prepare-release.sh X.Y.Z— it bumps the workspace version, every per-crate dependency pin,npm/codewhale/package.json(version+codewhaleBinaryVersion), the README install-tag examples, refreshesCargo.lock, regeneratescrates/tui/CHANGELOG.mdandweb/lib/facts.generated.ts, and ends by runningcheck-versions.sh. Write the CHANGELOG entry before running it. -
npm/deepseek-tui/package.jsonremains private/compatibility-only and is not bumped or published. -
./scripts/release/check-versions.shreportsVersion state OK: workspace=X.Y.Z, npm=X.Y.Z, lockfile in sync. -
./scripts/release/check-ohos-deps.shreports that the OpenHarmony target graph does not pull the unsupportednix0.28/0.29,portable-pty,starlark,arboard, orkeyringcrates.
Run, in order, from the repo root:
-
cargo fmt --all -- --check -
cargo check --workspace --all-targets --locked -
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings -
cargo test --workspace --all-features --locked(Re-run any single failure in isolation withcargo test -p PKG --bin BIN -- TEST_NAMEbefore declaring it a flake. Tests that mutate process-wide state —HOME,cwd,RUST_LOG— can race in parallel. Document confirmed flakes inKnown issues.) -
./scripts/release/publish-crates.sh dry-run
-
cargo build --release --locked -p codewhale-cli -p codewhale-tui -
node scripts/release/npm-wrapper-smoke.js(SetDEEPSEEK_TUI_KEEP_SMOKE_DIR=1if you need to inspect the temp install afterwards.)
- Branch is pushed:
git push -u origin work/vX.Y.Z-... - PR opened with
gh pr create --base main --title "chore(release): prepare vX.Y.Z" - PR body includes:
- one-paragraph summary of the release theme
- a punch list of the new commits since the last release
- explicit call-out of any Security items so reviewers see them
- the contributor thank-you list
- the
Known issuesblock from the CHANGELOG, if any
- PR title is neutral — do not put CVE-style language or specific attack details in the title. Save those for the GitHub release notes after the tag is pushed.
After the release/integration merge lands, make it obvious where the release
tip lives and clean up stale branches safely. A working checkout left on a
scratch/renovate branch (even when HEAD already matches the tag) creates
release anxiety: contributors cannot tell whether their work merged.
-
Run the dry-run report first (read-only, deletes nothing):
```sh ./scripts/release/branch-hygiene.sh --release-branch codex/vX.Y.Z ``` It prints: the current checkout branch, the local + remote release tips, and `origin/main`; the branches that are **safe to delete** (tip already contained in `origin/main` or the release branch); and a **keep / needs review** list naming each branch, its unique commit count, the author(s), and the keep reason. The summary line reports how many are safe-deletes, how many were kept for contributor work, and how many need a human decision. A diverged local/remote release tip exits non-zero. -
If the working checkout is parked on a stale branch, switch to the release branch and fast-forward it:
```sh git switch codex/vX.Y.Z git fetch origin && git merge --ff-only origin/codex/vX.Y.Z # if behind ``` -
Only after reviewing the dry-run, delete the safe branches. Local first; add
--prune-remoteto also delete remote safe-deletes:```sh ./scripts/release/branch-hygiene.sh --release-branch codex/vX.Y.Z --prune --yes ``` The script **never** auto-deletes a branch with unique commits from a contributor other than Hunter unless that work is already merged. Those land in the keep/review list with author and reason; review, merge, harvest with credit, or explicitly preserve them before removing the branch. When in doubt, leave the branch and record the decision.
- All required CI jobs are green. The
versionsjob should mirror the preflightcheck-versions.shand is your last line of defense. - PR has been reviewed.
-
git tag -s vX.Y.Z -m "vX.Y.Z" -
git push origin vX.Y.Z - The
release.ymlworkflow has built and uploaded artifacts to the GitHub release for this tag. - The live GitHub Release body has its own
## Contributorsor## Creditssection; do not rely on "see CHANGELOG" alone. Verify with:gh release view vX.Y.Z --repo Hmbown/CodeWhale --json body \ --jq '.body | test("## (Contributors|Credits)")' -
npm view codewhale@X.Y.Z version codewhaleBinaryVersion --jsonreports the new version on the npm registry. -
npm view deepseek-tui deprecatedis non-empty. The legacy npm package is deprecated and must not receive anX.Y.Zpublish. -
crates.iohas the new version (or thepublish-crates.shjob has pushed it). -
ghcr.io/hmbown/codewhale:vX.Y.Zand:latestare updated.
- Edit the GitHub release notes to expand any CVE-style or attack details that were intentionally omitted from the PR title/body.
- Re-run the GitHub Release body check after any release-workflow rerun; workflows can overwrite notes and accidentally remove contributor credit.
- Note any deferred items in the next release's tracking issue.
- Close any issues that this release fixed.
If a step fails, fix the underlying cause rather than skipping it. Pre-commit
hooks, signing, and CI are all here to catch real problems. --no-verify,
--no-gpg-sign, and force-pushing a release branch over reviewers should
remain hard-disabled by convention.