Skip to content

fix(release): unblock tagging — drop the self-defeating README slug rewrite, compare versions not strings - #12

Merged
wshallwshall merged 1 commit into
mainfrom
release-slug-fix
Jul 27, 2026
Merged

fix(release): unblock tagging — drop the self-defeating README slug rewrite, compare versions not strings#12
wshallwshall merged 1 commit into
mainfrom
release-slug-fix

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

Two defects, either of which fails a tag push on its own. Runbook F.1 could not be performed until both were fixed.

1. The README slug rewrite failed unconditionally

publish.ps1 used to rewrite the private source slug to the public mirror's before build embedded README.md as the PyPI long_description. That rewrite had been applied to this workflow itself, so at the cutover both sides of the substitution collapsed to the same string — a sed replacing the public slug with itself, followed by a guard that fails if that slug appears in the README. It appears 19 times.

So every tag push died there. Not hypothetical: the v0.3.0 tag (2026-07-13) failed at this exact step, which is why the repo has zero published releases.

Removed outright — there's one repo now and the README already names it, so there is nothing to rewrite. Same root cause as the release job's inverted if: guard fixed in #7.

2. Tag-vs-built compared as strings, in both jobs

The trigger only fires on vX.Y.Z / vX.Y.Z-*, so a pre-release tag must carry a hyphen — while hatchling and PyPI normalise 0.3.0-rc10.3.0rc1. A raw compare forced __version__ to hold the non-canonical "0.3.0-rc1" purely to satisfy the gate, meaning the tag, the module attribute and the wheel filename could never all be canonical at once.

In the harness job it was worse than awkward: built is parsed from the already-normalised wheel filename, so the compare could never match a pre-release tag. And with PUBLISH_HARNESS=true that job runs after the engine has uploaded — so it would fail half-published.

Both now compare packaging.Version objects. Verified against the real logic:

__version__ tag result
0.3.0rc1 v0.3.0-rc1 match
0.3.0-rc1 v0.3.0-rc1 match
0.3.0 v0.3.0-rc1 mismatch
0.3.1 v0.3.0 mismatch

Tests

Both pinned and mutation-verified: restoring the slug step fails, restoring the string compare fails. The existing "version==tag comparison" canary tracked the raw shell test by its exact spelling, so it's retargeted at the check rather than its wording — otherwise it would have blocked the fix while claiming to protect it.

Still owner-only for F.1

  • A messagefoundry-harness PyPI Trusted Publisher — PUBLISH_HARNESS is already true, so that job will attempt an upload on the next tag.
  • Setting __version__ to the rc being cut — canonical 0.3.0rc1 now works, tagged v0.3.0-rc1.
  • The tag itself, which publishes to production PyPI. There is no TestPyPI route.

🤖 Generated with Claude Code

…ewrite, compare versions not strings

Two defects, either of which fails a tag push on its own. Runbook F.1 ("validate the release under the
new OIDC binding") could not be performed until both were fixed.

1. THE README SLUG REWRITE FAILED UNCONDITIONALLY. publish.ps1 used to rewrite the private source slug
   to the public mirror's before `build` embedded README.md as the PyPI long_description. That rewrite
   had been applied to this workflow itself, so at the cutover both sides of the substitution collapsed
   to the same string: the sed replaced the public slug with itself (a no-op) and the guard after it
   failed if that slug appeared in the README -- which it does, 19 times. Every tag push died there.
   That is not hypothetical: the v0.3.0 tag (2026-07-13) failed at this exact step, which is why the
   repo has ZERO published releases. Removed outright -- there is one repo now and README.md already
   names it, so there is nothing to rewrite. Same root cause as the release job's inverted `if:` guard
   fixed in #7: mirror-era logic the slug rewrite mangled and the cutover left behind.

2. TAG-VS-BUILT COMPARED AS STRINGS, IN BOTH JOBS. The trigger only fires on `vX.Y.Z` / `vX.Y.Z-*`, so
   a pre-release tag must be spelled with a hyphen -- while hatchling and PyPI normalise `0.3.0-rc1` to
   `0.3.0rc1`. A raw compare therefore forced __version__ to carry the non-canonical "0.3.0-rc1" purely
   to satisfy the gate, and the tag, the module attribute and the wheel filename could not all be
   canonical at once. In the HARNESS job it was worse than awkward: `built` is parsed out of the
   already-normalised wheel FILENAME, so the compare could NEVER match a pre-release tag -- and with
   PUBLISH_HARNESS=true that job runs AFTER the engine has uploaded, so it would fail half-published.
   Both now compare packaging.Version objects; a genuine mismatch still fails loudly.

Verified by running the real comparison: 0.3.0rc1 vs tag v0.3.0-rc1 matches; 0.3.0-rc1 matches; 0.3.0
vs v0.3.0-rc1 does not; 0.3.1 vs v0.3.0 does not.

Tests pin both, mutation-verified: restoring the slug step fails, and restoring the string compare
fails. The existing "version==tag comparison" canary tracked the raw shell test by its exact spelling,
so it is retargeted at the CHECK rather than its wording.

STILL OWNER-ONLY for F.1, unchanged by this commit:
  * a `messagefoundry-harness` PyPI Trusted Publisher (PUBLISH_HARNESS is already true, so the harness
    job WILL attempt an upload on the next tag);
  * setting __version__ to the rc being cut -- canonical `0.3.0rc1` now works, tagged `v0.3.0-rc1`;
  * the tag itself, which publishes to PRODUCTION PyPI (there is no TestPyPI route).
@wshallwshall
wshallwshall enabled auto-merge (squash) July 27, 2026 16:50
@wshallwshall wshallwshall mentioned this pull request Jul 27, 2026
@wshallwshall
wshallwshall merged commit 2778f8f into main Jul 27, 2026
32 checks passed
wshallwshall added a commit that referenced this pull request Jul 27, 2026
Bumps the single-sourced version and cuts the CHANGELOG's Unreleased section into a dated 0.3.1
release. `messagefoundry/__init__.py` is the only version to edit -- packaging/messagefoundry-harness
reads it via `[tool.hatch.version] path = "../../messagefoundry/__init__.py"`, so both wheels ship
matched, which the release workflow then asserts against the tag.

Also repairs the CHANGELOG's compare links, which the 0.3.0 release never updated: `[Unreleased]` still
pointed at v0.2.10 and there was no `[0.3.0]` definition at all, so five versions of "what changed in
this release" rendered as dead links. Added 0.3.1 down to 0.2.11.

Other files matching "0.3.0" were checked and deliberately left alone -- they are synthetic fixtures
and comment examples (tests/test_sbom_finalize.py's inline __version__ string, test_update_check.py's
comparator cases, a docstring in pipeline/update_check.py), not the shipped version.

NOTE for the tag: v0.3.1 must be cut from a commit that already contains the release.yml fix (#12).
Before it, every tag push dies at the README slug-rewrite step -- which is exactly what happened to
v0.3.0 on 2026-07-13.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant