The bug
Repos store real version numbers in their source manifests (package.json, pubspec.yaml, *.csproj, Cargo.toml, shipwright.json). Every release then bumps those fields and commits/PRs the bump back — producing version churn on tracked source on every single release.
The correct, universal behaviour:
- Every package carries a placeholder version (
0.0.0-dev) in source so it runs/builds locally.
- On deployment, the git tag is the single source of truth for the version — it is stamped into the artifacts at build time, in the runner working tree only, and is never committed back.
This is not monorepo- or registry-specific. It applies to every Shipwright repo and every language.
Status of the spec
[SWR-VERSION-BUILD-STAMPING] already states this rule correctly and universally — "All version fields in source (Cargo.toml, package.json, *.csproj, pubspec.yaml, shipwright.json) MUST be 0.0.0-dev on every branch at all times" and "Release jobs MUST NOT commit, push, or move source-control refs after the tag exists."
So the rule is clear. What's missing is enforcement — nothing fails when a repo drifts off the placeholder, so the churn keeps happening in practice.
Ask
Add an acceptance gate ([SWR-GATE-*]) that:
- Scans every version carrier in the repo (
package.json, pubspec.yaml, *.csproj, Cargo.toml, shipwright.json, …).
- Fails the build if any of them is not the
0.0.0-dev placeholder (on PRs and on main), with a message pointing at the offending file/line.
- Is wired into the standard CI gate so a real version can never be committed to source.
That turns the existing rule from documentation into something that is actually enforced, which is what prevents the churn.
Real-world trigger
MelbourneDeveloper/dart_node (Dart → pub.dev) had real versions (0.11.0-beta, and one package hard-coded at the release version 0.13.0-beta) sitting in pubspec.yaml, and its release flow committed/PR'd the bumps back to main. Fixed by resetting every version: to 0.0.0-dev and stamping the tag version in the runner at publish time (zero source churn) — but only after the drift had already shipped, because no gate caught it.
(Edited: this issue originally and incorrectly framed the problem as a monorepo/registry gap. The placeholder rule is universal and already specified; the real gap is enforcement.)
The bug
Repos store real version numbers in their source manifests (
package.json,pubspec.yaml,*.csproj,Cargo.toml,shipwright.json). Every release then bumps those fields and commits/PRs the bump back — producing version churn on tracked source on every single release.The correct, universal behaviour:
0.0.0-dev) in source so it runs/builds locally.This is not monorepo- or registry-specific. It applies to every Shipwright repo and every language.
Status of the spec
[SWR-VERSION-BUILD-STAMPING]already states this rule correctly and universally — "All version fields in source (Cargo.toml,package.json,*.csproj,pubspec.yaml,shipwright.json) MUST be0.0.0-devon every branch at all times" and "Release jobs MUST NOT commit, push, or move source-control refs after the tag exists."So the rule is clear. What's missing is enforcement — nothing fails when a repo drifts off the placeholder, so the churn keeps happening in practice.
Ask
Add an acceptance gate (
[SWR-GATE-*]) that:package.json,pubspec.yaml,*.csproj,Cargo.toml,shipwright.json, …).0.0.0-devplaceholder (on PRs and onmain), with a message pointing at the offending file/line.That turns the existing rule from documentation into something that is actually enforced, which is what prevents the churn.
Real-world trigger
MelbourneDeveloper/dart_node(Dart → pub.dev) had real versions (0.11.0-beta, and one package hard-coded at the release version0.13.0-beta) sitting inpubspec.yaml, and its release flow committed/PR'd the bumps back tomain. Fixed by resetting everyversion:to0.0.0-devand stamping the tag version in the runner at publish time (zero source churn) — but only after the drift had already shipped, because no gate caught it.(Edited: this issue originally and incorrectly framed the problem as a monorepo/registry gap. The placeholder rule is universal and already specified; the real gap is enforcement.)