release-bump derives the target version from planning docs nothing keeps current, so an off-roadmap release can silently downgrade the manifest #87
Labels
No labels
already-shipped
bug
documentation
duplicate
enhancement
good first issue
help wanted
in progress
invalid
needs-decision
proposal
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: crenshawdev/cadence#87
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What happened
Opening v2.0.0 turned up that
.planning/PROJECT.md,REQUIREMENTS.mdandROADMAP.mdall still namedv1.4.0as the current release, two releases after it shipped.v1.4.1andv1.5.0both went out as issue-driven/cad-taskwork with no cycle open, and nothing on that path writes the version back:/cad-milestoneis what evolves PROJECT.md, and it only runs when a cycle closes.On its own that is cosmetic. What makes it a bug is that
release-bump.mjsreads those files.The actual failure
deriveTargetVersiontakes the first version-shaped token in PROJECT.md's### Activebody, falling back to the ROADMAP title. Between cycles that body opens with the version that just closed:So at the v1.5.0 cut, with the manifest sitting at
1.4.1, the derivation returned a version that had already shipped. Reproduced against the exact tree ata1453c3:A downgrade,
ok: true, nothing said. It did not happen only because that cut passed--version 1.5.0explicitly, and an explicit version wins the precedence. Nothing about the drift was load-bearing on the decision to pass it.Two separable defects
1. Nothing keeps the planning docs current when a release ships outside a cycle.
/cad-healthchecks presence, cursor schema, phase numbering and traceability consistency, and never reads.claude-plugin/plugin.json./cad-audittraces requirements to phases, not versions. self-verify touches plugin.json only to decide whether it is looking at a full tree. The drift is invisible to all three, which is why it survived two releases and was caught by a human reading the file.2.
decideManifestBumphas no monotonicity check. Handed a target below the manifest's current version it returnsbumplike any other change. An already-published version is the one input that can never be a valid target, and a stale### Activeproduces exactly that.Defect 2 is the cheap guard and it closes the sharp edge by itself. Defect 1 is the one worth thinking about, because the same stale prose is also what
branch-decision.mjsreads.What you want Cadence to do
decideManifestBumpreturns an error rather thanbumpwhen the target is at or below the current manifest version by semver comparison, naming both versions in the reason. The existingnoopon an equal version already half-states this rule; it just stops short of the case that matters./cad-healthrule comparing plugin.json'sversionagainst the version the planning docs name, reported and never auto-fixed, is the smallest thing that would have caught this. It belongs to rule 5's consistency family.### Activeshould name, if anything. The derivation reads that token as "the version we are shipping"; the prose there means "the version that just shipped". Those are opposite readings of the same bytes, and reconciling them is a design call rather than a patch. Either the closed-milestone prose names the next version, or it puts the shipped one somewhere the derivation does not scan.Reproduction
More generally: ship any release without an open cycle, then run
bumpwith no--versionbefore the next cycle opens.Files this touches
cadence-core/bin/lib/release-decision.mjs,cadence-core/bin/lib/branch-decision.mjs(activeVersionis shared with branch derivation),cadence-core/bin/release-bump.test.mjs,skills/cad-health/SKILL.md.Notes
Fixed for this tree by hand at the v2.0.0 open (
c57568c): the planning docs now record v1.4.1 and v1.5.0, and the derivation returns2.0.0, which is correct for the next cut. The failure mode returns on the next release that ships outside a cycle.Related: #86, the other
release-bumpdefect from the same v1.5.0 cut. Both were caught by reading the output rather than by any check, which is the pattern worth noticing.