changelog: nothing notices a DELETED release heading — arming is green on a tree that erased a shipped section #98
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:bootstrap
scope:coolify
scope:db
scope:docs
scope:drill
scope:installer
scope:labels
scope:platform
scope:runner
scope:users
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/rig#98
Loading…
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?
Nothing here notices a deleted release heading.
boxgrew a guard forthis (heavy-duty/box#122,
caught in review of box#118); rig never got it, and the invariant it protects
is the same one rig's release flow depends on.
What rig already has
To be clear about what is not missing: the arming rule is covered.
test/release.shdefineschangelog_armed()and asserts it against the realtree (
CHANGELOG.md: armed for the VERSION it carries (#66)). That is therig#66 fix and it works.
Arming is just narrow by design. It asks one question — does the top section
agree with
VERSION? — about one heading, the one a PR is about to writeunder. It says nothing about the rest of the file.
The gap
Release headings are append-only: the ceremony adds one and nothing in
CONTRIBUTING's release flow ever removes one. Nothing asserts that.
The failure is an author adding an entry under
## Unreleasedwho replacesthe heading below it instead of inserting above it:
git merges that cleanly — a one-line edit in a file nobody touched
concurrently, so no conflict and no signal.
changelog_armed()stays greenand is not wrong to: the top section is still the right one for
VERSION.0.2.0's body is now sitting under## Unreleased, and0.2.0has nosection at all.
It surfaces at the next release, in
changelog_section()(.github/scripts/release-lib.sh), which
anchors on the heading:
No heading, no section, and the release body is empty or wrong.
The duplicate half — rig fails differently from box, and it matters
box's guard also asserts version headings are unique on HEAD, because
containment cannot catch a duplicate (a duplicate is head-side surplus, and
base-minus-head is blind to it).
Worth noting rig's symptom here is not box's. box's
release-notes.shre-arms its grab on every matching
##line, so a duplicated heading makesit absorb whatever sits between the copies. rig's
changelog_sectionhasif (found) exit, so it stops at the first section instead — a duplicatetruncates, silently dropping everything after the second copy.
Different symptom, same class: silent, no conflict, no red run, discovered
only by a human reading the published notes. Both halves are worth having.
Proposal
Port
.github/scripts/changelog-monotonic.shfrom box, and wire it inci.ymlthe way box does:Three details from box's version that should survive the port:
history, not two files; its degradation is different (no base ref is a skip,
not a failure); and rig's arming logic is driven from
test/release.shagainst constructed non-git trees, so folding a git-dependent assert into it
would make those cases either skip or lie.
assert is vacuous.
STRICT=1in CI. A checkout that cannot reach the base ref must failrather than skip quietly forever — needs
fetch-depth: 0on the PRcheckout, which
ci.ymldoes not currently set.## Unreleasedis deliberately outside the guarded set — the arming check ownsthat heading, and the ceremony legitimately consumes it.
Sibling issue for the same gap in cast: heavy-duty/cast#133.