fix(check-self-bootstrap): skip on rolling-PR-merge push:main (#445) #449
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!449
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/445-check-self-bootstrap-prep-merge-skip"
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
Bundle 3 v1.0.0 must-fix — closes the "check-self-bootstrap RED on every substrate cut" class per operator's single-click-release directive. Empirical anchor: every substrate cut in the current sprint (PR#438 v0.28.0, PR#443 Bundle 1, PR#446 Bundle 2, v0.29.0 rolling merge) fired check-self-bootstrap RED on the rolling-PR-merge push:main event.
Closes #445.
Design pivot (substrate-honest reframing)
The tracker frames Option A as "cut workflow auto-updates release.yml pin as part of cut." Substrate reading discovered Option A is already implemented via #283. Empirical confirmation: v0.29.0 post-cut commit
2b5995e chore: post-cut bookkeeping for v0.29.0 [skip ci]advanced all 5 consumer wrappers from@v0.28.0to@v0.29.0. So Q1's 1A vs 1B decision doesn't apply to this PR — 1A is already shipped via #283's post-cut bookkeeping commit.Same convention-citation vs mechanical-substrate refinement pattern as PR#446 Bundle 2:
The actual residual problem is temporal, not code-path-divergent:
check-self-bootstrapANDreleaseworkflows in parallelcheck-self-bootstrapreads pin=@vOLD+ HEAD scripts=new → detects drift → REDreleaseworkflow completes →#283auto-re-pin commits[skip ci]→ drift heals in secondsThe RED is a false-positive: cut is in-flight and will auto-re-pin. But the pin-drift check has no signal that cut is in-flight, so it fires as-if the drift were an operator hand-edit.
Design shape: Option B (scope-by-trigger skip)
Given Option A is already implemented, ship Option B:
PREP_SUBJECT_RE(same regex used byrelease-decide.shfor cut-detection — single-source-of-truth semantics)release-toolkit#445and pointing at#283as the mechanism that will land the re-pinrelease.yml, orphaned tag, any content edit outside the rolling-PR flow still firesDesigns considered + rejected
check-self-bootstrapresolving@vNEWand cut workflow creating the tag on the same push:main event.check-self-bootstrapand cut workflow run in parallel; the tag doesn't exist until cut completes; check would fail to resolve the ref. No clean resolution without complexity.uses:@<ref>pattern is battle-tested and adopter-visible.Implementation
scripts/check-self-bootstrap.sh— early skip block after script boilerplate + before pinned-ref discovery. Usesgit log -1 --format=%s HEADto read HEAD subject; regex-matches againstPREP_SUBJECT_RE.tests/check-self-bootstrap.bats— 5 new fixtures covering skip variants + regression cases + prefix false-positive guard.Test coverage
chore(release): prepare vX.Y.Z(merge/rebase shape) → skipchore(release): vX.Y.Z(squash-merge shape using PR title) → skipchore(release): prepare v1.2.3-rc.1(rc-suffix) → skipfix(cli): drop wrapper→ check fires normally (regression guard)chore(release-toolkit): tidy something(prefix false-positive) → does NOT skip--git-log).What this PR does NOT do
PREP_SUBJECT_REinto a shared lib —release-decide.shcurrently duplicates the regex internally (two in-file copies at L260 + L460). This PR adds a third copy incheck-self-bootstrap.shwith a code comment naming the follow-up. DRY consolidation is a small follow-up tracker to be filed post-merge.check-self-bootstrap.ymlworkflow'sif:clause — the existing rolling-PR skip (!startsWith(github.head_ref, 'release-prep/')) covers the PR event; this PR adds the push:main-side skip via the script.Follow-ups
scripts/lib/prep-subject.shshared byrelease-decide.sh+check-self-bootstrap.sh. Small size/S DRY refactor; non-blocking for v1.0.0 tag.Closes #445.
Review — PR#449 Bundle 3 (#445): check-self-bootstrap skip on rolling-PR-merge
Verdict: APPROVED. The substrate-discovery reframing is correct and verified at source, and Option B is the right minimal fix. Two non-blocking should-considers below.
Reviewed on live state at head
c32ad056(base = #446's merge SHA34323616, on current main).Verification performed
The substrate-discovery claim — verified at source. Commit
2b5995e(chore: post-cut bookkeeping for v0.29.0 [skip ci], release-bot) advanced all 5 caller workflows'uses: reusable-*.yml@v0.28.0 → @v0.29.0. So #283's auto-re-pin is already implemented, and the[skip ci]is what makes it invisible to CI — the Option-A-already-done / residual-is-temporal framing holds. ✓Skip predicate is tight + non-spoofable.
PREP_SUBJECT_REis anchored^…$on thechore(release):conventional shape + semver. Match matrix:chore(release): v0.30.0/prepare v0.30.0/0.30.0/v1.0.0-rc.1…v0.30.0 and sneak an edit,…v0.30.0; drop discipline,Merge pull request #447 …,feat(x): v0.30.0,chore(release): update depsA hand-edit that appends anything to the subject still runs the check — the anchoring means genuine drift can't ride a suffix past the skip. ✓
Closed-loop (synthetic HEAD subjects on the checkout):
733/733 bats green; register-check clean file-scan +
--git-log; fragment445.fixed.mdregister-clean + check-7 clean. ✓Rejected options (1B race / C weakens-discipline / D XL) are all sound rejections; Option B is the correct minimal fix. ✓
Should-consider 1 — the 3×
PREP_SUBJECT_REduplication is a discipline-load-bearing invariantVerified the 3 copies (release-decide.sh ×2, check-self-bootstrap.sh ×1) are byte-identical today — so no live defect. But they must stay in sync, and the failure mode is asymmetric and dangerous: if check-self-bootstrap's copy ever becomes looser than release-decide's cut-detection copy, a push that check-self-bootstrap treats as a prep (→ skip) but release-decide does not cut would get the pin-drift check skipped on a genuine non-cut push — a real discipline hole, silently. That's exactly the shared-source-of-truth drift class the toolkit exists to prevent, and there's direct precedent: #442 extracted
register-patterns.shfor the identical reason (one pattern list, multiple consumers).You've named this as a follow-up. Recommend filing the tracker now (not "deferred post-merge"), referencing the #442 extraction as the pattern to mirror — a load-bearing invariant maintained by "3 copies that happen to match" shouldn't rest on vigilance. I'm happy to file it if you'd like.
Should-consider 2 — the skip shifts re-pin-failure detection to the next push
The skip suppresses the pin-drift check on the prep-merge (cut) push, on the assumption that #283's auto-re-pin will land. If that auto-re-pin ever fails, the resulting genuine post-cut drift isn't caught on the cut push — and because the re-pin commit is
[skip ci], that push doesn't fire the check either. The failure would surface on the next non-prep push:main (as the closed-loop (B) case demonstrates the check does catch real drift), so it's bounded, not invisible-forever. Given #283 is battle-tested (verified it worked for v0.29.0), this is a reasonable trade — killing the per-cut false-RED noise is worth a one-push detection lag on a rare failure. Just naming the residual honestly; no action needed unless you want a comment recording it.Coupling note (not a defect)
The skip keys on HEAD subject == prep shape, which depends on squash-merge producing the prep subject as HEAD (a merge-commit's
Merge pull request…subject wouldn't match, per the matrix). This is inherited from release-decide.sh's existing cut-detection — same regex, same HEAD-subject dependency — so it's consistent with the established mechanism, not a new assumption. Worth a mental note that the whole cut path assumes squash-merge; nothing to change here.Non-blocker ack
if:unchanged — confirmed the rolling-PR context (workflow layer) and the push:main context (script layer) are distinct trigger surfaces; the script-layer skip is the right home for the push:main case.Clean to merge through Bosun's gate;
Closes #445. This closes the check-self-bootstrap RED-on-every-cut class — the reliably-green-CI meta-tracker's substrate keeps firming up.— Surveyor