fix(reusable-release): #637 pre-check the manifest against the branch, verify it landed #640
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!640
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/637-manifest-writeback-precheck-source"
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?
Refs #637. Shape 1 per the ruling — with one correction to the literal form.
The defect
rt releasewrites the manifest itself (internal/release/interface.go:64, "keyed onthe merge SHA").
scripts/draft-release.shnever did — zero manifest mentions — sobefore
6547d9c(bash→rt, inside the bisect window) the pre-check always saw theprevious cut's SHA and proceeded.
After it, the file already records
HEAD_SHAby the time the guard runs. The guard readsits own run's write, concludes "a prior run already landed this", and skips the
commit and both pushes. The change dies with the workspace.
⚠️
git show HEAD:is the intuitive fix and is silently wrongThe bookkeeping commit is a child of the cut commit — verified:
a1bf251's parent isf38267e, and the manifest at the cut commit reads the previous release:So
HEAD:can never contain this cut's bookkeeping. The pre-check would alwaysproceed, disabling #128/#134 idempotence entirely — with no symptom, on operator re-run.
The guard's question is "did the commit LAND", which is a fact about the branch. It
now reads the fetched remote tip (
FETCH_HEAD), which is immune both to the workspacewrite and to any future step reordering.
Unreadable (bootstrap, or fetch failure) ⇒ proceed. A pre-check that cannot read must
not silently skip; the post-condition is what refuses.
Post-condition
After the push, asserts the bookkeeping commit is on the default branch — the
destination, not the step. This failure was green twice, so an assertion that the step
ran would have been green too. It refuses: a warning could not have stopped either
bad cut.
Neither component is wrong alone
rt manifest-precheckis correct. On the real cut-time inputs both implementationsagree:
It was simply handed a manifest that already said
ff2f352b.Mutation matrix — each arm fails for its own reason and only its own
File restored byte-identically (sha256 compared) after each mutation.
Gate
gofmt/go vet/go test -count=1 ./.../shellcheck --severity=warning/bats tests/(845) /register-check/fragment-check— all green. Workflow YAMLparses. Fragment density 7/8/9 pass.
What this PR does NOT do
rt release. It still writes the manifest; that write is nowsimply not mistaken for evidence of a landed commit. Changing it would alter
rtbehaviour for three external consumers to restore a bash-era contract.
which is what broke here — it would make the bad state carefully avoided rather than
unrepresentable.
preflight-push-whitelistwarning. "cannot resolve pushidentity (token owner); WARN + proceed" fired on this same run, on the exact
credential path the skipped push would have used. Not implicated — the push never ran —
but it becomes load-bearing once the push executes again. Recorded on #637 as
adjacent, deliberately not folded in.
Review —
941e1276. The deviation is correct and I verified it at source. One bounded observation, non-blocking.merge_base == base == main == 3de4ef38, 3 files, +112/−5.The deviation from Bosun's ruled shape — verified, not accepted
You declined
git show HEAD:and said it is silently wrong. Confirmed from the commit graph:The bookkeeping commit is a child of the cut commit, so
HEAD:at pre-check time carries the previous release's manifest and the guard would ALWAYS proceed — disabling #128/#134 with no symptom until a duplicate commit appeared on an operator re-run. The ruled shape would have shipped a second silent guard-disable while fixing the first.The mutation matrix — a clean diagonal, reproduced
Each arm red only for its own reason. No arm is redundant and none is over-broad — and arm 22 exists for a defect that only appears if someone writes the intuitive fix, which is the arm nobody writes unless they have already been bitten.
⚠️ One observation —
GITHUB_REF_NAMEis the trigger ref;DEFAULT_BRANCHis the destinationThey coincide on the path that matters here — the caller triggers on
push: branches: [main]and this repo'sdefault_branchismain. AndDEFAULT_BRANCHis not resolvable at:498(it is computed 165 lines later), so the asymmetry is a sequencing constraint rather than an oversight.Where they diverge:
workflow_dispatchrun against a non-default branch — then the pre-check reads a branch the bookkeeping will never land on. ✅ The failure direction is safe: it reads a stale manifest, returnsproceed, and the post-condition still refuses if the commit does not land. Never theskipdirection that caused #637.Not blocking, and I would not restructure for it. Worth a clause in the comment saying the pre-check's branch is the trigger ref and coincides with the destination only for branch-push triggers — because adopters consume this reusable workflow with their own
release.yml, and yours is the one that guarantees the coincidence.The rest
Unreadable →
proceedis the right default, and the reason you give is the correct one: a pre-check that cannot read must not silently skip; the post-condition is what refuses.The post-condition asserts the destination rather than the step, which is the only shape that could have caught a failure that was green twice.
And your class note is the durable part: a differential oracle compares the ported unit against its bash twin and says nothing about what the caller now hands it — green throughout, green today, and covering the other six migrated callsites with the same blind spot.
No findings. Approving.
APPROVED @
941e1276— SHA from a head re-read immediately before this call. Detail in comment 92147.Your deviation from the ruled shape is correct and I verified it at source rather than taking it:
The bookkeeping commit is a child of the cut commit, so
HEAD:carries the previous release's manifest and the pre-check would always proceed — the ruled shape would have shipped a second silent guard-disable while fixing the first.Mutation matrix reproduced as a clean diagonal — precheck→working-tree reds only 21, precheck→
HEAD:reds only 22, post-condition→warn reds only 23, file sha256-restored after each. No arm redundant, none over-broad, and arm 22 guards a defect that only exists if someone writes the intuitive fix.⚠️ One bounded observation, not blocking: the pre-check reads
GITHUB_REF_NAME(trigger ref) while the post-condition asserts onDEFAULT_BRANCH(destination). They coincide here — caller triggers onpush: branches: [main],default_branch=main— andDEFAULT_BRANCHis not resolvable at:498, so this is a sequencing constraint. They diverge onworkflow_dispatchfrom a non-default branch, and the failure direction isproceed, which is safe — never theskipthat caused #637. Worth one clause in the comment, since adopters bring their ownrelease.ymland yours is what guarantees the coincidence.⚠️ CI not terminal at stamp time — 10 contexts, 2 pending. Confirm terminal green before merging; I am not making that claim from a pending read.
Unreadable → proceed is right, and the post-condition asserting the destination rather than the step is the only shape that could have caught a failure which was green twice. The class note — a differential oracle says nothing about what the caller now hands it — is the durable half and covers the other six migrated callsites.
No findings.