fix(release): stage and resolve AC-closure reusable safely #998

Merged
bosun merged 2 commits from rigger/997-ac-closure-ref into main 2026-08-27 09:52:02 +02:00
Owner

Scope

Refs frankenbit/release-toolkit#997.

This PR keeps the repair in the tracker-specified order:

  1. Port the fail-closed empty-ref discrimination from #996 to reusable-ac-closure-check.yml.
  2. Repair the rt prep staging population after the resolver/control is present.

The local toolkit-self invocation resolves main; a matching pinned adopter retains its baked tag; explicit @main remains main; an unmatched external wrapper refuses instead of silently bypassing its baked ref.

Measured finding and disposition

The historical #982 cut exposed the latent interaction. At review-bound cut tree a1c383ea6f713aa73f12a708b4afa62d3baabf2d, the AC-closure reusable carried baked v0.53.0, its toolkit-self wrapper invoked it by local path, the pre-fix resolver selected v0.53.0, and the tag lookup returned 404. The cut later shipped and the tag now exists; this is historical evidence, not a current release-state claim.

The skip had a concrete source-level cause. internal/bake/marker.go enumerated seven canonical marker files, while cmd/rt/prep.go staged only six after RewriteToolkitRefFiles; its bakeRefFiles mirror omitted reusable-ac-closure-check.yml. The omission explains the observed 6-of-7 result. The final lists are now identical and ordered. The resolver/control commit precedes the staging-list repair commit.

Controls

  • Pre-fix mutation: removing only the new local-path branch makes an unpublished baked ref remain selected; an empty scratch repository has no matching tag ref, so the checkout probe refuses it.
  • Fixed local toolkit-self control: baked v0.53.0 resolves to main and reports the local source.
  • Matching pinned consumer control: baked v0.52.0 remains v0.52.0.
  • Explicit @main control: resolves to main.
  • Unmatched external wrapper control: exits 1 and never resolves to main.
  • The five adopter-invoked reusables are audited independently: release, manifest, changelog-fragment, changelog-body, and register each retain external-pin extraction plus the #456 @main override. The existing parse control remains in place from #996.

The external recognizer remains intentionally exact and unquoted. A valid quoted external uses line is unsupported and fails closed; broadening that syntax is a separate decision, not a reason to default to main.

Verification

  • bats tests/workflows.bats tests/workflow-parse-check.bats: 60/60 passed.
  • go test ./...: passed.
  • go vet ./...: passed.
  • go build ./...: passed.
  • go run ./cmd/rt fragment-check changelog.d: passed.
  • git diff --check: passed.
  • All workflow YAML files parsed successfully as part of the Bats run.

No external repositories were edited. No review request or merge was made.

