pyproject.toml carried a static version while releases are derived from conventional commits and tagged by CI. The first release after the packaging change was cut as v0.4.0 while the file still declared 0.3.0, so both the Python package metadata and the Nix store path understated the release.
Why a human cannot fix this by hand
The version is computed from commit messages since the last tag and is only known inside the release job, after the build. The pull request that causes a release cannot know the number it will produce — especially with more than one PR in flight. Any hand-set value drifts again at the next release.
The fix
The release job now writes the computed version into pyproject.toml, commits it as chore(release): vX.Y.Z, and tags that commit.
Neither push re-triggers the workflow: it listens on main only for the image-affecting paths, and pyproject.toml is not one of them.
chore(release) produces no bump of its own on the next run.
The branch push is ordered before the tag push, so a rejected push (main moved on) cannot leave a tag pointing at a commit that is not on main.
pyproject.toml is bumped to 0.4.0 here to correct today's state; from the next release onward CI maintains it, and a comment in the file says so.
Verification
The version-rewrite step was extracted from the workflow and run against a copy of pyproject.toml: the line is rewritten, and the step raises if it ever finds no version line rather than silently doing nothing.
bash -n on the step, nix flake check green at 0.4.0.
main has no branch protection rules, so the job's push will be accepted. If you ever add protection, the CI token needs an exemption or this step fails.
## The defect
`pyproject.toml` carried a static version while releases are derived from conventional commits and tagged by CI. The first release after the packaging change was cut as **v0.4.0** while the file still declared `0.3.0`, so both the Python package metadata and the Nix store path understated the release.
## Why a human cannot fix this by hand
The version is computed from commit messages *since the last tag* and is only known inside the release job, after the build. The pull request that causes a release cannot know the number it will produce — especially with more than one PR in flight. Any hand-set value drifts again at the next release.
## The fix
The release job now writes the computed version into `pyproject.toml`, commits it as `chore(release): vX.Y.Z`, and tags **that** commit.
- Neither push re-triggers the workflow: it listens on `main` only for the image-affecting paths, and `pyproject.toml` is not one of them.
- `chore(release)` produces no bump of its own on the next run.
- The branch push is ordered before the tag push, so a rejected push (main moved on) cannot leave a tag pointing at a commit that is not on `main`.
- `pyproject.toml` is bumped to `0.4.0` here to correct today's state; from the next release onward CI maintains it, and a comment in the file says so.
## Verification
- The version-rewrite step was extracted from the workflow and run against a copy of `pyproject.toml`: the line is rewritten, and the step raises if it ever finds no version line rather than silently doing nothing.
- `bash -n` on the step, `nix flake check` green at 0.4.0.
- `main` has no branch protection rules, so the job's push will be accepted. If you ever add protection, the CI token needs an exemption or this step fails.
The version in pyproject.toml was static, while releases are derived from
conventional commits and tagged by CI. The first release after packaging was
cut as v0.4.0 while the file still declared 0.3.0, so the Python package and
the Nix store path both understated the release.
The version cannot be set by hand in the pull request that causes a release:
it is computed from the commit messages and is only known inside the release
job. So the release job now writes it into pyproject.toml, commits it as
chore(release), and tags that commit.
Neither push re-triggers the workflow -- it listens on main only for the
image-affecting paths, and pyproject.toml is not one of them -- and the
chore(release) subject produces no bump of its own on the next run. The branch
push is ordered before the tag push so a rejected push cannot leave a tag
pointing at a commit that is not on main.
pyproject.toml is bumped to 0.4.0 here to correct the current state; from the
next release onward CI maintains it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The defect
pyproject.tomlcarried a static version while releases are derived from conventional commits and tagged by CI. The first release after the packaging change was cut as v0.4.0 while the file still declared0.3.0, so both the Python package metadata and the Nix store path understated the release.Why a human cannot fix this by hand
The version is computed from commit messages since the last tag and is only known inside the release job, after the build. The pull request that causes a release cannot know the number it will produce — especially with more than one PR in flight. Any hand-set value drifts again at the next release.
The fix
The release job now writes the computed version into
pyproject.toml, commits it aschore(release): vX.Y.Z, and tags that commit.mainonly for the image-affecting paths, andpyproject.tomlis not one of them.chore(release)produces no bump of its own on the next run.main.pyproject.tomlis bumped to0.4.0here to correct today's state; from the next release onward CI maintains it, and a comment in the file says so.Verification
pyproject.toml: the line is rewritten, and the step raises if it ever finds no version line rather than silently doing nothing.bash -non the step,nix flake checkgreen at 0.4.0.mainhas no branch protection rules, so the job's push will be accepted. If you ever add protection, the CI token needs an exemption or this step fails.