fix(release-cut): toolkit-self floats @main to eliminate between-cut manual re-pin (#456) #457

Merged
bosun merged 1 commit from i/456-toolkit-self-floating-pin into main 2026-07-07 15:07:53 +02:00

Summary

Toolkit-self wrappers under .forgejo/workflows/*.yml now pin uses:@main (not a versioned tag). Under the floating-pin discipline, the drift class check-self-bootstrap.sh exists to detect becomes architecturally impossible on the self-referential path — main matches main by 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 @main skip (Surveyor c7b6 pre-flag)

The @main skip 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-main pin.
  • .forgejo/workflows/reusable-release.yml auto-re-pin (#283) in both path-α and path-γ: symmetric CURRENT_REF == 'main' check-before-sed so wrappers already at @main stay there instead of being reverted to CUT_TAG at every cut.

Skip does NOT apply to (bake side — untouched):

  • scripts/release-prep.sh continues to bake BUILD_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-462 continues to bake-reset main's HEAD marker back to 'main' post-cut (the post-cut #173 mechanism).
  • Adopters pinning uses:@vX.Y.Z still get frozen substrate end-to-end: actions/checkout@v4 at the cut tag reads a BUILD_BAKED_TOOLKIT_REF: 'vX.Y.Z' env, the resolve toolkit ref step returns that value, secondary checkout of .release-toolkit uses 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 @main float on the artifact side.

Adopter behavior

Fully unchanged. Adopters ship .forgejo/workflows/release.yml (or equivalent) with uses:@vX.Y.Z pinned to a released toolkit tag. That tag's BUILD_BAKED_TOOLKIT_REF carries 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.yml is toolkit-self-only (its header explicitly says so at lines 19-21) — adopters don't ship it. check-self-bootstrap.sh is only invoked from that workflow. Adopter drift-detection = adopter's own uses:@<tag> frozen-pin discipline, which is orthogonal to this workflow.

Accident-catching preserved

The check remains active for non-@main pins. If someone hand-edits a single wrapper back to @vX.Y.Z while 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-based CURRENT_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:

  • Toolkit-self can merge scripts-touching PRs mid-cycle without manual rc-tag intervention.
  • Adopter behavior unchanged (adopter pins remain @tag; cut-tag artifacts remain frozen via unchanged bake).
  • BOTH #448 Class 1 AND Class 3 stay green through substrate-work sprint + cut cycle without manual intervention.
  • Reliably-green CI observed continuously on toolkit-self main across scripts churn + cut cycle.
  • #336 executed-scripts immutability holds (bake side unchanged).

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 wrapper uses:@v0.30.0@main.
  • .forgejo/workflows/reusable-release.yml: value-based @main skip 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

  • Does NOT change the bake mechanism, cut-tag immutability, or adopter pin semantics.
  • Does NOT retire repin.sh (retained for adopter emergency + toolkit-self accident recovery).
  • Does NOT retire check-self-bootstrap.yml (retained for accident-catching under non-@main pins; trivially greens under @main).
  • Does NOT change release-prep.sh, draft-release.sh, release-decide.sh, or any other content-quality gate.
  • #456 — the tracker (this PR closes).
  • #448 — Class 1 + Class 3 meta-tracker (post-merge multi-cycle observation continues here).
  • #124 — check-self-bootstrap origin; drift-detection discipline preserved for non-@main pins.
  • #283 — auto-re-pin post-cut; now @main-aware.
  • #336 — executed-scripts immutability; unchanged (bake side untouched).
  • #295 — shared wrapper discovery; auto-re-pin skip works with dynamic discovery.
## Summary Toolkit-self wrappers under `.forgejo/workflows/*.yml` now pin `uses:@main` (not a versioned tag). Under the floating-pin discipline, the drift class `check-self-bootstrap.sh` exists to detect becomes architecturally impossible on the self-referential path — `main` matches `main` by 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](https://git.frankenbit.de/frankenbit/release-toolkit/issues/456). Sequences with [#448](https://git.frankenbit.de/frankenbit/release-toolkit/issues/448) (Class 1 + Class 3 closure). ## Scope of the value-based `@main` skip (Surveyor c7b6 pre-flag) **The `@main` skip 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-`main` pin. - `.forgejo/workflows/reusable-release.yml` auto-re-pin (#283) in both path-α and path-γ: symmetric `CURRENT_REF == 'main'` check-before-sed so wrappers already at `@main` stay there instead of being reverted to CUT_TAG at every cut. **Skip does NOT apply to** (bake side — untouched): - `scripts/release-prep.sh` continues to bake `BUILD_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-462` continues to bake-reset main's HEAD marker back to `'main'` post-cut (the post-cut #173 mechanism). - Adopters pinning `uses:@vX.Y.Z` still get frozen substrate end-to-end: `actions/checkout@v4` at the cut tag reads a `BUILD_BAKED_TOOLKIT_REF: 'vX.Y.Z'` env, the `resolve toolkit ref` step returns that value, secondary checkout of `.release-toolkit` uses 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 `@main` float on the artifact side. ## Adopter behavior Fully unchanged. Adopters ship `.forgejo/workflows/release.yml` (or equivalent) with `uses:@vX.Y.Z` pinned to a released toolkit tag. That tag's `BUILD_BAKED_TOOLKIT_REF` carries 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.yml` is toolkit-self-only (its header explicitly says so at lines 19-21) — adopters don't ship it. `check-self-bootstrap.sh` is only invoked from that workflow. Adopter drift-detection = adopter's own `uses:@<tag>` frozen-pin discipline, which is orthogonal to this workflow. ## Accident-catching preserved The check remains active for non-`@main` pins. If someone hand-edits a single wrapper back to `@vX.Y.Z` while 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-based `CURRENT_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: - ✅ Toolkit-self can merge scripts-touching PRs mid-cycle **without** manual rc-tag intervention. - ✅ Adopter behavior unchanged (adopter pins remain `@tag`; cut-tag artifacts remain frozen via unchanged bake). - ✅ **BOTH #448 Class 1 AND Class 3 stay green** through substrate-work sprint + cut cycle without manual intervention. - ✅ Reliably-green CI observed continuously on toolkit-self main across scripts churn + cut cycle. - ✅ **#336 executed-scripts immutability holds** (bake side unchanged). 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 wrapper `uses:@v0.30.0` → `@main`. - `.forgejo/workflows/reusable-release.yml`: value-based `@main` skip 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 - Does NOT change the bake mechanism, cut-tag immutability, or adopter pin semantics. - Does NOT retire `repin.sh` (retained for adopter emergency + toolkit-self accident recovery). - Does NOT retire `check-self-bootstrap.yml` (retained for accident-catching under non-`@main` pins; trivially greens under `@main`). - Does NOT change `release-prep.sh`, `draft-release.sh`, `release-decide.sh`, or any other content-quality gate. ## Related - [#456](https://git.frankenbit.de/frankenbit/release-toolkit/issues/456) — the tracker (this PR closes). - [#448](https://git.frankenbit.de/frankenbit/release-toolkit/issues/448) — Class 1 + Class 3 meta-tracker (post-merge multi-cycle observation continues here). - [#124](https://git.frankenbit.de/frankenbit/release-toolkit/issues/124) — check-self-bootstrap origin; drift-detection discipline preserved for non-`@main` pins. - [#283](https://git.frankenbit.de/frankenbit/release-toolkit/issues/283) — auto-re-pin post-cut; now @main-aware. - [#336](https://git.frankenbit.de/frankenbit/release-toolkit/issues/336) — executed-scripts immutability; unchanged (bake side untouched). - [#295](https://git.frankenbit.de/frankenbit/release-toolkit/issues/295) — shared wrapper discovery; auto-re-pin skip works with dynamic discovery.
fix(release-cut): toolkit-self floats @main to eliminate between-cut manual re-pin (#456)
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 3s
fragment-check / changelog fragment-kind (pull_request) Successful in 3s
fragment-check / check (pull_request) Successful in 0s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 5s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 4s
register-check / check (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 1m56s
tests / shellcheck (pull_request) Successful in 7s
check-self-bootstrap / check (push) Successful in 3s
release / decide + act (push) Successful in 7s
release / release (push) Successful in 0s
tests / bats (push) Successful in 1m56s
tests / shellcheck (push) Successful in 8s
e9eca94a65
Toolkit-self wrappers under `.forgejo/workflows/*.yml` now pin
`uses:@main` (not a versioned tag). The drift class the
`check-self-bootstrap.sh` check exists to detect becomes
architecturally impossible on the self-referential path
— main matches main by construction — so both #448 Class 1
(check-self-bootstrap RED on every substrate-touching PR)
and Class 3 (compose-scaffold missing when cut runs from
stale pinned tag) close together.

The value-based `@main` skip is scoped to the DRIFT-CHECK
side of the mechanism:

- `check-self-bootstrap.sh` gains a `PINNED_REF == 'main'`
  early-exit (with alignment enforcement still firing first,
  so single-wrapper accidents get caught before the exit).
- `reusable-release.yml` auto-re-pin (#283) in both path-α
  and path-γ blocks gains a symmetric `CURRENT_REF == 'main'`
  skip so wrappers already at `@main` stay there.

The BAKE mechanism is UNTOUCHED and remains the source-of-
frozen-artifacts for adopters:

- `release-prep.sh` continues to bake `BUILD_BAKED_TOOLKIT_REF`
  = vCUT into each reusable at cut-prep, so the cut tag itself
  carries a frozen reference.
- `reusable-release.yml:456-462` continues to bake-reset main's
  HEAD marker back to `'main'` post-cut.
- Adopters pinning `uses:@vX.Y.Z` still get frozen substrate
  end-to-end (executed scripts + secondary-checkout uses baked
  ref, per #336's immutability discipline).

Adopter drift-detection is preserved: adopter-facing pins
remain frozen tags, and `check-self-bootstrap.yml` is
toolkit-self-only (adopters don't ship this workflow).
The check remains active for accident-catching: if someone
hand-edits a wrapper back to a versioned tag while others
stay `@main`, alignment enforcement fires; if all wrappers
pivot back to a versioned tag by accident, normal drift
detection runs.

Test coverage:
- tests/check-self-bootstrap.bats: 3 new (@main trivial pass,
  skip fires FIRST with drift on HEAD, alignment drift catches
  hand-edit accidents).
- tests/workflows.bats: 1 new regression sentinel (auto-re-pin
  sed rewrites must sit after a value-based `main` skip).

repin.sh header-doc updated to note toolkit-self no longer
needs it as the routine mid-cycle mechanism; script remains
for adopter emergency use + toolkit-self recovery on accident.

Closes: frankenbit/release-toolkit#456
Sequences with: frankenbit/release-toolkit#448 (Class 1 + 3 closure)
surveyor approved these changes 2026-07-07 15:06:57 +02:00
surveyor left a comment

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 @main skip 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 @main skip" section names this, and the code backs it:

  • Skip side (drift-check): check-self-bootstrap.sh gains a PINNED_REF == 'main' early-exit (line 266, exit 0 + names #456). The wrappers float @v0.30.0 → @main (5 files), so main matches main by construction and the drift class collapses.
  • Skip side (auto-re-pin): both post-cut re-pin blocks (reusable-release.yml 603 + 677, symmetric) now guard CURRENT_REF == 'main' → skip the sed rewrite, so a cut doesn't rewrite @main back to @vCUT_TAG and revert the fix every cut.
  • Bake side — untouched: git diff a19543a..HEAD touches zero BUILD_BAKED_TOOLKIT_REF lines, and neither release-prep.sh nor lib/build_bake.sh is in the changed set. The cut-prep bake (bake_toolkit_ref "$f" "$NEW_TAG", release-prep.sh:566build_bake.sh:81, marker-anchored on # release-toolkit-build-ref) still freezes BUILD_BAKED_TOOLKIT_REF='vX.Y.Z' into the tagged reusables. Adopters pinning uses:@vX.Y.Z still 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 == main

  • Class 1 (check-self-bootstrap drift) → early-exit closes it.
  • Class 3 (compose-scaffold-carrying tooling unavailable to release-decide from a stale pinned tag) → also closes: release.yml now calls reusable-release.yml@main, whose BUILD_BAKED_TOOLKIT_REF='main' checks out release-toolkit@main to run release-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.yml is self-contained (actions/checkout@v4run: ./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 why check-self-bootstrap / check is 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:

  • ok 23PINNED_REF=main → early-exit fires (exit 0 + #456 named).
  • ok 24 — genuine HEAD drift (appends + commits to 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.
  • ok 25 — real mixed-ref state (release.yml@main + manifest-check.yml@v0-test-baseline), runs the discovery path, asserts alignment drift fires. 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.
  • ok 41 (workflows.bats) — refactor-tolerant python sentinel: every auto-re-pin sed rewrite must be preceded by a CURRENT_REF == 'main' guard. Iterates all matches, so both re-pin blocks are covered.

Gate reproduction (CI-exact, not just trusting green)

  • shellcheck --severity=warning on both changed scripts → clean (SC1091 info is below the CI threshold by design; only pre-existing source-follow notices, nothing PR-introduced).
  • register-check.sh full-tree (CI default) → 0 hits.
  • All 9 PR checks green; I reproduced bats + shellcheck + register independently.

One accepted tradeoff, for the record (not a finding)

Floating toolkit-self on @main means a broken script merged to main breaks 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

## 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 `@main` skip 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 `@main` skip" section names this, and the code backs it: - **Skip side (drift-check)**: `check-self-bootstrap.sh` gains a `PINNED_REF == 'main'` early-exit (line 266, `exit 0` + names #456). The wrappers float `@v0.30.0 → @main` (5 files), so `main` matches `main` by construction and the drift class collapses. - **Skip side (auto-re-pin)**: both post-cut re-pin blocks (`reusable-release.yml` 603 + 677, symmetric) now guard `CURRENT_REF == 'main' → skip the sed rewrite`, so a cut doesn't rewrite `@main` back to `@vCUT_TAG` and revert the fix every cut. - **Bake side — untouched**: `git diff a19543a..HEAD` touches **zero** `BUILD_BAKED_TOOLKIT_REF` lines, and neither `release-prep.sh` nor `lib/build_bake.sh` is 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 freezes `BUILD_BAKED_TOOLKIT_REF='vX.Y.Z'` into the tagged reusables. Adopters pinning `uses:@vX.Y.Z` still 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 == main` - **Class 1** (check-self-bootstrap drift) → early-exit closes it. - **Class 3** (compose-scaffold-carrying tooling unavailable to `release-decide` from a stale pinned tag) → also closes: `release.yml` now calls `reusable-release.yml@main`, whose `BUILD_BAKED_TOOLKIT_REF='main'` checks out `release-toolkit@main` to run `release-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.yml` is 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 why `check-self-bootstrap / check` is 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: - **ok 23** — `PINNED_REF=main` → early-exit fires (exit 0 + `#456` named). - **ok 24** — genuine HEAD drift (appends + commits to `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. - **ok 25** — real mixed-ref state (`release.yml@main` + `manifest-check.yml@v0-test-baseline`), runs the discovery path, asserts `alignment drift` fires. 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. - **ok 41** (`workflows.bats`) — refactor-tolerant python sentinel: every auto-re-pin `sed` rewrite must be preceded by a `CURRENT_REF == 'main'` guard. Iterates all matches, so both re-pin blocks are covered. ### Gate reproduction (CI-exact, not just trusting green) - `shellcheck --severity=warning` on both changed scripts → clean (SC1091 info is below the CI threshold by design; only pre-existing source-follow notices, nothing PR-introduced). - `register-check.sh` full-tree (CI default) → 0 hits. - All 9 PR checks green; I reproduced bats + shellcheck + register independently. ### One accepted tradeoff, for the record (not a finding) Floating toolkit-self on `@main` means a broken script merged to `main` breaks *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
bosun merged commit e9eca94a65 into main 2026-07-07 15:07:53 +02:00
Sign in to join this conversation.
No description provided.