From 9d1d2c453f2cd60c4dfea78d6e6db4ebaa2230f2 Mon Sep 17 00:00:00 2001 From: Polichinl Date: Tue, 18 Aug 2026 14:08:48 +0200 Subject: [PATCH] docs(guide): give the publishing runbook a pre-tag checklist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit S3 of epic #267. Closes #270. The runbook had none. Its §TL;DR and §C are numbered process narratives — bump, rehearse, `gh release create`, confirm — with no step verifying the preconditions a MAJOR carries. So register C-13's requirement ("before tagging: confirm every consumer repo has an adoption issue filed") lived only in the risk register, which is not the document anyone stands in front of at release time. That is exactly how 2.0.0 reached "ready to tag" with zero adoption issues filed: the rule existed and was invisible at the moment it applied. The checklist sits immediately before `gh release create` — the point of no return, since a PyPI version can never be reused — and §C now points at it. Six items for every release, three for MAJORs only. Short enough to actually run. Two choices worth recording. The consumer-discovery step tells you to find the pinned repos **by their pins**, with the command, rather than from memory; a remembered list is how a fourth consumer gets missed. And it stays prose rather than a script: the adoption-issue condition needs network and cross-repo credentials, which the `docs` CI job deliberately does not have. The static half of this problem is check 10; this is the half a human has to read. Walked against the current state rather than asserted to work: CI green on the exact commit PASS (11/11) validate_docs.sh PASS check_arch_tree.py PASS twine check PASS wheel carries 3 packages + py.typed PASS CHANGELOG entry, no [Unreleased] PASS adoption issue per pinned consumer *** FAIL — 0 of 3 *** conformance floor decided PASS ADR records decision + migration PASS The one failure is the omission this release actually has. The checklist would have caught it before the tag, which is the only claim being made for it. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/publishing-to-pypi.md | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/guides/publishing-to-pypi.md b/docs/guides/publishing-to-pypi.md index 957c02c..1c40e90 100644 --- a/docs/guides/publishing-to-pypi.md +++ b/docs/guides/publishing-to-pypi.md @@ -49,6 +49,47 @@ trusted-publisher config — see Prerequisites. --- +### Pre-tag checklist — run this before `gh release create` + +`gh release create` is the point of no return: it publishes, and a PyPI version can never +be reused. Everything below is checkable in about two minutes. Tick it. + +**Every release** + +- [ ] CI is green on **the exact commit you are about to tag**, not merely on the branch: + `gh api repos/views-platform/views-frames/commits/$(git rev-parse main)/check-runs -q '.check_runs[]|"\(.conclusion) \(.name)"'` +- [ ] `bash docs/validate_docs.sh` passes (this includes the README banner and the + wheel-package checks) +- [ ] `python3 scripts/check_arch_tree.py` passes +- [ ] `rm -rf dist && uv build && uvx --from twine twine check dist/*` — both artifacts PASSED +- [ ] the built wheel carries **every** package in `[tool.hatch.build.targets.wheel] packages` + with its `py.typed` +- [ ] `CHANGELOG.md` has an entry for this version and no `[Unreleased]` section remains + +**MAJOR only — the expensive ones** + +- [ ] **An adoption issue is filed in every pinned consumer repository.** Register **C-13**'s + trigger requires this *before tagging*, and `GOVERNANCE.md` §Cross-repo MAJOR-bump + process step 3 says the same. Find the consumers by their pins, not from memory: + ```bash + for r in $(gh repo list views-platform --limit 50 --json name -q '.[].name'); do + gh api "repos/views-platform/$r/contents/pyproject.toml" -q .content 2>/dev/null \ + | base64 -d 2>/dev/null | grep -q "views-frames" && echo "$r" + done + ``` +- [ ] The **conformance floor** decision is made and recorded — `CONFORMANCE_FLOOR` is bumped + on any breaking change to any published entry point (`GOVERNANCE.md`), and moving it + means every consumer's CI begins asserting a new contract version. +- [ ] An ADR records the decision and the migration (`GOVERNANCE.md` MAJOR process step 1). + +> **Why this exists.** Until 2026-08-18 C-13's requirement lived only in the risk register, +> which is not the document anyone stands in front of at release time. 2.0.0 reached +> "ready to tag" with **zero** adoption issues filed — the rule existed and was invisible at +> the moment it applied. A pre-release falsification audit caught it; this checklist is so +> the next one does not need to. + +--- + ## Prerequisites (one-time setup) — Trusted Publishing The release workflow authenticates with **Trusted Publishing (OIDC)** — there is **no @@ -165,6 +206,9 @@ record of what was published. gh release create vX.Y.Z --target main --title "views-frames X.Y.Z" --notes "what changed" ``` It runs the **version guard**, `uv build`, `uv publish` via **Trusted Publishing**. +4½. **Before step 4 fires, walk the [pre-tag checklist](#pre-tag-checklist--run-this-before-gh-release-create).** + It is short, and it is the step that catches the expensive omissions — a MAJOR whose + consumers have not been told, a conformance floor nobody decided. 5. **Verify:** Actions → *Publish Package* green, then https://pypi.org/project/views-frames/. > Under the hood: `release: published` → `permissions: id-token: write` mints an OIDC