Nothing keeps the planning docs' version current when a release ships outside a cycle, and the drift is invisible to health, audit and self-verify #87
Labels
No labels
already-shipped
bug
documentation
duplicate
enhancement
external-review
good first issue
help wanted
in progress
invalid
needs-decision
proposal
question
security
wontfix
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: crenshawdev/cadence-archived#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.Half of this shipped. Narrowing the issue to the half that did not, rather than closing it.
Fixed by v2.2.0 (REL-03):
release-bump.mjsderives no version of its own.--versionis required and the seam refuses without it (no-target-version), and a downgrade is refused outright instead of reportedok:true. The exact path reproduced here ata1453c3— derivation returning an already-shipped1.4.0against a1.4.1manifest — cannot be reached now, because there is no derivation left to return it.Still true — defect 1 as filed. Nothing keeps the planning docs' version current when a release ships outside a cycle, and nothing notices the drift:
/cad-health's five rules cover presence, the STATE cursor, ROADMAP phase grammar, the traceability table, and cursor/roadmap consistency. None reads.claude-plugin/plugin.json./cad-audittraces requirements to phases, not versions.self-verifytouchesplugin.jsononly to decide whether it is looking at a full tree (self-verify.mjs:298).What changed since filing is that the consequence is smaller: stale docs can no longer steer the manifest, because nothing reads them for a version. The drift is now a correctness problem in the docs themselves rather than a downgrade vector.
Re-verified against the tree at the v2.3.0 close.
release-bump derives the target version from planning docs nothing keeps current, so an off-roadmap release can silently downgrade the manifestto Nothing keeps the planning docs' version current when a release ships outside a cycle, and the drift is invisible to health, audit and self-verify