Release PRs Must Own Derived Version State
Release PRs must own derived version state
A release PR is not coherent just because the human-facing version files changed. It also has to update the derived files that the build treats as truth.
The spotuify failure was a clean example. Release Please opened the release PR and bumped .release-please-manifest.json plus the workspace version in Cargo.toml. That part was correct. But Cargo.lock still carried the old workspace package versions, and CI ran Cargo with --locked. Cargo refused to build.
That was not CI being fussy. It was CI catching a split-brain release: the manifest said one version, the lockfile said another.
The rule
When release automation updates version declarations, it must also update any generated or derived version state that downstream tools read as authoritative.
For Rust workspaces, that usually means:
cargo update --workspace
For other ecosystems it might be a package lockfile, generated OpenAPI metadata, SDK version tables, Homebrew formula inputs, or docs-site metadata. The exact file changes. The shape is the same.
What changed in spotuify
spotuify now keeps the responsibility explicit:
- Release Please owns the release PR, changelog, manifest, and
Cargo.toml. .github/workflows/release-lockfile.ymlruns only on same-repo release-please PRs.- That workflow runs
cargo update --workspace. - If
Cargo.lockchanges, it commits the lockfile back to the release PR. - CI keeps using
--locked.
That last line matters. The fix was not to loosen the gate. The fix was to make the release PR carry the full version graph.
Why this generalizes
Derived files are easy to treat as clerical. They are not. They are the files package managers, release builders, docs sites, and installers actually consume.
The question to ask in any release system is: after the version bump, what other checked-in file can still describe the old product? Make the automation update that file, or make CI fail when it drifts.
What mxr added
mxr hit the same class twice.
The release PR path did carry Cargo.lock after the 0.5.59 and 0.5.61
bumps. That kept cargo --locked honest.
The docs site still drifted: site/public/openapi.json reported 0.5.58 while
the repo was at 0.5.61. The API routes generated from code, but the committed
metadata still told API explorers and agents they were looking at an older
surface. This is a softer failure than a lockfile build break, but it is the
same family. Release PRs need to own generated docs metadata too.