bug(decide): an unrecorded cut whose prepare commit is buried below the tag still passes silently #1569
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
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
frankenbit/release-toolkit#1569
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 decide's unrecorded-cut check from #1482 recognises a toolkit cut only when the prepare commit is the tagged commit or the tag's second parent (toolkitPrepareAt,internal/decide/decide.go). If the prepare commit sits lower, the check returns nothing and the pre-#1482 silent pass comes back.Measured
On
origin/mainat9048da0, a throwaway test ininternal/decidebuilt this history:chore(release): prepare v0.1.0, then one more commit (docs: reword a line on the rolling branch);v0.1.0on that top commit;feat: work after the cut.Decidereturnederr = <nil>. The same history with the tag on the prepare commit blocks, asTestDecide_1482UnrecordedFirstCutBlocksshows.When it is reachable
rt releasetags HEAD. With a rebase or fast-forward merge of a rolling branch that carries a commit above the prepare, HEAD is that commit, and it has no second parent. Rebase is this repository's default merge style. A commit lands above the prepare when someone pushes a fixup torelease-prep/rollingbefore merging. It is the #259 buried-prepare shape thatdetectCut's range scan already handles.Two conditions must meet: the buried prepare, and a failed manifest write. When they do, the result is the #1482 failure again: a published release that no manifest records, and nothing reports it. It fails open, never closed. Hence low priority.
Suggested direction
Review 7284 on #1568 suggested scanning the tag's own merged range for the version's prepare subject, not just the tag and
^2. Something liketag^1..tagfor a merge, and for a linear history the commits since the previous tag. That covers both merge styles. It must keep the positive control: a pre-adoption tag with no prepare commit is still an ordinary bootstrap.Acceptance criteria
^2lookupTestDecide_1482PreAdoptionTagIsAnOrdinaryBootstrapandTestDecide_1482ManifestPresentSteadyStateDoesNotBlockstill passRefs #1482 (follow-up from review 7284 on #1568)
Fixed by PR #1588, merged fast-forward-only at
1f2f9259on review 8029 (@surveyor,official=true,stale=false, bound to that head), 5 of 5 required contexts green, rebased onto main first.All three ACs tick. The scan is unbounded — the bounds the first version of this PR called a cost-only optimisation were the defect, and the live instance is tmux-tell v0.35.0: its tag commit merges
mainINTO the rolling branch, so the prepare is an ancestor oftag^1andtag^1..tagexcluded it. Measured against/srv/tmux-msg:tag^1..tagcontains the prepare 0 times, the tag's ancestry once, and the bounded lookup returned""on a published release.Three findings of mine were corrected in review, and they are worth recording because they are one pattern:
tag^1, while tmux-tell's sits below it. Addingtag^1to the ref list and restoring the bound left all five arms green while the live shape stayed broken. One commit above the prepare closed it.All three had the same cause: a fixture built from the shape in my head rather than from the history it cited.
The live instance, the decoy-in-waiting measurement, the cost figures (11/15/22ms at 683/1046/1146 commits) and the subtree-import residual are @surveyor's.