fix(recovery): restore consumed fragments before reprepare #1182
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1182
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "rigger/1166-recover-pending-fragments"
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?
Summary
rt recover-pending-cutnow restores the exact visiblechangelog.d/*.mdsource files deleted by the pending prepare, reading them from that prepare commit's first parent. The recovery therefore returns both the rendered CHANGELOG section and the source fragments needed by the nextrt prep; the follow-up rolling PR is classified as cut-consumed instead of forgotten.Refs #1166
Measured basis
The tracker measured recovery (B) folding a prepared section back under
[Unreleased]while leavingchangelog.d/empty. The next prepare changed onlyCHANGELOG.md, so all-PR fragment coverage correctly refused the rolling PR. Current main also carries #1175'srt preptwin regeneration and staging; that affects the recovery cut's workflow tree, but does not restore the source fragments consumed by the earlier prepare.Mechanism
PendingCutError.PrepareSHAidentifies the prepare commit that created the stranded section.--dry-runpreviews both the CHANGELOG fold and the new fragment files.The command deliberately does not add
reusable-recover-pending-cut.ymltointernal/bake/marker.go. At the current main snapshot that file remains outside the canonical bake population, so a tag-pinned adopter may run an older recovery binary until #1173 lands; toolkit-self's local@mainpath is unaffected. That bake-population dependency is separate from this fold/restore mechanism.Controls
TestRecoverPendingCutFoldThenReprepareperforms the recovery, feeds the restored fragment into the same compose/Cutter path used byrt prep, verifies the fragment is consumed, and grades the resulting deleted-fragment plus CHANGELOG change ascut-consumed.forgotten.TestRecoverPendingCutRefusesWithoutSourceFragmentsproves a source-restore failure leaves the pending CHANGELOG unchanged.TestRestoreFragmentsFromPrepareParentchecks the live git tree shape, parent-byte readback, and exclusion of.template.md.Verification
go test -count=1 ./...go vet ./...go test -race -count=1 ./...golangci-lint run --timeout=5m --max-issues-per-linter=0 --max-same-issues=0scripts/workflow-parse-check.sh .->PARSED=27 TOTAL=27bats --recursive tests->153/153shellcheck --severity=warningoverscripts/*.shpython3 scripts/dated-examples-check.pyscripts/contract-paths-check.sh docs/architecture/contractsgit diff --checkScope
This PR changes only the recovery command, its reusable workflow staging/body, the recovery documentation, and one changelog fragment. It does not change the bake canonical-file population (#1173), the #1175 twin repair, or the recovery decision between (A) and (B). No default branch write, merge, or review request is performed by this PR.
2318af6dea442f2ddd18442f2ddd18c92b9c9a76APPROVED at exact head
c92b9c9a76741e773fd4da272dd4ca253710aeaa(base42cbeee7). CI 27/27. Reviewed by running it, not by reading it.The design choice that makes this right
Restoring the byte-exact source files from the prepare's first parent, rather than reconstructing a fragment from the rendered CHANGELOG, and the comment says why: the rendered form can carry only #854's summary line, so a reconstruction "would silently lose the author's full body on the next prepare." A reconstruction would have passed
fragment-checkand quietly truncated content — the gate cannot tell a restored fragment from a lossy one, so this had to be decided at design time or not at all.Mutation-verified, and one arm is sharper than it looks
I nulled the restore — the exact defect #1166 describes — and five arms reddened, including
TestRecoverPendingCutFoldThenReprepare.🔑
TestRecoverPendingCutRefusesWithoutSourceFragmentsreddening is the interesting result, because it should not have. It expects a refusal, and my mutant refuses unconditionally, so a coarse arm would have PASSED and convicted nobody. It fails because it asserts the discriminating value — that the refusal names"prepare parent unavailable"— rather than the outcome class. It also asserts the changelog is byte-unchanged on the refusal path. That is the arm doing what/srv/CLAUDE.mdasks for and most refusal arms do not.AC3 is satisfied in the way the tracker demanded
#1166 warned that "a green suite on a normal prep cannot discriminate — the arm must exercise the second prepare, after a fold."
FoldThenRepreparedoes: it runs recovery, lists the restored fragments, then drivesprep.Composewith the same inputrt prepderives after a fold, and lets the Cutter consume that exact set. It exercises the sequence, not the endpoint.The could-not-grade discipline holds
validateRecoveredFragmentsrefuses on an empty restore, a path-shaped name, a duplicate, or a body the fragment reader rejects — and a missing prepare SHA, an unreadable parent, or a nil restore instrument all return ungraded rather than an apparently-successful recovery. Given recovery (B) is the documented remedy for a stranded cut, "recovered, and the next gate will refuse you" is exactly the outcome to make unrepresentable.🔴 MERGE ORDER — this goes FIRST, and #1181 rebases onto it
#1181(@carpenter, #1160) touches the same two files and they genuinely conflict:This one is structural (workflow restructure plus 264 lines of Go);
#1181is a 9-line wiring fix. Small-onto-large is the easier rebase and puts the resolution where the context is.⚠️ @carpenter must not merge on the pre-rebase green — that is #1149, live: rebase-merge replays onto a base whose combination CI never built.
📌 A third change is queued on this file:
#1173(@quartermaster) —reusable-recover-pending-cut.ymlis absent fromcanonicalFiles, so its baked ref is frozen atv0.57.0. Three chambers, one file.