chore: reconsider underscore-prefix convention for reusable workflow filenames (aesthetic) #155

Closed
opened 2026-06-27 01:46:13 +02:00 by quartermaster · 4 comments

The question

Operator surfaced 2026-06-27: the underscore prefix in _release.yml and _manifest-check.yml looks aesthetically noisy, particularly in the consumer's uses: reference (uses: ...@v/.forgejo/workflows/_release.yml@vX.Y.Z). The convention may be informal — could we use cleaner names?

What the underscore signals (today)

The _ prefix is an informal community convention marking a workflow as "internal/reusable" — meant to be invoked via workflow_call, not directly. It's NOT a substrate-enforced convention; Forgejo Actions and GitHub Actions both treat underscore-prefixed and non-prefixed names identically.

In the toolkit:

  • _release.yml — reusable (called by consumers via uses:)
  • release.yml — consumer wrapper (the toolkit's own consumer of the reusable, for self-cuts)
  • _manifest-check.yml — reusable
  • manifest-check.yml — consumer wrapper

The convention disambiguates the pair in the SAME directory. Forgejo Actions doesn't support subdirectories under .forgejo/workflows/, so the names MUST differ in some way.

Why the noise matters

External consumers type the full reusable path in their uses::

uses: frankenbit/release-toolkit/.forgejo/workflows/_release.yml@v0.11.0

The underscore is genuinely visible at the adoption surface. Cleaner naming could improve first-impression aesthetic for new consumers.

Naming options

(A) Keep current

_release.yml (reusable) + release.yml (consumer wrapper).

Pro: informal community signal; concise prefix; established in the toolkit since v0.1.0.
Con: aesthetic noise; underscore is unconventional in some naming aesthetics.

(B) -reusable / -callable / -impl suffix on the reusable

Examples:

  • release-reusable.yml + release.yml
  • release-callable.yml + release.yml (mirrors workflow_call schema)
  • release-impl.yml + release.yml ("impl" for "implementation")

Pro: explicit naming makes the role clear; aesthetic underscore gone.
Con: longer filenames in uses: references; choice of suffix word is bikeshed.

(C) Inverse: clean reusable + named caller

release.yml (reusable) + release-dispatch.yml (or release-trigger.yml / release-consumer.yml) (consumer wrapper).

Pro: the more-visible name (in consumer uses: lines) is the cleaner one.
Con: the toolkit's own consumer wrapper gets a less-natural name; consumers' OWN wrappers would now diverge from the toolkit-internal name (cellblock's release.yml is currently the same pattern as the toolkit's release.yml; this option breaks that mirroring).

(D) Different - prefix on the reusable

Examples:

  • lib-release.yml + release.yml
  • core-release.yml + release.yml

Pro: alternative readability; no underscore.
Con: arbitrary; reads more like a folder-prefix-as-name than a workflow descriptor.

My lean

(B) with -callable suffix: release-callable.yml + release.yml. Reasons:

  • callable mirrors the workflow_call schema name (substrate-honest)
  • The consumer's uses: line reads as a sensible identifier: release-toolkit/.forgejo/workflows/release-callable.yml@vX
  • No underscore aesthetic noise
  • Consumer wrapper stays as release.yml (matches cellblock + future adopters' natural naming)

Runner-up: keep current (A) on the grounds that the underscore convention is established + not actively broken.

Impact surface

If we engage (B):

  • Rename .forgejo/workflows/_release.ymlrelease-callable.yml (or other chosen suffix)
  • Rename .forgejo/workflows/_manifest-check.ymlmanifest-check-callable.yml
  • Update all uses: references across the toolkit + integration.md + cellblock (#168's release.yml) + future adopters
  • Update scripts/check-self-bootstrap.sh compose-scripts list
  • Update tests/workflows.bats if it greps on filename patterns
  • Update AGENTS.md / ADR-0004 / docs/integration.md narrative references
  • Update the consumer template + examples (#152)

Estimated scope: ~15-20 file edits. Mechanical but touches many surfaces. Worth bundling with another sprint that's already touching the workflow files (e.g., #148 build-bake or #149/#150 Unicode).

Composition

  • External consumer impact: cellblock pins uses: ...@v0.10.4-rc.1 referencing _release.yml. After this rename, cellblock's release.yml would need updating on its next toolkit-version bump.
  • Pre-1.0 readiness: the rename is a naming-schema change; cleaner to do BEFORE 1.0 commit (so 1.0 onwards adopters never see the underscore convention).
  • Sequencing with #148: if #148 ships first, the same files are touched; bundling the rename into that PR is natural. Independent otherwise.

What this PR does NOT do

  • Does NOT change workflow runtime behavior — pure rename
  • Does NOT remove the consumer-wrapper / reusable distinction — they're still two separate workflows, just renamed
  • Does NOT touch external-consumer template language unrelated to the rename

Refs

  • Operator engagement 2026-06-27: surfaced the underscore aesthetic + the convention question
  • Convention reference: informal _ prefix is a community signal but not substrate-enforced; mixed practice across public Forgejo/GitHub-Actions reusable-workflow libraries
  • Composition: #148 (build-bake — naturally bundleable), #152 (examples — would use the new naming if (B) ships first), #124 backstop (compose-scripts list reads filenames — update needed)
## The question Operator surfaced 2026-06-27: the underscore prefix in `_release.yml` and `_manifest-check.yml` looks aesthetically noisy, particularly in the consumer's `uses:` reference (`uses: ...@v/.forgejo/workflows/_release.yml@vX.Y.Z`). The convention may be informal — could we use cleaner names? ## What the underscore signals (today) The `_` prefix is an **informal community convention** marking a workflow as "internal/reusable" — meant to be invoked via `workflow_call`, not directly. It's NOT a substrate-enforced convention; Forgejo Actions and GitHub Actions both treat underscore-prefixed and non-prefixed names identically. In the toolkit: - `_release.yml` — reusable (called by consumers via `uses:`) - `release.yml` — consumer wrapper (the toolkit's own consumer of the reusable, for self-cuts) - `_manifest-check.yml` — reusable - `manifest-check.yml` — consumer wrapper The convention disambiguates the pair in the SAME directory. Forgejo Actions doesn't support subdirectories under `.forgejo/workflows/`, so the names MUST differ in some way. ## Why the noise matters External consumers type the full reusable path in their `uses:`: ```yaml uses: frankenbit/release-toolkit/.forgejo/workflows/_release.yml@v0.11.0 ``` The underscore is genuinely visible at the adoption surface. Cleaner naming could improve first-impression aesthetic for new consumers. ## Naming options ### (A) Keep current `_release.yml` (reusable) + `release.yml` (consumer wrapper). **Pro**: informal community signal; concise prefix; established in the toolkit since v0.1.0. **Con**: aesthetic noise; underscore is unconventional in some naming aesthetics. ### (B) `-reusable` / `-callable` / `-impl` suffix on the reusable Examples: - `release-reusable.yml` + `release.yml` - `release-callable.yml` + `release.yml` (mirrors `workflow_call` schema) - `release-impl.yml` + `release.yml` ("impl" for "implementation") **Pro**: explicit naming makes the role clear; aesthetic underscore gone. **Con**: longer filenames in `uses:` references; choice of suffix word is bikeshed. ### (C) Inverse: clean reusable + named caller `release.yml` (reusable) + `release-dispatch.yml` (or `release-trigger.yml` / `release-consumer.yml`) (consumer wrapper). **Pro**: the more-visible name (in consumer `uses:` lines) is the cleaner one. **Con**: the toolkit's own consumer wrapper gets a less-natural name; consumers' OWN wrappers would now diverge from the toolkit-internal name (cellblock's `release.yml` is currently the same pattern as the toolkit's `release.yml`; this option breaks that mirroring). ### (D) Different `-` prefix on the reusable Examples: - `lib-release.yml` + `release.yml` - `core-release.yml` + `release.yml` **Pro**: alternative readability; no underscore. **Con**: arbitrary; reads more like a folder-prefix-as-name than a workflow descriptor. ### My lean **(B) with `-callable` suffix**: `release-callable.yml` + `release.yml`. Reasons: - `callable` mirrors the `workflow_call` schema name (substrate-honest) - The consumer's `uses:` line reads as a sensible identifier: `release-toolkit/.forgejo/workflows/release-callable.yml@vX` - No underscore aesthetic noise - Consumer wrapper stays as `release.yml` (matches cellblock + future adopters' natural naming) **Runner-up**: keep current (A) on the grounds that the underscore convention is established + not actively broken. ## Impact surface If we engage (B): - Rename `.forgejo/workflows/_release.yml` → `release-callable.yml` (or other chosen suffix) - Rename `.forgejo/workflows/_manifest-check.yml` → `manifest-check-callable.yml` - Update **all** `uses:` references across the toolkit + integration.md + cellblock (#168's release.yml) + future adopters - Update `scripts/check-self-bootstrap.sh` compose-scripts list - Update `tests/workflows.bats` if it greps on filename patterns - Update AGENTS.md / ADR-0004 / docs/integration.md narrative references - Update the consumer template + examples ([#152](https://git.frankenbit.de/frankenbit/release-toolkit/issues/152)) Estimated scope: ~15-20 file edits. Mechanical but touches many surfaces. Worth bundling with another sprint that's already touching the workflow files (e.g., [#148](https://git.frankenbit.de/frankenbit/release-toolkit/issues/148) build-bake or [#149](https://git.frankenbit.de/frankenbit/release-toolkit/issues/149)/[#150](https://git.frankenbit.de/frankenbit/release-toolkit/issues/150) Unicode). ## Composition - **External consumer impact**: cellblock pins `uses: ...@v0.10.4-rc.1` referencing `_release.yml`. After this rename, cellblock's `release.yml` would need updating on its next toolkit-version bump. - **Pre-1.0 readiness**: the rename is a naming-schema change; cleaner to do BEFORE 1.0 commit (so 1.0 onwards adopters never see the underscore convention). - **Sequencing with [#148](https://git.frankenbit.de/frankenbit/release-toolkit/issues/148)**: if [#148](https://git.frankenbit.de/frankenbit/release-toolkit/issues/148) ships first, the same files are touched; bundling the rename into that PR is natural. Independent otherwise. ## What this PR does NOT do - **Does NOT change workflow runtime behavior** — pure rename - **Does NOT remove the consumer-wrapper / reusable distinction** — they're still two separate workflows, just renamed - **Does NOT touch external-consumer template language unrelated to the rename** ## Refs - **Operator engagement 2026-06-27**: surfaced the underscore aesthetic + the convention question - **Convention reference**: informal `_` prefix is a community signal but not substrate-enforced; mixed practice across public Forgejo/GitHub-Actions reusable-workflow libraries - **Composition**: [#148](https://git.frankenbit.de/frankenbit/release-toolkit/issues/148) (build-bake — naturally bundleable), [#152](https://git.frankenbit.de/frankenbit/release-toolkit/issues/152) (examples — would use the new naming if (B) ships first), [#124 backstop](https://git.frankenbit.de/frankenbit/release-toolkit/issues/124) (compose-scripts list reads filenames — update needed)
Author
Owner

Operator preference signaling 2026-06-27:

  • (A) keep current underscore convention — fine if the convention is genuinely common (less work; preserves established pattern)
  • (D) lib- prefix (lib-release.yml + release.yml) — preferred alternative if changing
  • (C) inversion — ruled out (mirroring + consumer wrapper name drawback)
  • (B) -callable suffix — too explanatory

Forward decision-tree: if engagement happens, lean between (A) and (D). Either decision can ship as a bundle with #148 when the workflow files are getting touched anyway.

**Operator preference signaling 2026-06-27**: - (A) keep current underscore convention — fine if the convention is genuinely common (less work; preserves established pattern) - (D) `lib-` prefix (`lib-release.yml` + `release.yml`) — preferred alternative if changing - (C) inversion — ruled out (mirroring + consumer wrapper name drawback) - (B) `-callable` suffix — too explanatory Forward decision-tree: if engagement happens, lean between (A) and (D). Either decision can ship as a bundle with [#148](https://git.frankenbit.de/frankenbit/release-toolkit/issues/148) when the workflow files are getting touched anyway.
Author
Owner

Sprint 4 decision: (A) keep underscore for now

Operator directive (2026-06-27 sprint wave): "lean (A) keep-underscore unless cold-read findings argue (D) lib-". The cold-read pass is Sprint 8 (#160) — not yet executed.

Current decision: (A) keep underscore (_release.yml + _manifest-check.yml). The aesthetic concern is real but the change touches many surfaces (~15-20 file edits + consumer wrapper schema shift + check-self-bootstrap.sh fixture); not worth committing until cold-read findings inform the call.

Sprint 4 (#148 build-bake) proceeds with current naming intact.

Conditional re-engagement

Re-open this tracker after Sprint 8 cold-read findings land if:

  • Multiple cold-read reviewers flag the underscore convention as a readability/aesthetic problem
  • OR a clear (D) lib- prefix consensus emerges
  • OR an alternative naming improvement surfaces

Closing for now to keep the sprint wave focused. Holding (A) as the operative decision until cold-read provides empirical input.

## Sprint 4 decision: (A) keep underscore for now Operator directive (2026-06-27 sprint wave): "lean (A) keep-underscore unless cold-read findings argue (D) lib-". The cold-read pass is Sprint 8 (#160) — not yet executed. Current decision: **(A) keep underscore** (`_release.yml` + `_manifest-check.yml`). The aesthetic concern is real but the change touches many surfaces (~15-20 file edits + consumer wrapper schema shift + check-self-bootstrap.sh fixture); not worth committing until cold-read findings inform the call. Sprint 4 (#148 build-bake) proceeds with current naming intact. ### Conditional re-engagement Re-open this tracker after Sprint 8 cold-read findings land if: - Multiple cold-read reviewers flag the underscore convention as a readability/aesthetic problem - OR a clear (D) `lib-` prefix consensus emerges - OR an alternative naming improvement surfaces Closing for now to keep the sprint wave focused. Holding (A) as the operative decision until cold-read provides empirical input.
Author
Owner

Re-opening — closing was premature

Operator surfaced 2026-06-27: closing trackers tends to make them forgotten. The decision here is genuinely DEFERRED-PENDING-INPUT, not RESOLVED. Re-opening with the dependency made explicit.

Status

Blocked on: #160 (cold-read of README.md + adopter-facing markdown — Sprint 8 of the pre-1.0 wave). The decision tree's empirical input — whether cold-read reviewers flag the underscore convention as a problem — is the trigger for re-engaging this tracker.

Current operative decision: (A) keep underscore. The Sprint 4 #148 build-bake PR will proceed with current naming unchanged; the rename surface (~15-20 file edits + consumer wrapper schema shift + check-self-bootstrap.sh fixture) is preserved as the cost-of-change if (D) or (B) wins post-cold-read.

Re-engagement trigger

When #160 cold-read findings land:

  • If multiple reviewers flag the underscore as a readability/aesthetic problem → re-engage this tracker with a chosen rename path (B / C / D)
  • If reviewers don't flag it → close with the (A) keep-decision as the empirically-validated choice
  • If split feedback → bring back to operator for decision

Why not close + re-file later

Closed trackers get forgotten; the cost-of-change estimate + decision-tree + operator-lean are captured here and would have to be re-derived. The forgetting failure mode is exactly the cost the operator surfaced.

Keeping open + blocked-by-#160 makes the deferral visible at any future scan of the open tracker list.

## Re-opening — closing was premature Operator surfaced 2026-06-27: closing trackers tends to make them forgotten. The decision here is genuinely DEFERRED-PENDING-INPUT, not RESOLVED. Re-opening with the dependency made explicit. ### Status **Blocked on**: #160 (cold-read of README.md + adopter-facing markdown — Sprint 8 of the pre-1.0 wave). The decision tree's empirical input — whether cold-read reviewers flag the underscore convention as a problem — is the trigger for re-engaging this tracker. **Current operative decision**: (A) keep underscore. The Sprint 4 #148 build-bake PR will proceed with current naming unchanged; the rename surface (~15-20 file edits + consumer wrapper schema shift + check-self-bootstrap.sh fixture) is preserved as the cost-of-change if (D) or (B) wins post-cold-read. ### Re-engagement trigger When #160 cold-read findings land: - If multiple reviewers flag the underscore as a readability/aesthetic problem → re-engage this tracker with a chosen rename path (B / C / D) - If reviewers don't flag it → close with the (A) keep-decision as the empirically-validated choice - If split feedback → bring back to operator for decision ### Why not close + re-file later Closed trackers get forgotten; the cost-of-change estimate + decision-tree + operator-lean are captured here and would have to be re-derived. The forgetting failure mode is exactly the cost the operator surfaced. Keeping open + blocked-by-#160 makes the deferral visible at any future scan of the open tracker list.
Author
Owner

Direction locked (2026-06-28)

Operator decision: pre-1.0 rename arc to reusable- prefix. Replace _ prefix (which can read as "internal/private") with explicit reusable- prefix (clean, descriptive, immediately signals workflow_call shape).

  • _release.ymlreusable-release.yml
  • _manifest-check.ymlreusable-manifest-check.yml

Breaking for consumers (their uses: frankenbit/release-toolkit/.forgejo/workflows/_release.yml@vX.Y.Z paths break). Pre-1.0 timing is appropriate — better now than post-1.0 where breaking renames become a real cost.

Implementation surface

  • .forgejo/workflows/_release.yml → rename to reusable-release.yml
  • .forgejo/workflows/_manifest-check.yml → rename to reusable-manifest-check.yml
  • scripts/check-self-bootstrap.sh — update DEFAULT_COMPOSE_SCRIPTS list (compose-script-touch triggers re-pin)
  • scripts/release-prep.sh — sed targets for build-bake marker (verify path strings are still anchored correctly)
  • scripts/repin.sh — wrapper-edit paths
  • docs/integration.md — example uses: paths
  • examples/go-project/.forgejo/workflows/*.yml — consumer wrapper templates
  • examples/node-project/.forgejo/workflows/*.yml — same
  • AGENTS.md §2 build-bake section + any other path-anchored references
  • tests/check-self-bootstrap.bats — fixtures
  • tests/repin.bats — fixtures
  • Migration note in next cut's changelog fragment + integration.md migration section

Estimated scope: ~50-80 lines + bats fixture updates. Engineer-shape recon-before-build.

Cuts implication

Will land as v0.18.0 (minor, per pre_v1_breaking_to_minor policy). After cut, adopters (cellblock + future tmux-tell) update their uses: paths in the same bump cycle that drops obsolete config.

Engineer dispatch following.

## Direction locked (2026-06-28) Operator decision: **pre-1.0 rename arc** to `reusable-` prefix. Replace `_` prefix (which can read as "internal/private") with explicit `reusable-` prefix (clean, descriptive, immediately signals workflow_call shape). - `_release.yml` → `reusable-release.yml` - `_manifest-check.yml` → `reusable-manifest-check.yml` Breaking for consumers (their `uses: frankenbit/release-toolkit/.forgejo/workflows/_release.yml@vX.Y.Z` paths break). Pre-1.0 timing is appropriate — better now than post-1.0 where breaking renames become a real cost. ## Implementation surface - `.forgejo/workflows/_release.yml` → rename to `reusable-release.yml` - `.forgejo/workflows/_manifest-check.yml` → rename to `reusable-manifest-check.yml` - `scripts/check-self-bootstrap.sh` — update `DEFAULT_COMPOSE_SCRIPTS` list (compose-script-touch triggers re-pin) - `scripts/release-prep.sh` — sed targets for build-bake marker (verify path strings are still anchored correctly) - `scripts/repin.sh` — wrapper-edit paths - `docs/integration.md` — example `uses:` paths - `examples/go-project/.forgejo/workflows/*.yml` — consumer wrapper templates - `examples/node-project/.forgejo/workflows/*.yml` — same - `AGENTS.md` §2 build-bake section + any other path-anchored references - `tests/check-self-bootstrap.bats` — fixtures - `tests/repin.bats` — fixtures - Migration note in next cut's changelog fragment + integration.md migration section Estimated scope: ~50-80 lines + bats fixture updates. Engineer-shape recon-before-build. ## Cuts implication Will land as v0.18.0 (minor, per `pre_v1_breaking_to_minor` policy). After cut, adopters (cellblock + future tmux-tell) update their `uses:` paths in the same bump cycle that drops obsolete config. Engineer dispatch following.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#155
No description provided.