## Scope Refs frankenbit/release-toolkit#997. This PR keeps the repair in the tracker-specified order: 1. Port the fail-closed empty-ref discrimination from #996 to `reusable-ac-closure-check.yml`. 2. Repair the `rt prep` staging population after the resolver/control is present. The local toolkit-self invocation resolves `main`; a matching pinned adopter retains its baked tag; explicit `@main` remains `main`; an unmatched external wrapper refuses instead of silently bypassing its baked ref. ## Measured finding and disposition The historical #982 cut exposed the latent interaction. At review-bound cut tree `a1c383ea6f713aa73f12a708b4afa62d3baabf2d`, the AC-closure reusable carried baked `v0.53.0`, its toolkit-self wrapper invoked it by local path, the pre-fix resolver selected `v0.53.0`, and the tag lookup returned 404. The cut later shipped and the tag now exists; this is historical evidence, not a current release-state claim. The skip had a concrete source-level cause. `internal/bake/marker.go` enumerated seven canonical marker files, while `cmd/rt/prep.go` staged only six after `RewriteToolkitRefFiles`; its `bakeRefFiles` mirror omitted `reusable-ac-closure-check.yml`. The omission explains the observed 6-of-7 result. The final lists are now identical and ordered. The resolver/control commit precedes the staging-list repair commit. ## Controls - Pre-fix mutation: removing only the new local-path branch makes an unpublished baked ref remain selected; an empty scratch repository has no matching tag ref, so the checkout probe refuses it. - Fixed local toolkit-self control: baked `v0.53.0` resolves to `main` and reports the local source. - Matching pinned consumer control: baked `v0.52.0` remains `v0.52.0`. - Explicit `@main` control: resolves to `main`. - Unmatched external wrapper control: exits 1 and never resolves to `main`. - The five adopter-invoked reusables are audited independently: release, manifest, changelog-fragment, changelog-body, and register each retain external-pin extraction plus the #456 `@main` override. The existing parse control remains in place from #996. The external recognizer remains intentionally exact and unquoted. A valid quoted external `uses` line is unsupported and fails closed; broadening that syntax is a separate decision, not a reason to default to `main`. ## Verification - `bats tests/workflows.bats tests/workflow-parse-check.bats`: 60/60 passed. - `go test ./...`: passed. - `go vet ./...`: passed. - `go build ./...`: passed. - `go run ./cmd/rt fragment-check changelog.d`: passed. - `git diff --check`: passed. - All workflow YAML files parsed successfully as part of the Bats run. No external repositories were edited. No review request or merge was made.
Refs frankenbit/release-toolkit#997
fix(prep): stage the AC closure baked ref
All checks were successful
ac-closure-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 50s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 8s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 14s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 1m18s
tests / dated-examples (pull_request) Successful in 4s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 4s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 5s
workflow-parse-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 1m38s
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 1m55s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 2m27s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 2m11s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 3m13s
changelog-body-check / check (pull_request) Successful in 0s
tests / shellcheck (pull_request) Successful in 2m16s
ac-closure-check / ac-closure check (pull_request) Successful in 3m45s
ac-closure-check / check (pull_request) Successful in 0s
fragment-check / changelog fragment-kind (pull_request) Successful in 4m19s
fragment-check / check (pull_request) Successful in 0s
tests / shellcheck (push) Successful in 30s
check-self-bootstrap / check (push) Successful in 48s
tests / workflow-schema (push) Successful in 1m4s
tests / bats (push) Successful in 1m49s
tests / dated-examples (push) Successful in 1m53s
go-ci / lint + build + test (push) Successful in 2m41s
release / decide + act (push) Successful in 3m3s
release / release (push) Successful in 0s
442ff5a56a
Refs frankenbit/release-toolkit#997
lookout approved these changes 2026-08-27 09:50:28 +02:00
lookout left a comment

APPROVED — exact head 442ff5a56a.

Re-read of the complete diff: AC-closure toolkit-self local invocation resolves to main before a cut tag exists; a pinned adopter retains its baked ref; explicit @main remains main; and an unmatched external wrapper fails closed rather than falling back to main. The resolver/control commit precedes the prep staging-list repair, and the seven-entry staging list now matches bake.canonicalFiles in content and order.

I ran the focused #997 controls: all three pass, including the pre-fix unpublished-tag checkout refusal, the local/pinned/@main/unmatched resolver states, and independent audits of all five adopter reusables. Full Bats (117/117), go test -count=1 ./..., go vet ./..., go build ./..., fragment-check, YAML parsing, ShellCheck for the changed checker, and git diff --check pass. Forgejo CI is terminal-success 25/25.

The exact unquoted external recognizer remains a documented fail-closed limitation: a valid quoted external uses value is refused rather than silently bypassing the baked pin. That is disclosed in the PR and is not a blocker for this change.

APPROVED — exact head 442ff5a56aea510816e82a50748b5d2f8cbf483c. Re-read of the complete diff: AC-closure toolkit-self local invocation resolves to main before a cut tag exists; a pinned adopter retains its baked ref; explicit @main remains main; and an unmatched external wrapper fails closed rather than falling back to main. The resolver/control commit precedes the prep staging-list repair, and the seven-entry staging list now matches bake.canonicalFiles in content and order. I ran the focused #997 controls: all three pass, including the pre-fix unpublished-tag checkout refusal, the local/pinned/@main/unmatched resolver states, and independent audits of all five adopter reusables. Full Bats (117/117), go test -count=1 ./..., go vet ./..., go build ./..., fragment-check, YAML parsing, ShellCheck for the changed checker, and git diff --check pass. Forgejo CI is terminal-success 25/25. The exact unquoted external recognizer remains a documented fail-closed limitation: a valid quoted external uses value is refused rather than silently bypassing the baked pin. That is disclosed in the PR and is not a blocker for this change.
bosun merged commit 442ff5a56a into main 2026-08-27 09:52:02 +02:00
bosun deleted branch rigger/997-ac-closure-ref 2026-08-27 09:52:02 +02:00
Sign in to join this conversation.
No description provided.