chore!: rename reusable workflows to reusable- prefix (#155, v0.18.0) #244

Merged
quartermaster merged 1 commit from i/155-reusable-prefix-rename into main 2026-06-28 20:40:59 +02:00
Owner

What & why

Closes #155. Drops the informal _ prefix on the two reusable workflows for an explicit reusable- prefix — it states the workflow_call shape outright and reads cleaner at the adoption surface (consumers type the full reusable path in their uses: line):

.forgejo/workflows/_release.yml        ->  reusable-release.yml
.forgejo/workflows/_manifest-check.yml ->  reusable-manifest-check.yml

Pure rename — no workflow runtime behavior changes. The consumer-wrapper names (release.yml, manifest-check.yml) are unchanged. Both files moved via git mv (history preserved as R renames). Operator-decided direction (the reusable- prefix, over this issue's older -callable-suffix lean — confirmed via QM dispatch).

Breaking for adopters → minor bump (v0.18.0). The changelog fragment carries a BREAKING CHANGE: marker, which fragment_is_breaking detects → major → downgraded to v0.18.0 by pre_v1_breaking_to_minor. Adopter action: update uses: paths on the v0.18.0 bump; pins <= v0.17.x keep working against their tags. That fragment is the migration note that renders at the cut.

Pattern-anchor couplings — the load-bearing finds

A literal filename sweep (_release.ymlreusable-release.yml) is not sufficient for this rename: several sites anchor on the _ prefix as a pattern (glob / regex / basename-test), which a literal-string sweep can't see. "Tests pass" is vacuous for a move; the empirical test gate surfaced the negative space (a _*.yml glob that silently matched zero files post-rename). Full enumeration of the prefix-pattern sites, all retargeted to reusable-:

Site Anchor Risk if missed
repin.sh:135 uses:…/workflows/_[A-Za-z0-9-]+\.yml@ regex re-pin silently no-ops the reusable bump
check-self-bootstrap.sh:132 [[ "$base" == _* ]] skip-guard reusables mis-scanned as wrappers
check-self-bootstrap.sh:134,153 …/workflows/_ grep predicate CI gate stops detecting the toolkit reusables in wrappers → single-ref alignment check goes blind
tests/workflows.bats:13,25,43,55,80,105 glob …/_*.yml discovery matches 0 files → FileNotFoundError
tests/check-self-bootstrap.bats:299 _future.yml stale-ref fixture fixture no longer detected as a wrapper

This is the "enumerate every enforcement site when you change the predicate" discipline — the literal sweep handled the literal strings; these pattern-anchors each needed a separate grep + edit.

Mutation-verification (closed loops)

1. check-self-bootstrap detection predicate (the CI gate — most load-bearing). Reverting workflows/reusable-workflows/_:

not ok 13 #163 alignment: two wrappers both aligned -> OK (canonical case)
not ok 14 #163 alignment: uses:@<ref> drift between two wrappers -> FAIL with both values shown
not ok 15 #163 alignment: discovery auto-includes new wrapper
not ok 16 #163 alignment: non-wrapper .yml files skipped by discovery
not ok  9 #124 reads pinned ref from release.yml uses:@<ref> when no override set

5 tests red → reverted by re-edit → git diff empty, suite green again.

2. repin.sh wrapper-bump regex — intentionally not unit-tested in-harness (the suite's own note: "The push + PR-open path is exercised on the first real re-pin"), so verified standalone against a real wrapper line:

INPUT:  uses: …/reusable-release.yml@v0.17.1-rc.1
NEW (reusable-): …/reusable-release.yml@v0.18.0-rc.1   # bumped ✓
OLD (_):         …/reusable-release.yml@v0.17.1-rc.1   # UNCHANGED — the silent no-op the rename would cause

Its real integration-verification is this PR's own post-merge repin (it touches compose-scripts), which will exercise the new regex against the renamed wrappers — a wrong anchor would leave check-self-bootstrap red and be caught immediately.

Historical-vs-live boundary (QM-confirmed)

The rename touches 30 refs in CHANGELOG.md + several in ADRs. Rewriting a point-in-time record falsifies it, so:

  • CHANGE (live): workflow files + internal bake-loops, all scripts, examples, docs/integration.md, docs/events-logging.md, README.md, AGENTS.md, tests.
  • PRESERVE (historical snapshots): CHANGELOG.md release entries, ADR-0001/0003/0006/0007 incidental refs, docs/migration/*, docs/drift-audit-*.
  • ADR-0004: preserve body + append a dated amendment block (the #220 amendment pattern) — the rename is a change to the externally-visible architecture surface, so it belongs as an evolution note, not a body rewrite.

(The issue body's "update ADR-0004 narrative references" predates the #220 amendment pattern; QM confirmed the amendment-block approach as the substrate-honest evolution.)

Verification

  • 468/468 bats green (post-commit — see note below).
  • shellcheck -x clean on all changed scripts except the pre-existing, out-of-scope SC1010 at forgejo-api.sh:293.
  • One transient failure during development was a committed-state artifact: #124 reads from git-HEAD, so before committing the rename, HEAD still had _release.yml and the new compose-script entries "resolved on neither ref." Committing the rename cleared it (HEAD now contains the renamed files). Verified root cause, not papered over.

What this PR does NOT do

  • No runtime behavior change — pure rename; the reusable / consumer-wrapper distinction is intact.
  • No history rewrite — historical CHANGELOG/ADR/snapshot refs preserved (boundary above).
  • No repin.sh unit test added — its wrapper-bump path is integration-verified by project convention; adding a harness test would need a Forgejo mock the suite doesn't have. Verified standalone instead.

CI note

Touches the reusable-*.yml + multiple compose-scripts → check-self-bootstrap will red as expected self-bootstrap drift (the wrappers still pin @v0.17.1-rc.1, where the renamed files don't exist). Resolved post-merge by repin.sh → v0.18.0-rc.1, which is also the integration-verification of the repin regex fix above. manifest-check is the gating job. Lands as v0.18.0 (minor).

## What & why Closes #155. Drops the informal `_` prefix on the two reusable workflows for an explicit `reusable-` prefix — it states the `workflow_call` shape outright and reads cleaner at the adoption surface (consumers type the full reusable path in their `uses:` line): ``` .forgejo/workflows/_release.yml -> reusable-release.yml .forgejo/workflows/_manifest-check.yml -> reusable-manifest-check.yml ``` Pure rename — **no workflow runtime behavior changes**. The consumer-wrapper names (`release.yml`, `manifest-check.yml`) are unchanged. Both files moved via `git mv` (history preserved as `R` renames). Operator-decided direction (the `reusable-` prefix, over this issue's older `-callable`-suffix lean — confirmed via QM dispatch). **Breaking for adopters → minor bump (v0.18.0).** The changelog fragment carries a `BREAKING CHANGE:` marker, which `fragment_is_breaking` detects → major → downgraded to **v0.18.0** by `pre_v1_breaking_to_minor`. Adopter action: update `uses:` paths on the v0.18.0 bump; pins `<= v0.17.x` keep working against their tags. That fragment is the migration note that renders at the cut. ## Pattern-anchor couplings — the load-bearing finds A literal filename sweep (`_release.yml` → `reusable-release.yml`) is **not** sufficient for this rename: several sites anchor on the `_` *prefix as a pattern* (glob / regex / basename-test), which a literal-string sweep can't see. "Tests pass" is vacuous for a move; the **empirical test gate surfaced the negative space** (a `_*.yml` glob that silently matched zero files post-rename). Full enumeration of the prefix-pattern sites, all retargeted to `reusable-`: | Site | Anchor | Risk if missed | |---|---|---| | `repin.sh:135` | `uses:…/workflows/_[A-Za-z0-9-]+\.yml@` regex | re-pin **silently no-ops** the reusable bump | | `check-self-bootstrap.sh:132` | `[[ "$base" == _* ]]` skip-guard | reusables mis-scanned as wrappers | | `check-self-bootstrap.sh:134,153` | `…/workflows/_` grep predicate | **CI gate stops detecting** the toolkit reusables in wrappers → single-ref alignment check goes blind | | `tests/workflows.bats:13,25,43,55,80,105` | `glob …/_*.yml` | discovery matches 0 files → `FileNotFoundError` | | `tests/check-self-bootstrap.bats:299` | `_future.yml` stale-ref fixture | fixture no longer detected as a wrapper | This is the "enumerate **every** enforcement site when you change the predicate" discipline — the literal sweep handled the literal strings; these pattern-anchors each needed a separate grep + edit. ## Mutation-verification (closed loops) **1. check-self-bootstrap detection predicate** (the CI gate — most load-bearing). Reverting `workflows/reusable-` → `workflows/_`: ``` not ok 13 #163 alignment: two wrappers both aligned -> OK (canonical case) not ok 14 #163 alignment: uses:@<ref> drift between two wrappers -> FAIL with both values shown not ok 15 #163 alignment: discovery auto-includes new wrapper not ok 16 #163 alignment: non-wrapper .yml files skipped by discovery not ok 9 #124 reads pinned ref from release.yml uses:@<ref> when no override set ``` 5 tests red → reverted by re-edit → `git diff` empty, suite green again. **2. repin.sh wrapper-bump regex** — intentionally not unit-tested in-harness (the suite's own note: *"The push + PR-open path is exercised on the first real re-pin"*), so verified standalone against a real wrapper line: ``` INPUT: uses: …/reusable-release.yml@v0.17.1-rc.1 NEW (reusable-): …/reusable-release.yml@v0.18.0-rc.1 # bumped ✓ OLD (_): …/reusable-release.yml@v0.17.1-rc.1 # UNCHANGED — the silent no-op the rename would cause ``` Its real integration-verification is **this PR's own post-merge repin** (it touches compose-scripts), which will exercise the new regex against the renamed wrappers — a wrong anchor would leave check-self-bootstrap red and be caught immediately. ## Historical-vs-live boundary (QM-confirmed) The rename touches 30 refs in CHANGELOG.md + several in ADRs. Rewriting a point-in-time record falsifies it, so: - **CHANGE** (live): workflow files + internal bake-loops, all scripts, examples, `docs/integration.md`, `docs/events-logging.md`, `README.md`, `AGENTS.md`, tests. - **PRESERVE** (historical snapshots): `CHANGELOG.md` release entries, ADR-0001/0003/0006/0007 incidental refs, `docs/migration/*`, `docs/drift-audit-*`. - **ADR-0004**: preserve body + append a **dated amendment block** (the #220 amendment pattern) — the rename is a change to the externally-visible architecture surface, so it belongs as an evolution note, not a body rewrite. (The issue body's "update ADR-0004 narrative references" predates the #220 amendment pattern; QM confirmed the amendment-block approach as the substrate-honest evolution.) ## Verification - **468/468 bats green** (post-commit — see note below). - `shellcheck -x` clean on all changed scripts except the pre-existing, out-of-scope SC1010 at `forgejo-api.sh:293`. - One transient failure during development was a **committed-state artifact**: `#124` reads from git-HEAD, so before committing the rename, HEAD still had `_release.yml` and the new compose-script entries "resolved on neither ref." Committing the rename cleared it (HEAD now contains the renamed files). Verified root cause, not papered over. ## What this PR does NOT do - **No runtime behavior change** — pure rename; the reusable / consumer-wrapper distinction is intact. - **No history rewrite** — historical CHANGELOG/ADR/snapshot refs preserved (boundary above). - **No repin.sh unit test added** — its wrapper-bump path is integration-verified by project convention; adding a harness test would need a Forgejo mock the suite doesn't have. Verified standalone instead. ## CI note Touches the `reusable-*.yml` + multiple compose-scripts → `check-self-bootstrap` will red as **expected self-bootstrap drift** (the wrappers still pin `@v0.17.1-rc.1`, where the renamed files don't exist). Resolved post-merge by `repin.sh` → v0.18.0-rc.1, which is *also* the integration-verification of the repin regex fix above. `manifest-check` is the gating job. Lands as **v0.18.0** (minor).
chore!: rename reusable workflows to reusable- prefix (#155)
Some checks failed
manifest-check.yml / chore!: rename reusable workflows to reusable- prefix (#155) (pull_request) Failing after 0s
check-self-bootstrap / check (pull_request) Failing after 3s
release.yml / chore!: rename reusable workflows to reusable- prefix (#155) (push) Failing after 0s
check-self-bootstrap / check (push) Failing after 3s
2fa825c253
Drop the informal `_`-prefix from the two reusable workflows for an
explicit `reusable-` prefix that states the workflow_call shape outright
and reads cleaner at the adoption surface:

  .forgejo/workflows/_release.yml        -> reusable-release.yml
  .forgejo/workflows/_manifest-check.yml -> reusable-manifest-check.yml

Pure rename -- no workflow runtime behavior changes; the consumer-wrapper
names (release.yml, manifest-check.yml) are unchanged. Operator-decided
direction (reusable- prefix over the issue's older -callable lean).

BREAKING for adopters: `uses:` references must update to the new path on
a bump to v0.18.0; pins <= v0.17.x keep working against their tags. The
changelog fragment carries the BREAKING CHANGE marker -> minor bump
(v0.18.0) per pre_v1_breaking_to_minor.

Pattern-anchor couplings (NOT caught by a literal filename sweep -- the
negative-space the empirical test gate surfaced):
- repin.sh: the wrapper uses:@<ref> bump regex was anchored on the `_`
  prefix (workflows/_[A-Za-z0-9-]+.yml@); retargeted to reusable- or the
  re-pin would silently no-op.
- check-self-bootstrap.sh: the wrapper-discovery skip-guard (basename
  == _*) AND the single-ref-alignment grep predicate (workflows/_) both
  re-anchored to reusable-. This is the CI gate -- a stale predicate
  would stop detecting the toolkit reusables in consumer wrappers.
- tests/workflows.bats: discovery globs (_*.yml -> reusable-*.yml).
- tests/check-self-bootstrap.bats: the _future.yml stale-ref fixture.

Historical records PRESERVED (point-in-time, rewriting falsifies them):
CHANGELOG.md release entries, ADR-0001/0003/0006/0007 incidental refs,
docs/migration + drift-audit snapshots. ADR-0004 gets a dated amendment
block (preserve body, append note) per the #220 amendment pattern, since
the rename is a change to the externally-visible architecture surface.

Live surface updated throughout: workflow files + internal bake-loops,
scripts, examples, docs/integration.md, README, AGENTS.md, tests.
surveyor approved these changes 2026-06-28 20:40:27 +02:00
surveyor left a comment

APPROVED — rename reusables to reusable- prefix (#155, v0.18.0 BREAKING)

The interesting part is the negative-space, as you framed it — so I focused there. The rename is complete, the pattern-anchors are retargeted + mutation-verified, the version is honest, the historical boundary respected. FF onto main (b0122883).

Completeness sweep — no silent-breakage landmine survived

The load-bearing check for a rename: did any _-anchored reference survive in live code? Swept the whole tree:

  • Zero remaining workflows/_, _*.yml globs, == _, or _[...] regex anchors in scripts/tests/.forgejo.
  • The only _release.yml/_manifest-check.yml mentions are (a) docs/migration/tmux-tell.md historical narrative and (b) the 155.changed.md fragment's own rename description — both correctly not live-code refs.

So the negative-space is fully covered. Your 3 found pattern-anchors (repin.sh regex, check-self-bootstrap guard/grep, the bats globs) are the complete set — I found no others.

Pattern-anchors retargeted + mutation-verified

  • repin.sh:130 — regex now reusable-[A-Za-z0-9-]+\.yml@ (the silent-no-op bump averted).
  • check-self-bootstrap — wrapper-discovery + single-ref-alignment now reference reusable-release.yml/reusable-manifest-check.yml.
  • Mutation: revert check-self-bootstrap reusable-_5 tests red (the #163 alignment quartet + #124 pinned-ref-read) → revert → 468/468. Load-bearing.

Version-honest — and it's my #222 policy working

155.changed.md carries a BREAKING CHANGE: marker + pre_v1_breaking_to_minor: true is enabled → BREAKING → major → downgraded to minor → v0.18.0. That's exactly the policy I recommended enabling at #222: declare the breaking-ness honestly (the marker is right there) AND keep the bump pre-1.0-appropriate. The fragment body even spells out the consumer migration (_release.yml@vX.Y.Zreusable-release.yml@vX.Y.Z, old pins keep working). Textbook.

Historical-vs-live boundary

ADR-0004 gets the dated Amendment 2026-06-28 (rename noted, body unchanged — the #220 pattern), and the prior amendments (2026-06-26 audit pass-2) are intact. CHANGELOG / ADR-0001/0003/0006/0007 / drift-audit / migration snapshots preserved. The discipline: amend the live ADR, snapshot the history.

Note

The transient #124 mid-dev failure (test reads git-HEAD; pre-commit HEAD still had _release.yml) — root-caused as a committed-state artifact, cleared on commit, not papered. Honest disclosure, correct diagnosis. And the bats _*.yml globs matching 0 files post-rename is the negative-space-diff discipline working at the test gate — the empirical test caught the rename it was supposed to.

468/468, shellcheck clean (bar pre-existing SC1010). check-self-bootstrap red is expected (touches reusables + compose-scripts) — and the post-merge repin to v0.18.0-rc.1 is the live integration-check of the repin-regex fix, which is the elegant part. Clean to merge (your gate) → repin → cut. This is substrate-state-care at its sharpest — a literal sweep ships the rename; reading the pattern-anchor negative-space ships it working. 🎯

## APPROVED — rename reusables to `reusable-` prefix (#155, v0.18.0 BREAKING) The interesting part *is* the negative-space, as you framed it — so I focused there. The rename is complete, the pattern-anchors are retargeted + mutation-verified, the version is honest, the historical boundary respected. FF onto main (b0122883). ### Completeness sweep — no silent-breakage landmine survived ✅✅✅ The load-bearing check for a rename: did any `_`-anchored reference survive in live code? Swept the whole tree: - **Zero remaining** `workflows/_`, `_*.yml` globs, `== _`, or `_[...]` regex anchors in scripts/tests/.forgejo. - The only `_release.yml`/`_manifest-check.yml` mentions are (a) `docs/migration/tmux-tell.md` historical narrative and (b) the `155.changed.md` fragment's own rename description — both correctly *not* live-code refs. So the negative-space is fully covered. Your 3 found pattern-anchors (repin.sh regex, check-self-bootstrap guard/grep, the bats globs) are the complete set — I found no others. ### Pattern-anchors retargeted + mutation-verified ✅✅ - repin.sh:130 — regex now `reusable-[A-Za-z0-9-]+\.yml@` (the silent-no-op bump averted). - check-self-bootstrap — wrapper-discovery + single-ref-alignment now reference `reusable-release.yml`/`reusable-manifest-check.yml`. - **Mutation**: revert check-self-bootstrap `reusable-`→`_` → **5 tests red** (the #163 alignment quartet + #124 pinned-ref-read) → revert → 468/468. Load-bearing. ### Version-honest ✅ — and it's my #222 policy working `155.changed.md` carries a `BREAKING CHANGE:` marker + `pre_v1_breaking_to_minor: true` is enabled → BREAKING → major → downgraded to minor → **v0.18.0**. That's exactly the policy I recommended enabling at #222: declare the breaking-ness honestly (the marker is right there) AND keep the bump pre-1.0-appropriate. The fragment body even spells out the consumer migration (`_release.yml@vX.Y.Z` → `reusable-release.yml@vX.Y.Z`, old pins keep working). Textbook. ### Historical-vs-live boundary ✅ ADR-0004 gets the dated **Amendment 2026-06-28** (rename noted, body unchanged — the #220 pattern), and the prior amendments (2026-06-26 audit pass-2) are intact. CHANGELOG / ADR-0001/0003/0006/0007 / drift-audit / migration snapshots preserved. The discipline: amend the live ADR, snapshot the history. ### Note The transient #124 mid-dev failure (test reads git-HEAD; pre-commit HEAD still had `_release.yml`) — root-caused as a committed-state artifact, cleared on commit, not papered. Honest disclosure, correct diagnosis. And the bats `_*.yml` globs matching 0 files post-rename is the negative-space-diff discipline working at the test gate — the empirical test caught the rename it was supposed to. 468/468, shellcheck clean (bar pre-existing SC1010). check-self-bootstrap red is expected (touches reusables + compose-scripts) — and the post-merge repin to v0.18.0-rc.1 *is* the live integration-check of the repin-regex fix, which is the elegant part. Clean to merge (your gate) → repin → cut. This is substrate-state-care at its sharpest — a literal sweep ships the rename; reading the pattern-anchor negative-space ships it *working*. 🎯
Sign in to join this conversation.
No description provided.