From 762241f73fba8cb932857879de0b33752e9af3d9 Mon Sep 17 00:00:00 2001 From: chris-colinsky Date: Sun, 4 Oct 2026 23:27:57 -0700 Subject: [PATCH 1/2] Name the changelog timezone and all five version places Two gaps that each cost time during the v0.17.0 release. The changelog date requirement never named a timezone. A tag pushed in the evening US-Pacific carries a UTC timestamp on the next day, so for a few hours every night the two disagree and a reviewer reading UTC calls a correct heading stale, which is exactly what happened on #309. The convention the tags actually show is the maintainer's local day: v0.16.0 and v0.14.0 both have headings a day behind their UTC timestamps. v0.15.0 is the counter-example and it is simply wrong, a day behind its own local tag day. The version-bump item named three files. Five carry it. uv.lock locks the local package's own version and the bundled AGENTS.md stamps it into its header, and neither fails anything until an artifact is built, so both are easy to miss. They are generated, so the doc says to run the generator rather than hand-edit. Also records why the rc and real-release bumps cannot be one commit, in the place someone reads while doing it rather than in the comment at the top of the workflow. --- RELEASING.md | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index faaa1e44..18fdca60 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -39,7 +39,17 @@ changelog entry. - [ ] **`CHANGELOG.md` is current.** Every commit since the previous release that changed user-visible behavior is reflected in the upcoming version's section. The date matches the day the rc tag - is pushed (refresh it again at the real-release step). + is pushed (refresh it again at the real-release step), **in the + releasing maintainer's local timezone, not UTC.** A tag pushed in + the evening US-Pacific carries a UTC timestamp on the following + day, so the two disagree for a few hours every night and a + reviewer reading UTC will call a correct heading stale. The + heading is a human record of when the work landed, so it follows + the human. Set it immediately before merging the version bump, + because setting it any earlier is what produces drift: v0.15.0 + shipped a heading a day behind its own tag, and v0.17.0's was + nine days stale mid-cycle and needed correcting twice before it + was right at tag time. - [ ] **`conformance.toml` is current.** Any proposal whose impl landed in this cycle has its `[proposals."NNNN"]` entry — either newly added (set `since` to the version about to ship) or @@ -63,8 +73,19 @@ changelog entry. "0.7.0"`. The rc and real-release pyproject bumps are SEPARATE COMMITS — one before each tag — because the normalized forms differ. - Also update `src/openarmature/__init__.py`'s `__version__` and - `tests/test_smoke.py`'s version assertion in the same commit. + The version lands in **five** files, and two of them are easy to + miss because nothing fails until the artifact is built: + - `pyproject.toml` — `project.version` + - `src/openarmature/__init__.py` — `__version__` + - `tests/test_smoke.py` — the version assertion + - `uv.lock` — locks the local package's own version; `uv sync` or + any `uv run` refreshes it + - `src/openarmature/AGENTS.md` — stamps `version X.Y.Z (spec + vA.B.C)` into its header; regenerate with + `uv run python scripts/build_agents_md.py` + All five in the same commit. The last two are generated, so run + the generator and let `uv` touch the lock rather than editing + either by hand. - [ ] **Branch state.** On `main`, clean working tree, latest pulled. Release tags should point at commits already on `main`. - [ ] **CI is green on `main`.** The release workflow's `test` job From 0a675fc9aba35077b8fa35351f15b1cacac3439b Mon Sep 17 00:00:00 2001 From: chris-colinsky Date: Sun, 4 Oct 2026 23:36:24 -0700 Subject: [PATCH 2/2] Name what catches a missed version file The claim that nothing fails until the artifact is built was wrong three ways. A stale uv.lock fails the uv-lock pre-commit hook at commit time and uv sync --frozen in both CI and the release workflow; a stale bundled AGENTS.md fails test_agents_md_matches_generator_output. Saying no signal exists when three do is worse than saying nothing, because it teaches a maintainer not to look for the failure that will actually stop them. The two generated files are easy to miss because the checklist omitted them, not because they go undetected: you found out from a failing hook instead of from the doc, which is backwards for a checklist meant to prevent surprises. Naming each mechanism is the more useful form anyway, since it says which failure corresponds to which omission. --- RELEASING.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 18fdca60..648ffffb 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -73,8 +73,7 @@ changelog entry. "0.7.0"`. The rc and real-release pyproject bumps are SEPARATE COMMITS — one before each tag — because the normalized forms differ. - The version lands in **five** files, and two of them are easy to - miss because nothing fails until the artifact is built: + The version lands in **five** files: - `pyproject.toml` — `project.version` - `src/openarmature/__init__.py` — `__version__` - `tests/test_smoke.py` — the version assertion @@ -86,6 +85,13 @@ changelog entry. All five in the same commit. The last two are generated, so run the generator and let `uv` touch the lock rather than editing either by hand. + Each of the last two is caught, so an omission shows up as a + failure rather than as a bad artifact — the point of listing them + is to know which failure means what: + - a stale `uv.lock` fails the `uv-lock` pre-commit hook at commit + time, and `uv sync --frozen` in both CI and the release workflow + - a stale bundled `AGENTS.md` fails + `test_agents_md_matches_generator_output` - [ ] **Branch state.** On `main`, clean working tree, latest pulled. Release tags should point at commits already on `main`. - [ ] **CI is green on `main`.** The release workflow's `test` job