Skip to content

Specify the API version stamps' phase 2 - #331

Merged
bjlittle merged 2 commits into
mainfrom
stamps-spec
Sep 15, 2026
Merged

bjlittle merged 2 commits into
mainfrom
stamps-spec

Conversation

@bjlittle

Copy link
Copy Markdown
Owner

Specifies phase 2 of #227's API version stamps as a new living specification, stamps spec (docs/src/developer/specs/2026-09-15-api-stamps-design.md), and adds it to the specifications index. Specification only — the plan and the build follow as their own pull requests, and the build closes #227. It must merge before the v0.1.0 release candidate: without it the rehearsal's merge-back turns main red.

Why now

The gate's phase-1 rule — every published object cites the target, the base version the next tag will carry — is exact only while nothing has been released. Measured in a throwaway clone of main at 1ffb603, it stops being right at the first merge-back of any tag, a release candidate included, not at the release itself:

repository state setuptools_scm target tests/test_api_docstrings.py
main, no tag 0.1.0.dev223 0.1.0 52 passed
tag v0.1.0rc1 on v0.1.x 0.1.0rc1 0.1.0 52 passed
main after merging v0.1.x back 0.2.0.dev2 0.2.0 3 failed

The failures are the hard-coded "0.1.0" in the version test, all 94 stamps ("cites 0.1.0, expected 0.2.0"), and main() returning 1 — over stamps that are all correct. The release runbook's Two gates will move at the first tag note had the timing wrong.

The design

  • A committed snapshot, .github/api-surface.txt, written at the release freeze (runbook step 4) by check_api_docstrings.py --write-snapshot, which refuses to write unless every object passes and a target can be derived. An object it records keeps its recorded version; an object it does not record cites the target. The snapshot half needs no derived version, so it keeps working in shallow clones.
  • No snapshot means phase 1, so the build can land before any tag.
  • Removals are ignored until the next freeze rewrites the file; a renamed object is new and cites the target.
  • The merge-back goes through a branch named merge-back (runbook step 10). An object merged into main after the release branch is cut must cite 0.1.0 before the merge-back and 0.2.0 after, and the target moves in the merge commit — a pull request from vA.B.x cannot contain the re-stamp, and main's protection requires the checks to pass.

Two things designing it got wrong first, both measured before this was written

  1. The merge-back. The first draft said a mis-stamped new object could be re-stamped in the merge-back pull request. It cannot — the release branch does not contain it — which is the deadlock shape Let the pre-release note come out before the tag, not after #317 was. The dedicated branch is the fix.
  2. The branch name. semver-pep440-release-branch reads any branch name containing a version as a release branch. Measured: merge-back-v0.1.x and merge-back/0.1 derive 0.1.0rc2.dev2 locally while pull-request CI derives 0.2.0.dev2 — a correct re-stamp would fail locally and pass in CI. merge-back and merge-back-release derive 0.2.0.dev2, agreeing with CI. §3.4 records the table, and a trap for whoever re-measures: tagging and merging with no commit on the release branch makes no merge commit and passes for the wrong reason.

Verification

On 427e8e4: every hook passes on the two changed files; tests/test_citations.py, tests/test_github_references.py, tests/test_docs_readingtime.py and tests/test_docs_landing_pages.py — 283 passed; a fail-on-warning docs build with no warnings, and check_rendered_citations.py and check_documentation_links.py both pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01C79QePZ862i61EJodupwVT

The versionadded gate's phase-1 rule — every published object cites the
target — turns main red at the first merge-back of any tag, a release
candidate included: measured in a throwaway clone, main derives 0.2.0.dev
after merging v0.1.x back and three tests in tests/test_api_docstrings.py
fail over 94 correct stamps.

stamps spec records the whole rule and phase 2: a committed snapshot of the
published API, written at the release freeze, keeps released objects on their
recorded version while new objects cite the target; removals are ignored
until the next freeze; and the merge-back goes through a versionless branch,
the one route by which a new object on main can be re-stamped without
turning main red. The measured version tables are recorded, including why a
versioned branch name disagrees with pull-request CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C79QePZ862i61EJodupwVT
@bjlittle bjlittle added the type: documentation Auto-labelled for doc/* and docs/* branches label Sep 15, 2026
@bjlittle
bjlittle deployed to development September 15, 2026 19:59 — with GitHub Actions Active
@bjlittle bjlittle moved this from Backlog to In review in 🥾 Bootstrap Sep 15, 2026
@bjlittle
bjlittle merged commit b8e5cb1 into main Sep 15, 2026
14 checks passed
@bjlittle
bjlittle deleted the stamps-spec branch September 15, 2026 21:21
@bjlittle
bjlittle deployed to development September 15, 2026 21:21 — with GitHub Actions Active
@github-project-automation github-project-automation Bot moved this from In review to Done in 🥾 Bootstrap Sep 15, 2026

This branch was successfully deployed

1 active deployment
development 9a3d3f64 Deployed Sep 15, 2026 by bjlittle via welcome #107
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: documentation Auto-labelled for doc/* and docs/* branches

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Public API docstrings carry no versionadded, and nothing could tell

1 participant