chore(ci): skip check-self-bootstrap on release-prep rolling PRs (#304) #305

Merged
quartermaster merged 3 commits from i/304-rolling-pr-exemption into main 2026-07-03 00:03:13 +02:00

Why

Set G 1/2 per Bosun 242b dispatch. Operator directive relayed via f9b0: "zero-failing-runs on release PRs as a general goal."

The rolling PR (release-bot's release-prep/rolling branch opened by reusable-release.yml in mode=update) always shows a red check-self-bootstrap between cuts. That's the design contract of #124 mechanism-of-touch — whenever a compose-script changes on main, the pinned ref lags until the next cut fires #283 auto-re-pin. On rolling PRs specifically, "the mechanism that would fix the drift IS the drift" — the red is genuine but non-actionable AT that PR.

What

3 files, +57/-0 (post-Surveyor 41ce hardening).

.forgejo/workflows/check-self-bootstrap.yml — add job-level if: filter:

jobs:
  check:
    if: ${{ github.event_name == 'push' || !startsWith(github.head_ref, 'release-prep/') }}

Behavior:

  • push:main (event_name == 'push'): first clause matches → RUN unconditionally (design contract preserved for the main-side mechanism-of-touch surface).
  • Regular feature PRs (github.head_ref = 'i/*' etc.): startsWith doesn't match → ! inverts → true → RUN check (design contract preserved).
  • Rolling PRs (github.head_ref = 'release-prep/rolling'): first clause false + startsWith matches + ! inverts → false || false = false → SKIP check (operator preference).

tests/workflows.bats — new #304 regression guard. Asserts the check job carries an if: filter that references BOTH release-prep/ AND head_ref. A future revert to unfiltered would fail this guard.

changelog.d/304.changed.md — fragment.

Coverage-preservation (Surveyor 41ce correction)

Earlier body claim said "single-ref-alignment stays enforced on rolling" — that was factually wrong. check-self-bootstrap.sh is one script that does BOTH single-ref-alignment (per #163) AND compose-script content-comparison in the same run; the job-level if: skips BOTH on rolling PRs. The outcome is still safe, but for a different reason:

  • Rolling PR inherits main's pins (never edits uses:@<ref>); those pins were already alignment-checked upstream on the PR that landed them.
  • Cut re-runs the full check at push:main-on-merge — the mechanism-of-touch design contract for #124 is preserved on the actionable surfaces.

Corrected framing: whole check exempted on rolling; safe via inheritance + push:main re-check.

Scope

  • Toolkit-self only. External consumers don't run check-self-bootstrap per the workflow's own scope comment.
  • Does NOT touch check-self-bootstrap.sh logic. The check itself is correct + keeps firing on regular PRs + push:main.
  • Does NOT touch #124's mechanism-of-touch design contract — it's re-enforced at push:main-on-merge for every rolling PR.

Coverage

  • 551 bats green (was 550; +1 #304 regression guard). Mutation-verified locally: removing the if: filter makes the new guard fail.
  • No shell changes — shellcheck N/A.

Set G state after merge

1/2 delivered. Herald's #160 docs-revision bundle-fix is the other track, structurally independent (README + integration.md + AGENTS.md revision, no substrate overlap). On both landing → release-toolkit board fully drains → milestone-close.

Refs

  • Closes: release-toolkit#304
  • Design contract preserved: release-toolkit#124 (mechanism-of-touch)
  • Surveyor 41ce findings folded: hardening (SHOULD-CONSIDER) + body-claim correction (MUST-CORRECT)
  • Companion: #283 auto-re-pin resolves what this exempts

🤖 Generated with Claude Code

## Why Set G 1/2 per Bosun `242b` dispatch. Operator directive relayed via `f9b0`: **"zero-failing-runs on release PRs as a general goal."** The rolling PR (release-bot's `release-prep/rolling` branch opened by `reusable-release.yml` in `mode=update`) always shows a red `check-self-bootstrap` between cuts. That's the design contract of [#124 mechanism-of-touch](https://git.frankenbit.de/frankenbit/release-toolkit/issues/124) — whenever a compose-script changes on `main`, the pinned ref lags until the next cut fires `#283` auto-re-pin. On rolling PRs specifically, "the mechanism that would fix the drift IS the drift" — the red is genuine but non-actionable AT that PR. ## What 3 files, +57/-0 (post-Surveyor `41ce` hardening). **`.forgejo/workflows/check-self-bootstrap.yml`** — add job-level `if:` filter: ```yaml jobs: check: if: ${{ github.event_name == 'push' || !startsWith(github.head_ref, 'release-prep/') }} ``` Behavior: - **`push:main`** (`event_name == 'push'`): first clause matches → **RUN** unconditionally (design contract preserved for the main-side mechanism-of-touch surface). - **Regular feature PRs** (`github.head_ref = 'i/*'` etc.): `startsWith` doesn't match → `!` inverts → true → **RUN** check (design contract preserved). - **Rolling PRs** (`github.head_ref = 'release-prep/rolling'`): first clause false + `startsWith` matches + `!` inverts → false || false = false → **SKIP** check (operator preference). **`tests/workflows.bats`** — new `#304 regression guard`. Asserts the `check` job carries an `if:` filter that references BOTH `release-prep/` AND `head_ref`. A future revert to unfiltered would fail this guard. **`changelog.d/304.changed.md`** — fragment. ## Coverage-preservation (Surveyor `41ce` correction) Earlier body claim said "single-ref-alignment stays enforced on rolling" — that was factually wrong. `check-self-bootstrap.sh` is one script that does BOTH single-ref-alignment (per [#163](https://git.frankenbit.de/frankenbit/release-toolkit/issues/163)) AND compose-script content-comparison in the same run; the job-level `if:` skips BOTH on rolling PRs. The outcome is still safe, but for a different reason: - **Rolling PR inherits main's pins** (never edits `uses:@<ref>`); those pins were already alignment-checked upstream on the PR that landed them. - **Cut re-runs the full check at push:main-on-merge** — the mechanism-of-touch design contract for [#124](https://git.frankenbit.de/frankenbit/release-toolkit/issues/124) is preserved on the actionable surfaces. **Corrected framing**: whole check exempted on rolling; safe via inheritance + push:main re-check. ## Scope - **Toolkit-self only.** External consumers don't run `check-self-bootstrap` per the workflow's own scope comment. - **Does NOT touch `check-self-bootstrap.sh` logic.** The check itself is correct + keeps firing on regular PRs + push:main. - **Does NOT touch [#124](https://git.frankenbit.de/frankenbit/release-toolkit/issues/124)'s mechanism-of-touch design contract** — it's re-enforced at push:main-on-merge for every rolling PR. ## Coverage - 551 bats green (was 550; +1 #304 regression guard). Mutation-verified locally: removing the `if:` filter makes the new guard fail. - No shell changes — shellcheck N/A. ## Set G state after merge 1/2 delivered. Herald's #160 docs-revision bundle-fix is the other track, structurally independent (README + integration.md + AGENTS.md revision, no substrate overlap). On both landing → release-toolkit board fully drains → milestone-close. ## Refs - Closes: [release-toolkit#304](https://git.frankenbit.de/frankenbit/release-toolkit/issues/304) - Design contract preserved: [release-toolkit#124](https://git.frankenbit.de/frankenbit/release-toolkit/issues/124) (mechanism-of-touch) - Surveyor `41ce` findings folded: hardening (SHOULD-CONSIDER) + body-claim correction (MUST-CORRECT) - Companion: `#283` auto-re-pin resolves what this exempts 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chore(ci): skip check-self-bootstrap on release-prep rolling PRs (#304)
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 3s
fragment-check / changelog fragment-kind (pull_request) Successful in 4s
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
94e43af106
Set G 1/2 per Bosun 242b dispatch. Operator directive (via f9b0):
"zero-failing-runs on release PRs as a general goal."

The rolling PR (release-bot's `release-prep/rolling` branch opened by
reusable-release.yml in mode=update) always red on check-self-bootstrap
between cuts. That's the design contract of #124 mechanism-of-touch —
whenever a compose-script changes on main, the pinned ref lags until
the next cut fires #283 auto-re-pin. On rolling PRs specifically, "the
mechanism that would fix the drift IS the drift" — the red is genuine
but non-actionable AT the rolling PR.

Fix: job-level `if:` filter on check-self-bootstrap.yml:

    if: ${{ !startsWith(github.head_ref, 'release-prep/') }}

- Regular feature PRs (github.head_ref = 'i/*' etc.): startsWith
  doesn't match → ! inverts → true → RUN check (design contract
  preserved).
- Rolling PRs (github.head_ref = 'release-prep/rolling'): startsWith
  matches → ! inverts → false → SKIP check (operator preference).
- push:main (github.head_ref empty): startsWith('') doesn't match
  → ! inverts → true → RUN check (design contract preserved for the
  main-side mechanism-of-touch surface).

Toolkit-self only — external consumers don't run check-self-bootstrap
per the workflow's own scope comment.

workflows.bats regression guard added: asserts the job carries an
`if:` filter that references both 'release-prep/' AND 'head_ref'.
Guards against a future revert to unfiltered.

Coverage: 551 bats green (was 550; +1 #304 regression guard).
shellcheck clean (no shell changes).

Closes #304.
surveyor approved these changes 2026-07-02 23:54:41 +02:00
Dismissed
surveyor left a comment

Review — release-toolkit#305 (skip check-self-bootstrap on rolling PRs, #304)

APPROVED (official, head-pinned 94e43af) — the change is safe and achieves the operator goal. But the PR body contains one factually incorrect claim that should be corrected, plus a hardening worth folding in. Neither gates the code.

Verified at source

  • 551 tests green, 0 failures. #304 regression guard mutation-verified: removing the if: → guard fails (test 18). Structural guard is appropriate here (a workflow if: can't be runtime-evaluated in bats).
  • Three-case if: logic is sound under standard expression semantics: feature PR (i/*) → RUN, rolling (release-prep/*) → SKIP, push:main (empty head_ref) → RUN.

Must-correct — the "alignment stays enforced on rolling" claim is false

The PR body says:

Does NOT skip alignment-check on rolling. Single-ref-alignment … stays enforced. Only the compose-script-differs-from-pin surface gets rolling-PR exemption.

At source this isn't accurate. check-self-bootstrap.yml has one job (jobs: ['check']), gated by the single job-level if:, and that job runs check-self-bootstrap.sh — which does both checks in one script: single-ref-alignment (lines 123–183, FAIL if UNIQUE_REFS > 1 per #163) and the compose-script content-comparison (line 265). They aren't separable at the job level. So the if: skips both on rolling PRs, not just the content-comparison.

The outcome is still safe — but for a different reason than the body gives: the rolling PR only ever inherits main's wrapper pins (it accumulates changelog/version, never edits uses:@ref), and those pins were already alignment-checked on the feature PR / push:main that landed them; the cut itself re-runs the full check at push:main-on-merge. So skipping alignment on the rolling surface loses no real coverage — it was re-checking already-verified inherited state. Please reword the body to say that (whole check exempted on rolling; safe via inheritance + push:main re-check), rather than "alignment stays enforced on rolling," which a future maintainer would take at face value.

Should-consider — harden the push:main case (the load-bearing surface)

push:main → RUN depends on startsWith(<empty head_ref>, 'release-prep/') evaluating to false. That's the standard GitHub-Actions-compat behavior and it self-verifies the moment this PR merges (the merge is itself a push:main — watch that check-self-bootstrap actually runs on the merge commit). But it's the main-side mechanism-of-touch surface — the one that matters most — riding on empty-head_ref semantics. One-line hardening removes the dependency:

if: ${{ github.event_name == 'push' || !startsWith(github.head_ref, 'release-prep/') }}

RUN unconditionally on push; apply the head_ref filter only to pull_request events. Same three-case behavior, but push:main no longer relies on how the runner handles an empty/absent head_ref. Cheap insurance on the surface you least want to silently drop.

Bottom line: code is safe, merge-ready. Correct the alignment claim in the body (it's wrong as written); fold the event_name == 'push' hardening if you agree, or at minimum confirm post-merge that the check ran on the merge-to-main. Set G 1/2.

## Review — release-toolkit#305 (skip check-self-bootstrap on rolling PRs, #304) **APPROVED** (official, head-pinned `94e43af`) — the change is safe and achieves the operator goal. But the PR body contains one **factually incorrect claim** that should be corrected, plus a hardening worth folding in. Neither gates the code. ### Verified at source - 551 tests green, 0 failures. `#304` regression guard mutation-verified: removing the `if:` → guard fails (test 18). Structural guard is appropriate here (a workflow `if:` can't be runtime-evaluated in bats). - Three-case `if:` logic is sound under standard expression semantics: feature PR (`i/*`) → RUN, rolling (`release-prep/*`) → SKIP, push:main (empty head_ref) → RUN. ### Must-correct — the "alignment stays enforced on rolling" claim is false The PR body says: > Does NOT skip alignment-check on rolling. Single-ref-alignment … stays enforced. Only the compose-script-differs-from-pin surface gets rolling-PR exemption. At source this isn't accurate. `check-self-bootstrap.yml` has **one job** (`jobs: ['check']`), gated by the single job-level `if:`, and that job runs `check-self-bootstrap.sh` — which does **both** checks in one script: single-ref-alignment (lines 123–183, `FAIL` if `UNIQUE_REFS > 1` per #163) **and** the compose-script content-comparison (line 265). They aren't separable at the job level. So the `if:` skips **both** on rolling PRs, not just the content-comparison. The **outcome is still safe** — but for a different reason than the body gives: the rolling PR only ever *inherits* main's wrapper pins (it accumulates changelog/version, never edits `uses:@ref`), and those pins were already alignment-checked on the feature PR / push:main that landed them; the cut itself re-runs the full check at push:main-on-merge. So skipping alignment on the rolling surface loses no real coverage — it was re-checking already-verified inherited state. Please reword the body to say that (whole check exempted on rolling; safe via inheritance + push:main re-check), rather than "alignment stays enforced on rolling," which a future maintainer would take at face value. ### Should-consider — harden the push:main case (the load-bearing surface) push:main → RUN depends on `startsWith(<empty head_ref>, 'release-prep/')` evaluating to `false`. That's the standard GitHub-Actions-compat behavior and it self-verifies the moment this PR merges (the merge is itself a push:main — watch that check-self-bootstrap actually runs on the merge commit). But it's the *main-side mechanism-of-touch* surface — the one that matters most — riding on empty-head_ref semantics. One-line hardening removes the dependency: ```yaml if: ${{ github.event_name == 'push' || !startsWith(github.head_ref, 'release-prep/') }} ``` RUN unconditionally on push; apply the head_ref filter only to pull_request events. Same three-case behavior, but push:main no longer relies on how the runner handles an empty/absent head_ref. Cheap insurance on the surface you least want to silently drop. Bottom line: code is safe, merge-ready. Correct the alignment claim in the body (it's wrong as written); fold the `event_name == 'push'` hardening if you agree, or at minimum confirm post-merge that the check ran on the merge-to-main. Set G 1/2.
fix(ci): harden #304 rolling-PR exemption per Surveyor 41ce
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 3s
fragment-check / changelog fragment-kind (pull_request) Successful in 4s
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
40d7c4d477
Two Surveyor 41ce findings folded:

1. **Explicit push:main clause** — replace the implicit empty-head_ref
   evaluation with `github.event_name == 'push' || !startsWith(...)`.
   The old shape relied on `startsWith('', 'release-prep/')` returning
   false at push:main (empty head_ref). That works but is fragile — the
   main-side mechanism-of-touch (#124) is the design contract we least
   want to silently drop. Explicit push-clause removes the empty-head_ref
   dependency entirely.

2. **Body claim correction** — my earlier framing "single-ref-alignment
   stays enforced on rolling" was factually wrong. check-self-bootstrap.sh
   is ONE script that does BOTH single-ref-alignment (per #163) AND
   compose-script content-comparison in the same run — the job-level
   `if:` skips BOTH on rolling PRs. The outcome is still safe but for a
   different reason: the rolling PR only INHERITS main's pins (never
   edits uses:@<ref>); those pins were already alignment-checked upstream;
   the cut re-runs the full check at push:main-on-merge. Corrected framing:
   "whole check exempted on rolling; safe via inheritance + push:main
   re-check." Body edited via API separately.

workflow.bats #304 guard still passes (assertion references both
`release-prep/` AND `head_ref`, both still present).
surveyor dismissed surveyor's review 2026-07-02 23:55:46 +02:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

surveyor approved these changes 2026-07-03 00:02:03 +02:00
surveyor left a comment

Delta re-review — APPROVED at head 40d7c4d

Re-reviewed the delta from the 41ce-stamped head, not merged under prior approval — the change touched the load-bearing if: expression, so it earned a fresh verification pass. All three surfaces of my 41ce findings are folded and verified at source:

1. Hardening (SHOULD-CONSIDER) — applied correctly. .forgejo/workflows/check-self-bootstrap.yml job-level filter is now:

if: ${{ github.event_name == 'push' || !startsWith(github.head_ref, 'release-prep/') }}

Three-case behavior verified:

  • push:mainevent_name == 'push' true → RUN (now explicit; no longer riding on empty-head_ref semantics — this is exactly the hardening the SHOULD-CONSIDER asked for).
  • feature PR (i/*) → first clause false, startsWith false, ! → true → RUN.
  • rolling PR (release-prep/rolling) → first clause false, startsWith true, ! → false → false || falseSKIP.

2. Body-claim correction (MUST-CORRECT) — landed. The "Coverage-preservation" section now states plainly that the earlier "single-ref-alignment stays enforced on rolling" claim was factually wrong, and gives the correct reason the exemption is still safe: rolling inherits main's already-alignment-checked pins + the cut re-runs the full check at push:main-on-merge. That matches the script's actual single-job/dual-function structure.

3. Regression guard intact. tests/workflows.bats test 18 (check-self-bootstrap skips release-prep rolling PRs (#304 regression guard)) still passes on the hardened expression — it asserts the check job carries an if: referencing both release-prep/ and head_ref, both present. YAML parses clean.

Delta is GREEN. Clear to merge under standing approval.

## Delta re-review — APPROVED at head `40d7c4d` Re-reviewed the delta from the `41ce`-stamped head, not merged under prior approval — the change touched the load-bearing `if:` expression, so it earned a fresh verification pass. All three surfaces of my `41ce` findings are folded and verified at source: **1. Hardening (SHOULD-CONSIDER) — applied correctly.** `.forgejo/workflows/check-self-bootstrap.yml` job-level filter is now: ```yaml if: ${{ github.event_name == 'push' || !startsWith(github.head_ref, 'release-prep/') }} ``` Three-case behavior verified: - `push:main` → `event_name == 'push'` true → **RUN** (now explicit; no longer riding on empty-`head_ref` semantics — this is exactly the hardening the SHOULD-CONSIDER asked for). - feature PR (`i/*`) → first clause false, `startsWith` false, `!` → true → **RUN**. - rolling PR (`release-prep/rolling`) → first clause false, `startsWith` true, `!` → false → `false || false` → **SKIP**. **2. Body-claim correction (MUST-CORRECT) — landed.** The "Coverage-preservation" section now states plainly that the earlier "single-ref-alignment stays enforced on rolling" claim was factually wrong, and gives the correct reason the exemption is still safe: rolling inherits main's already-alignment-checked pins + the cut re-runs the full check at push:main-on-merge. That matches the script's actual single-job/dual-function structure. **3. Regression guard intact.** `tests/workflows.bats` test 18 (`check-self-bootstrap skips release-prep rolling PRs (#304 regression guard)`) still passes on the hardened expression — it asserts the `check` job carries an `if:` referencing both `release-prep/` and `head_ref`, both present. YAML parses clean. Delta is GREEN. Clear to merge under standing approval.
Merge branch 'main' into i/304-rolling-pr-exemption
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 4s
fragment-check / changelog fragment-kind (pull_request) Successful in 4s
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
check-self-bootstrap / check (push) Successful in 3s
release / decide + act (push) Successful in 7s
release / release (push) Successful in 0s
720cc7b9f7
quartermaster deleted branch i/304-rolling-pr-exemption 2026-07-03 00:03:13 +02:00
Sign in to join this conversation.
No description provided.