fix(release): bump to 0.4.0, and make the tag and the version agree - #93
Merged
Conversation
The 0.4.0 release failed to publish. `pyproject.toml` still said 0.3.0, so `python -m build` produced a 0.3.0 wheel and PyPI rejected it as a duplicate — after the GitHub release was already published. `twine check` and the cold install smoke test both passed, because neither validates identity. The version lived in two places with nothing making them agree, which is the hand-maintained projection DP-5 says will drift. It drifted on the first release after the convention was set. Bumps the version, and adds a build-job assertion that the built wheel matches the release tag (a leading `v` is tolerated) before the publish job runs. That is DP-5's rung 2 — guard the property. Rung 1 is deriving the version from the tag via hatch-vcs, which also needs `fetch-depth: 0` on the publish checkout; left as a follow-up rather than bundled into a release unblock. Guard verified against all three cases: tag 0.4.0 with a 0.3.0 wheel exits 1, matching versions pass, and a `v`-prefixed tag passes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012AWc5urqmvaJUhcvy1VWLM
dmarx
pushed a commit
that referenced
this pull request
Aug 16, 2026
#93 named the ladder and shipped rung 2: assert the built version equals the release tag. It deferred rung 1 — deriving the version — because switching to hatch-vcs without also fetching tags would have failed the release a second time by resolving to a `0.1.dev` fallback. This is rung 1, with the tag fetch that makes it safe. `pyproject.toml` declares `dynamic = ["version"]` with hatch-vcs reading `git describe`, so there is one source for the version rather than two that can disagree. The publish checkout takes `fetch-depth: 0`. No VCS version file is generated: nothing in the package reads its own version, and writing one out would reintroduce the hand-maintained copy this removes. #93's assertion stays. Deriving prevents the drift; the guard is what makes a recurrence loud rather than a PyPI rejection reached after the environment gate. The two are complementary, and DP-5's own ladder puts derive above guard rather than instead of it. A downstream data point for why the quiet failure matters: an adopting project ran `pip install luria` (0.3.0) while its CI pinned `dmarx/luria/actions/generate@main`. Local lint and CI lint were executing different code with nothing reporting it, because `pip install --upgrade luria` is a no-op while the release is missing. Verified: a clean checkout on the 0.4.0 tag builds `luria-0.4.0-py3-none-any.whl` — no `.devN`, no `+g` local segment, which matters because PyPI rejects local segments outright. A working-tree build produces `0.4.1.dev3+g0a80de972`, correctly unuploadable. 425 tests pass and `pip install -e .` still works. The ADR keeps its temporary code, as #88 did — `luria concretize` assigns the real number where merges serialize. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DpK3k2WhH9Pnc3i6TjLMVv
dmarx
pushed a commit
that referenced
this pull request
Aug 16, 2026
release tag. It deferred rung 1 — deriving the version — because switching to hatch-vcs without also fetching tags would have failed the release a second time by resolving to a `0.1.dev` fallback. This is rung 1, with the tag fetch that makes it safe. `pyproject.toml` declares `dynamic = ["version"]` with hatch-vcs reading `git describe`, so there is one source for the version rather than two that can disagree. The publish checkout takes `fetch-depth: 0`. No VCS version file is generated: nothing in the package reads its own version, and writing one out would reintroduce the hand-maintained copy this removes. a recurrence loud rather than a PyPI rejection reached after the environment gate. The two are complementary, and DP-5's own ladder puts derive above guard rather than instead of it. A downstream data point for why the quiet failure matters: an adopting project ran `pip install luria` (0.3.0) while its CI pinned `dmarx/luria/actions/generate@main`. Local lint and CI lint were executing different code with nothing reporting it, because `pip install --upgrade luria` is a no-op while the release is missing. Verified: a clean checkout on the 0.4.0 tag builds `luria-0.4.0-py3-none-any.whl` — no `.devN`, no `+g` local segment, which matters because PyPI rejects local segments outright. A working-tree build produces `0.4.1.dev3+g0a80de972`, correctly unuploadable. 425 tests pass and `pip install -e .` still works. The ADR keeps its temporary code, as #88 did — `luria concretize` assigns the real number where merges serialize. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DpK3k2WhH9Pnc3i6TjLMVv
dmarx
pushed a commit
that referenced
this pull request
Aug 16, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DpK3k2WhH9Pnc3i6TjLMVv
dmarx
added a commit
that referenced
this pull request
Aug 16, 2026
#94) * fix(release): derive the version from the tag, completing #93's rung 1 release tag. It deferred rung 1 — deriving the version — because switching to hatch-vcs without also fetching tags would have failed the release a second time by resolving to a `0.1.dev` fallback. This is rung 1, with the tag fetch that makes it safe. `pyproject.toml` declares `dynamic = ["version"]` with hatch-vcs reading `git describe`, so there is one source for the version rather than two that can disagree. The publish checkout takes `fetch-depth: 0`. No VCS version file is generated: nothing in the package reads its own version, and writing one out would reintroduce the hand-maintained copy this removes. a recurrence loud rather than a PyPI rejection reached after the environment gate. The two are complementary, and DP-5's own ladder puts derive above guard rather than instead of it. A downstream data point for why the quiet failure matters: an adopting project ran `pip install luria` (0.3.0) while its CI pinned `dmarx/luria/actions/generate@main`. Local lint and CI lint were executing different code with nothing reporting it, because `pip install --upgrade luria` is a no-op while the release is missing. Verified: a clean checkout on the 0.4.0 tag builds `luria-0.4.0-py3-none-any.whl` — no `.devN`, no `+g` local segment, which matters because PyPI rejects local segments outright. A working-tree build produces `0.4.1.dev3+g0a80de972`, correctly unuploadable. 425 tests pass and `pip install -e .` still works. The ADR keeps its temporary code, as #88 did — `luria concretize` assigns the real number where merges serialize. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DpK3k2WhH9Pnc3i6TjLMVv * docs: regenerate views after rebase onto #93's concretization Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DpK3k2WhH9Pnc3i6TjLMVv --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
0.4.0 is not on PyPI — the publish failed.
pip install luria==0.4.0reports available versions0.1.0, 0.1.1, 0.1.2, 0.2.0, 0.3.0.What happened
The
0.4.0tag points atf61282e(the #92 merge), whosepyproject.tomlstill saysversion = "0.3.0". Sopython -m buildproducedluria-0.3.0-py3-none-any.whl, and PyPI rejected it:after the GitHub release was already published. Both existing gates passed on the way through:
twine check dist/*validates metadata, not identity, and the cold-install smoke test exercisesluria init/index/new/linton a wheel that installs perfectly well — it's simply the wrong version.Why it's a DP-5 instance
The version lives in two places —
pyproject.tomland the git tag — with nothing making them agree. That is the hand-maintained projection DP-5 says will drift, and it drifted on the first release after the pattern was set. Nicely, it's the same principle #710 downstream was just annotated with.Rung 2 is what this PR does — guard the property rather than trust the copy:
It runs in
build, so it fails before thepublishjob and its environment gate are reached.Rung 1 would be better — derive the version from the tag with
hatch-vcs, so there is only one source. Deliberately not bundled here: the publish checkout isactions/checkout@v4at the defaultfetch-depth: 1with no tags fetched, so switching without also settingfetch-depth: 0would resolve to a0.1.dev…version and fail the release a second time. Worth its own PR.Verified
Fired the guard against all three cases before trusting it (DP-6):
luria-0.3.0-…whl0.4.0luria-0.4.0-…whl0.4.0luria-0.4.0-…whlv0.4.0421 tests pass;
luria lintclean.To actually ship 0.4.0
The
0.4.0tag points at a commit without the bump, so re-running the failed workflow rebuilds the same 0.3.0 wheel. After merging, either delete the0.4.0tag and release and re-cut them at the newmain(safe — nothing was ever published under it), or cut 0.4.1 if you'd rather never move a tag. Your call; I haven't touched the tag.Generated by Claude Code