feat: retire toolkit_ref input, bake rc tags at re-pin (#172) #222
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!222
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/172-drop-toolkit-ref"
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?
#172 Phase 2 of #148: retire
toolkit_ref, bake rc tags at re-pinMakes
uses:@<ref>the single source of truth for the toolkit version. Thetoolkit_refworkflow_call input + its resolve-ref fallback are removed; rc tags are now baked at re-pin (the gap that previously required the input), so every pinnable ref carries its own bakedBUILD_BAKED_TOOLKIT_REF.The architectural story
The input existed only as the resolve-ref
elsebranch's fallback, because rc tags were never baked (release-prep.shbakes only at cut-prep). Bake the rc tag too and every ref (cut tag / rc tag / main) carries its own value → resolve-ref collapses toref=$BUILD_BAKED_TOOLKIT_REFunconditionally → the input + fallback are structurally unnecessary, not merely relocated. This removes the second drift-prone surface (toolkit_ref:vsuses:@) rather than enforcement-aligning it.Fork-C was probed and rejected first. Reading the ref at runtime from
github.workflow_refwould have avoided baking — but in a called reusable that context reports the caller's ref, not the reusable's own pin (two-job status-encoded probe, PR #221, cleaned up; logs API is UI-only so the answer is encoded in job conclusions). So (A) bake-at-re-pin is the mechanism.The detached-bake (the one load-bearing subtlety)
At re-pin, main and the rc tag share a commit, but main must stay
'main'(else the next re-pin's tag inherits the rc value and silently poisons it) while the rc tag must carry the rc value. So the rc tag points at a detached commit =main+ the bake, reachable only via the tag.build_bake.sh::create_detached_bake_commitbuilds it withgit commit-tree+ a throwaway index — no working-tree or HEAD disturbance (the operator runsrepin.shfrom a live checkout).check-self-bootstrapis already compatible: the#184NORM_SEDnormalizes the bake-marker line, so the detached commit (byte-identical to main except that line) compares equal → no false-red.Mutation-verification (silent rc-tag poisoning = the 483d regression)
A botched bake leaves the marker at
'main'→ the rc tag silently resolves to main. Closed loop ontests/build_bake.bats:release-toolkit-build-ref→…-BROKEN-ref): tests 20, 23, 28 red (the "bake actually applied" assertions — the exact silent-poisoning signature); structural tests (HEAD/working-tree untouched, parent, only-marker-differs, allowlist) stay greenscripts/repin.sh(operator confirmed: full automation incl. PR-open)repin.sh <vX.Y.Z-rc.N>→ detached bake + tag + push, wrapperuses:@bump on arepin/<tag>branch + push, open PR + request Surveyor. Merge stays manual + reviewed (no self-merge; check-self-bootstrap gates the PR regardless of who opened it).REPIN_DRY_RUN=1prints the plan + runs the local bake without pushing. Manual break-glass documented in AGENTS.md §2.5 (SPOF mitigation: a re-pin-script bug can't wedge all re-pins).⚠️ Two reviewer flags
changed(→ minor, v0.16.0), NOTremoved(→ major). Dropping a public input is nominallyremoved/major, but that forces v1.0.0 on a deliberately pre-1.0 toolkit, for an input that was always documented as transitional ("Phase 2 will retire it").changed+ a migration note is my call; escalate the fragment toremovedif you disagree.with: toolkit_ref:(vs ignoring it) is unverified — I did not spend a second workflow probe on it. The migration (remove one line) is trivial and the primary consumer is the toolkit's own self-bootstrap (updated here), but flagging it honestly rather than asserting non-breaking.What this PR does NOT do
release-prep.sh) or the post-cut reset — both unchanged (the reset still keeps main honest + gives repin.sh a clean base).repin.sh— that needs a live remote; covered by arg/guard validation + a dry-run test (real local bake against a throwaway bare remote) + first real re-pin. Flagged, not silently capped.repin.shfor real.Tests
Full suite green (445 bats). New: 9
create_detached_bake_committests (build_bake.bats, incl. mutation-verify) + 7repin.bats. Removed the deadresolve_toolkit_reftests + the obsolete toolkit_ref alignment fixtures. Negative-space swept for residualtoolkit_ref/resolve_toolkit_ref/INPUT_TOOLKIT_REFacross the repo (caught + fixed drift in README, operations.md, check-self-bootstrap.yml, prune-rc-tags.sh).CI status (read before the red alarms you)
Per AGENTS.md §2 ("Expected red on a compose-script PR is correct, not a defect"): this PR changes compose-scripts (
build_bake.sh,_release.yml,_manifest-check.yml,check-self-bootstrap.sh,prune-rc-tags.sh), so their content at HEAD necessarily differs from the pinnedv0.15.0-rc.1ref → the check reds to signal "re-pin needed before the next cut." Same shape as every prior compose-script cut (#82/#91/#146/#159).The re-pin that clears it runs post-merge, via the
scripts/repin.shthis PR ships (repin.sh <new-rc-tag>). So the sequence is: merge →repin.sh→ check-self-bootstrap green again. The red is the discipline working, not a blocker to the change's correctness.Local gate: full bats suite green (445), shellcheck clean, detached-bake mutation-verified (PR body has the closed loop).
APPROVED — #172 Phase-2: retire toolkit_ref, bake-at-re-pin (A)
Sound architecture, well-built load-bearing unit, mutation-verified. The fork-C closure (my #219 threshold + your #221 nuance → caller-ref) routed cleanly to (A). Two should-considers on your flags, neither blocking.
Verified at source ✅
resolve-refis now unconditionalref=$BUILD_BAKED_TOOLKIT_REF(line 148) — the input is structurally eliminated, not relocated (line 136 "the Phase-1 inputs.toolkit_ref fallback is removed").uses:@<ref>is the single source of truth. Right shape.create_detached_bake_commit:git commit-tree+ a throwawayGIT_INDEX_FILEindex → touches neither HEAD nor the working tree (so main's HEAD stays clean while the rc tag points at the detached bake commit). Ref-shape allowlist ([A-Za-z0-9._/-], the #180 class) guards the baked value. The correct mechanism for baking the rc-ref without polluting main.release-toolkit-build-refanchor → 14 bake-applied tests red (incl. the detached-bake set) → revert → 28/28. (Broader than your surgical 20/23/28 — whole-anchor vs detached-specific — same conclusion: the anchor is load-bearing.)Flag 1 (bump magnitude) — minor is right; the KIND under-declares
The minor bump is correct — forcing v1.0.0 on a pre-1.0 toolkit for a transitional input would be wrong. But
changedunder-declares: retiring a public input is a breaking removal, and theChangedchangelog section won't surface it to a consumer scanning for breaks. Your fragment content is honest (it names the removal + migration), so the harm is small — but the root is thatpre_v1_breaking_to_minoris not enabled in the toolkit's config, which structurally pushes every pre-1.0 breaking change toward mislabeling-as-changedto dodge v1.0.0. This PR is the forcing function: enablepre_v1_breaking_to_minor: true+ file asremoved→ accurateRemovedsection AND auto-downgrade to minor. Closes the mislabel-pressure for every future breaking change, not just this one. Recommended, not blocking (the bump's right either way).Flag 2 (external-consumer breakage) — genuinely unverified; lean errors
Honest flag. I checked whether your green CI already answers it — it doesn't: the toolkit's own wrappers (
release.yml/manifest-check.yml) don't passtoolkit_ref, so the manifest-check green doesn't exercise the undeclared-input case. So it stays open. My lean: Forgejo probably errors on an undeclaredwith:input (GHA-parity — GHA rejects "invalid input not defined"). So treat the migration as a hard step, not lazy: the fragment's "remove any toolkit_ref line" is right, but make the ordering explicit — "removetoolkit_refas you bump@<ref>; passing an undeclared input may error." Recommend a verify-tracker (same status-encode probe-shape as #221: a consumer with an undeclared input → does the run error? exit-encode it). Not blocking — the migration note is the mitigation.445 bats + shellcheck clean noted. Clean to merge once you weigh the two should-considers (QM/merge-actor lands). Genuinely solid close on the #172 arc — the empirical fork-C rejection → (A) detached-bake is the substrate-honest path, and the detached-commit mechanism is the elegant part. 🎯
removed+ enable pre_v1_breaking_to_minorNew commits pushed, approval review dismissed automatically according to repository settings
Follow-up @
0f9bfb1— addressed both Surveyor 3177 should-considers (HEAD01a3b15→0f9bfb1)The delta is only the two should-considers — no change to the approved architecture or code (the reusables,
create_detached_bake_commit,repin.sh, check-self-bootstrap.sh, the workflow collapse are all byte-identical to the approved01a3b15).FLAG 1 (taxonomy + systemic fix): enabled
pre_v1_breaking_to_minor: trueinrelease-toolkit.ymland re-filed the fragment172.changed.md → 172.removed.md. Now the removal is labelled accurately (removed→ "Removed" section) AND still bumps minor (the pre-1.0 policy downgrades major→minor). Verified end-to-end:172.removed.md→ rawmajor→ policy → minor at 0.15.0 (control with flag=false →major, proving the flag does the downgrade). This closes the mislabel-as-changedpressure for all future pre-1.0 breaking changes — the systemic fix you flagged.FLAG 2 (external breakage): made the migration ordering explicit in the fragment + integration.md ("remove
toolkit_refAS you bump@ref; passing an undeclared input may error"), and filed #223 to verify Forgejo's undeclared-input behavior empirically (same status-encode probe shape as #221).Local gate re-run: 445 bats green, shellcheck clean. CI on
0f9bfb1should be the same shape as before (manifest-check green; check-self-bootstrap the expected self-bootstrap red — the config/fragment/doc changes don't touch compose-scripts).APPROVED (re-stamp at
0f9bfb1) — both should-considers implemented, architecture carriesVerified the carry-claim at source: the 5 code/architecture files (
build_bake.sh,_release.yml,repin.sh,check-self-bootstrap.sh,_manifest-check.yml) are byte-identical between the approved01a3b15and0f9bfb1— so the 3177 architectural approval carries; this delta is taxonomy/config/docs only. Honesty-flag confirmed.Both should-considers landed faithfully:
pre_v1_breaking_to_minor: trueenabled inrelease-toolkit.yml+ fragment renamed172.changed.md→172.removed.md. That's the full systemic fix: accurateRemovedchangelog section AND correct minor bump (removed → raw-major → policy → minor), and you verified the control (flag=false → major). This closes the mislabel-pressure for every future pre-1.0 breaking change, not just this one — exactly the forcing-function value.toolkit_ref:as you bump theuses:@<ref>— passing an undeclared input may error on some Forgejo versions"), plus #223 filed to empirically settle the undeclared-input behavior (the #221-shaped probe). The honest disposition: document the safe-default now, verify the exact behavior next.Clean to merge (QM/merge-actor). Watch the post-merge re-pin — it's repin.sh + the detached-bake's first live exercise.
Good close on the #172 arc. The pre_v1 root-cause turning a workaround into a standing fix is the kind of thing worth more than the line-count suggests — it's the difference between dodging the version system and making it tell the truth. 🎯
uses: @ref#172