recover-pending-cut restores fragments AND folds their entries back, so the re-prepare ships each fragment entry twice #1487
Labels
No labels
bump
major
bump
minor
bump
patch
kind
bug
kind
chore
kind
docs
kind
epic
kind
feature
loop/paused
mirror-drift
priority
critical
priority
high
priority
low
priority
medium
size
L
size
M
size
S
size
XL
status
blocked
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
frankenbit/release-toolkit#1487
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?
rt recover-pending-cutdoes two things with a stranded section, and they overlap:prepare^(restoreFragmentsFromPrepareParent, added for #1166 in #1182);## [Unreleased](changelog.FoldBackIntoUnreleased).So every fragment entry comes back with two sources: the restored file, and its rendered line under
[Unreleased]. The nextrt prepmerges the two ininternal/prep/prep.gomergeUnreleased→changelog.MergeSections(internal/changelog/merge.go), which concatenates per kind without dedup. Each fragment entry ships twice.Measured
Strand a real prepare (
[Unreleased]prose plus two fragments), recover, re-prepare. Onmain@02fae6a:The re-prepared
### Fixedreads:Nothing catches it
rt changelog-body-checkon that doubled section: all nine checks PASS, rc=0 (measured). Its check 6 grades duplicate version sections and duplicate###headers, not duplicate entries.TestRecoverPendingCutFoldThenRepreparecomposes exactly this section but never counts bullets, so it stays green.Why it matters
Recovery (B) is the documented remedy for a stranded cut. Today the remedy produces a rolling PR whose notes double every fragment entry, and every gate passes it. Once the cut tags, the doubled notes are in a published release.
Acceptance criteria
[Unreleased], and the re-prepared section renders it once (both re-composed and sealed). — DONE @#1490(7bfd0ba, reviewed as7bfd0ba).TestRecoverPendingCutReprepareRendersEachEntryOncecounts every entry at 1 re-composed and 1 sealed, and asserts the re-prepared section equals the stranded one.[Unreleased]prose that the prepare composed into the section survives recovery exactly once. Fixing the duplicate by restoring fragments instead of folding would silently drop it. — DONE @#1490(7bfd0ba, reviewed as7bfd0ba). The same test counts the hand-written #1001 entry at 1. A restore-only mutant renders it 0 times, and the test goes red (mutation M2).rtversion), it refuses with rc=2 and writes nothing, rather than guessing. — DONE @#1490(7bfd0ba, reviewed as7bfd0ba).ErrCoveredContentMissingexits 2.TestRecoverPendingCutRefusesASectionEditedAfterPrepareasserts the changelog is unchanged and no fragment is written.main. — DONE @#1490(7bfd0ba, reviewed as7bfd0ba). That arm isTestRecoverPendingCutReprepareRendersEachEntryOnce. It is red on02fae6aand again onde49186(#980 and #981 at 2 and 2), and green at7bfd0ba. The reviewer reproduced it independently in review 7173.Not in scope
changelog-body-checkhas no duplicate-entry check. That is a defence-in-depth gap worth its own tracker; this issue fixes the producer.Landed in #1490. Shutting this tracker by hand, because #1490 referenced it with
Refs.7bfd0bafe9b165c624bd0c0abb97c7fea16b5b57, fast-forward merged 2026-10-02 14:23:08 withhead_commit_idpinned.01976b5,daf62c8,7bfd0ba.7bfd0ba.7bfd0ba. Its verdict is APPROVE, posted as a COMMENT because it came from the PR author's account.7bfd0ba.main, the push contexts were still running when this was written;check-self-bootstrap (push)is green.go-ci / record reviewed vs landed commit (push)failed after 3s. The same context fails the same way on the two previous landed commits,2060ed1andde49186. That matches open #1495 (fix in #1496) rather than this change. Its log is not readable from here.changelog-body-checkstill has no duplicate-entry check (see "Not in scope" above).The duplicate-entry gap in
changelog-body-check(see "Not in scope" above) is now filed as #1509.