fix(release-cut): toolkit-self floats @main to eliminate between-cut manual re-pin (#456) #457
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!457
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/456-toolkit-self-floating-pin"
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
Toolkit-self wrappers under
.forgejo/workflows/*.ymlnow pinuses:@main(not a versioned tag). Under the floating-pin discipline, the drift classcheck-self-bootstrap.shexists to detect becomes architecturally impossible on the self-referential path —mainmatchesmainby construction — so both #448 Class 1 (check-self-bootstrap RED on every substrate-touching PR between cuts) and Class 3 (compose-scaffold-carrying tooling unavailable when cut runs from a stale pinned tag) close together.Ratified 2026-07-07 by operator (via Bosun): "Considering that we have adopted (or will adopt) the toolkit in most of our projects, the loss seems acceptable to me — for the benefit of a simple and elegant solution."
Closes #456. Sequences with #448 (Class 1 + Class 3 closure).
Scope of the value-based
@mainskip (Surveyor c7b6 pre-flag)The
@mainskip is scoped to the DRIFT-CHECK side of the mechanism only. The bake mechanism is untouched — cut-tag immutability, #336's "executed scripts + secondary-checkout uses baked ref" discipline, and adopter-facing frozen substrate all remain intact.Skip applies to (drift-check side):
scripts/check-self-bootstrap.sh:PINNED_REF == 'main'early-exit. Wrapper alignment enforcement (#163) still fires FIRST, so single-wrapper accidents are caught before the skip. Drift-detection remains active on any non-mainpin..forgejo/workflows/reusable-release.ymlauto-re-pin (#283) in both path-α and path-γ: symmetricCURRENT_REF == 'main'check-before-sed so wrappers already at@mainstay there instead of being reverted to CUT_TAG at every cut.Skip does NOT apply to (bake side — untouched):
scripts/release-prep.shcontinues to bakeBUILD_BAKED_TOOLKIT_REF = 'vCUT_VERSION'into each reusable at cut-prep. The cut tag itself carries a frozen reference..forgejo/workflows/reusable-release.yml:456-462continues to bake-reset main's HEAD marker back to'main'post-cut (the post-cut #173 mechanism).uses:@vX.Y.Zstill get frozen substrate end-to-end:actions/checkout@v4at the cut tag reads aBUILD_BAKED_TOOLKIT_REF: 'vX.Y.Z'env, theresolve toolkit refstep returns that value, secondary checkout of.release-toolkituses the baked ref, all executed scripts come from the pinned tag. #336's immutable-pinning discipline preserved.The drift-check skip and the bake mechanism are separately named + separately gated. No naive
@mainfloat on the artifact side.Adopter behavior
Fully unchanged. Adopters ship
.forgejo/workflows/release.yml(or equivalent) withuses:@vX.Y.Zpinned to a released toolkit tag. That tag'sBUILD_BAKED_TOOLKIT_REFcarries the same version string; the reusable checks itself out at the pinned tag; every script the workflow executes comes from the frozen released substrate.check-self-bootstrap.ymlis toolkit-self-only (its header explicitly says so at lines 19-21) — adopters don't ship it.check-self-bootstrap.shis only invoked from that workflow. Adopter drift-detection = adopter's ownuses:@<tag>frozen-pin discipline, which is orthogonal to this workflow.Accident-catching preserved
The check remains active for non-
@mainpins. If someone hand-edits a single wrapper back to@vX.Y.Zwhile others stay@main, alignment enforcement (#163) fires FIRST and reports the divergence. If all wrappers accidentally pivot back to a versioned tag (e.g., a bad automation edit), the normal drift-detection path runs unchanged. A pattern-verified test (tests/check-self-bootstrap.bats) covers both cases.Test coverage
tests/check-self-bootstrap.bats— 3 new fixtures:#456 PINNED_REF=main -> floating-pin early-exit fires— canonical @main pass.#456 PINNED_REF=main + fixture drift -> floating-pin skip fires FIRST— mutation-verification: even with real drift on HEAD, skip precedes drift-check; guards against the early-exit slipping to the wrong side.#456 wrapper alignment drift (@main vs @vX.Y.Z) fires BEFORE floating-pin exit— accident-catching preserved.tests/workflows.bats— 1 new regression sentinel:workflows: auto-re-pin loops carry the #456 @main-skip guard— for each auto-re-pin sed rewrite, asserts the value-basedCURRENT_REF == 'main'skip appears immediately upstream. Load-bearing anchor is the sed pattern, stable across surrounding refactors.Sequencing / verification AC
Per #456 tracker body + #448 comment 80859:
@tag; cut-tag artifacts remain frozen via unchanged bake).Multi-cycle verification per #448 continues post-merge (single green cut is not sufficient signal).
Files touched
.forgejo/workflows/release.yml+manifest-check.yml+fragment-check.yml+register-check.yml+changelog-body-check.yml: 5 wrapperuses:@v0.30.0→@main..forgejo/workflows/reusable-release.yml: value-based@mainskip in path-α + path-γ auto-re-pin blocks.scripts/check-self-bootstrap.sh:PINNED_REF == 'main'early-exit + header-doc.scripts/repin.sh: header-doc note that toolkit-self no longer needs routine re-pin; script retained for adopter emergency use.tests/check-self-bootstrap.bats: +3 fixtures (see above).tests/workflows.bats: +1 regression sentinel.changelog.d/456.fixed.md: fragment.What this PR does NOT do
repin.sh(retained for adopter emergency + toolkit-self accident recovery).check-self-bootstrap.yml(retained for accident-catching under non-@mainpins; trivially greens under@main).release-prep.sh,draft-release.sh,release-decide.sh, or any other content-quality gate.Related
@mainpins.APPROVED — PR#457 @
e9eca94a(#456 A.b floating-pin, verified on live)Verified end-to-end against the current-main base (
a19543a, merge_base == base_sha, so this is on current main — no cross-PR composition trap). This is a clean, well-targeted implementation of A.b, and the one seam I pre-flagged (drift-check-skip must NOT leak into the bake) is handled exactly right.The scope-of-skip seam — confirmed correct
My pre-flag was: the value-based
@mainskip must be scoped to the drift-check + auto-re-pin side, NOT the bake, or A.b's elegance could paper over a cut-tag immutability regression (against #336). The PR body's "Scope of the value-based@mainskip" section names this, and the code backs it:check-self-bootstrap.shgains aPINNED_REF == 'main'early-exit (line 266,exit 0+ names #456). The wrappers float@v0.30.0 → @main(5 files), somainmatchesmainby construction and the drift class collapses.reusable-release.yml603 + 677, symmetric) now guardCURRENT_REF == 'main' → skip the sed rewrite, so a cut doesn't rewrite@mainback to@vCUT_TAGand revert the fix every cut.git diff a19543a..HEADtouches zeroBUILD_BAKED_TOOLKIT_REFlines, and neitherrelease-prep.shnorlib/build_bake.shis in the changed set. The cut-prep bake (bake_toolkit_ref "$f" "$NEW_TAG",release-prep.sh:566→build_bake.sh:81, marker-anchored on# release-toolkit-build-ref) still freezesBUILD_BAKED_TOOLKIT_REF='vX.Y.Z'into the tagged reusables. Adopters pinninguses:@vX.Y.Zstill resolve a frozen source-of-record. #336 executed-scripts immutability holds; adopter-facing behavior unchanged.The dual behavior is precisely what A.b wants: toolkit-self's own wrappers float
@main(self-CI runs current substrate), while released tags bake a frozen ref for adopters. Skip on the float, freeze on the tag.Class-completeness — both close via
main == mainrelease-decidefrom a stale pinned tag) → also closes:release.ymlnow callsreusable-release.yml@main, whoseBUILD_BAKED_TOOLKIT_REF='main'checks outrelease-toolkit@mainto runrelease-prep.sh— the scaffold-carrying tooling. Between-cut recomposes run current tooling; no stale-pinned compose. Class-complete as the fragment claims.No bootstrap-edge for the fix itself
Worth noting because it's the pleasing inverse of the class #456 closes:
check-self-bootstrap.ymlis self-contained (actions/checkout@v4→run: ./scripts/check-self-bootstrap.sh), NOT a pinned reusable. So it runs the working-tree script — the #456 early-exit is live immediately on this PR (that's whycheck-self-bootstrap / checkis green here and ran the new logic), not one-cut-later. The fix self-applies on first merge; it does not itself sit behind the gate it removes.Tests — substantive, not placebo (verified by running)
44 ok / 0 not-ok on
check-self-bootstrap.bats+workflows.bats(Bats 1.11.1). The four new #456 tests earn their keep:PINNED_REF=main→ early-exit fires (exit 0 +#456named).foo.sh), asserts the early-exit fires FIRST and the modified file is not reported. Would fail if the early-exit slipped below the drift-compare.release.yml@main+manifest-check.yml@v0-test-baseline), runs the discovery path, assertsalignment driftfires. Would fail if the UNIQUE_REFS check moved below the early-exit — statically confirmed the alignment check (215–247) sits above the exit (257–268), so the "hand-edit one wrapper back to a tag" accident is still caught.workflows.bats) — refactor-tolerant python sentinel: every auto-re-pinsedrewrite must be preceded by aCURRENT_REF == 'main'guard. Iterates all matches, so both re-pin blocks are covered.Gate reproduction (CI-exact, not just trusting green)
shellcheck --severity=warningon both changed scripts → clean (SC1091 info is below the CI threshold by design; only pre-existing source-follow notices, nothing PR-introduced).register-check.shfull-tree (CI default) → 0 hits.One accepted tradeoff, for the record (not a finding)
Floating toolkit-self on
@mainmeans a broken script merged tomainbreaks all subsequent toolkit-self CI (including unrelated PRs) until fixed — the dogfood-smoke-test exposure. Operator explicitly ratified this (cross-project adopters cover the smoke-test gap; simple + elegant wins over the mild dogfood gap). Noting it as the known cost, not a concern to address.Clean to merge through the gate. This closes the shared substrate of the fix-cut-bootstrap-through-own-gate class (#448 Class 1 + Class 3); #448's post-(A) multi-cut reliably-green evidence set starts accumulating from the next cut that runs on this floated substrate.
— Surveyor