feat: label-based bump-control mechanism (PR labels driving SemVer bump signal) #107

Closed
opened 2026-06-26 14:16:22 +02:00 by quartermaster · 1 comment

Idea

Add a label-based mechanism for signaling SemVer bump intent on a per-PR basis. Composes with the existing three mechanisms (cc-subject !:, fragment frontmatter breaking: true, bump_override workflow input).

Why this is useful

Authors who don't want to use cc !: subject suffix and don't want to write a fragment frontmatter line could attach a label to their PR:

Label Intent
bump/major This PR triggers a major bump
bump/minor This PR triggers a minor bump (default for feat:)
bump/patch This PR triggers a patch bump (default for fix:)
bump/skip This PR explicitly does NOT trigger a bump (overrides cc-default for feat:/fix: if needed)

Composition with existing mechanisms — labels would be ADDITIVE (highest level wins):

effective_bump = max(
  cc_default_from_subject,
  fragment_breaking_signal,
  pr_label_signal,
  bump_override_input
)

This preserves backward compatibility — every existing mechanism still works; labels add a fourth signal source.

Substrate-state-care implications (§8 Axis A)

release-decide.sh currently walks git log + reads fragment files. Adding label-based bump means querying Forgejo API for PR labels in the walk window — a NEW external-system dependency. Per AGENTS.md §8 Axis A (substrate-state-care for external claims), this needs:

  • PR-label state verification — labels can be added/removed AFTER merge; what time-window is canonical? Probably "labels at merge time" since the cut decision-fires post-merge.
  • API failure handling — if the label query fails, fall back to existing mechanisms (no regression).
  • API token scope — label-read requires repository: read; the workflow token already has this.

Open design questions

  1. Walk window: should label-bump be inferable for ALL merged PRs in the walk window, or only those without other signals? (i.e., is the label a "primary signal" or a "tiebreaker"?)
  2. Label namespace: bump/* or semver/* or something else? Match existing label patterns in frankenbit's ecosystem.
  3. bump/skip semantics: does it override CC defaults entirely, or only the "auto-bump" decision? Edge case: a feat: PR labeled bump/skip — what's the right semantic?
  4. Documentation surface: where does this live? Probably docs/integration.md + the README refresh tracker.

Implementation surface

File What changes
scripts/release-decide.sh Walk the merged-PR-list in the cut window; query labels; integrate into bump_max()
scripts/lib/forgejo-api.sh Already has the PR list helper; may need pr_labels(N) helper
tests/release-decide.bats New tests for: label-driven major, label-driven skip, label + cc disagreement (max wins), label-API failure (degrades cleanly)
docs/integration.md Document the label convention + composition rule
README.md Brief mention + link to integration.md

ADR candidate?

The label-based mechanism touches the architectural axis "how do we discover bump intent" — currently expressed via ADR-0004 (push-trigger-manifest-rolling-PR). Adding a label source might warrant an ADR-0007 amendment or a fresh ADR. Decide during design pass.

Sequencing

Substrate-stable enough for v1.0? Probably — the convergence at §10 means new feature work is safe. But this should land BEFORE v1.0 commitment because:

  • It changes the public surface (new label namespace)
  • Adding it post-1.0 means another minor bump immediately

Target: implement in v0.7.x or v0.8.x as part of the pre-1.0 readiness sweep ([sibling tracker]).

Refs

  • Operator framing 2026-06-26: "there was the idea of controlling this using labels, if I remember correctly"
  • Sibling trackers: pre-v1.0 readiness sweep, README + docs refresh
  • AGENTS.md §8 Axis A — substrate-state-care discipline applies to the new Forgejo API dependency
  • ADR-0004 — push-trigger architecture this composes with
## Idea Add a label-based mechanism for signaling SemVer bump intent on a per-PR basis. Composes with the existing three mechanisms (cc-subject `!:`, fragment frontmatter `breaking: true`, `bump_override` workflow input). ## Why this is useful Authors who don't want to use cc `!:` subject suffix and don't want to write a fragment frontmatter line could attach a label to their PR: | Label | Intent | |---|---| | `bump/major` | This PR triggers a major bump | | `bump/minor` | This PR triggers a minor bump (default for `feat:`) | | `bump/patch` | This PR triggers a patch bump (default for `fix:`) | | `bump/skip` | This PR explicitly does NOT trigger a bump (overrides cc-default for `feat:`/`fix:` if needed) | **Composition with existing mechanisms** — labels would be ADDITIVE (highest level wins): ``` effective_bump = max( cc_default_from_subject, fragment_breaking_signal, pr_label_signal, bump_override_input ) ``` This preserves backward compatibility — every existing mechanism still works; labels add a fourth signal source. ## Substrate-state-care implications (§8 Axis A) `release-decide.sh` currently walks git log + reads fragment files. Adding label-based bump means querying Forgejo API for PR labels in the walk window — a NEW external-system dependency. Per AGENTS.md §8 Axis A (substrate-state-care for external claims), this needs: - **PR-label state verification** — labels can be added/removed AFTER merge; what time-window is canonical? Probably "labels at merge time" since the cut decision-fires post-merge. - **API failure handling** — if the label query fails, fall back to existing mechanisms (no regression). - **API token scope** — label-read requires `repository: read`; the workflow token already has this. ## Open design questions 1. **Walk window**: should label-bump be inferable for ALL merged PRs in the walk window, or only those without other signals? (i.e., is the label a "primary signal" or a "tiebreaker"?) 2. **Label namespace**: `bump/*` or `semver/*` or something else? Match existing label patterns in frankenbit's ecosystem. 3. **`bump/skip` semantics**: does it override CC defaults entirely, or only the "auto-bump" decision? Edge case: a `feat:` PR labeled `bump/skip` — what's the right semantic? 4. **Documentation surface**: where does this live? Probably docs/integration.md + the README refresh tracker. ## Implementation surface | File | What changes | |---|---| | `scripts/release-decide.sh` | Walk the merged-PR-list in the cut window; query labels; integrate into bump_max() | | `scripts/lib/forgejo-api.sh` | Already has the PR list helper; may need `pr_labels(N)` helper | | `tests/release-decide.bats` | New tests for: label-driven major, label-driven skip, label + cc disagreement (max wins), label-API failure (degrades cleanly) | | `docs/integration.md` | Document the label convention + composition rule | | README.md | Brief mention + link to integration.md | ## ADR candidate? The label-based mechanism touches the architectural axis "how do we discover bump intent" — currently expressed via ADR-0004 (push-trigger-manifest-rolling-PR). Adding a label source might warrant an ADR-0007 amendment or a fresh ADR. Decide during design pass. ## Sequencing Substrate-stable enough for v1.0? Probably — the convergence at §10 means new feature work is safe. But this should land BEFORE v1.0 commitment because: - It changes the public surface (new label namespace) - Adding it post-1.0 means another minor bump immediately Target: implement in v0.7.x or v0.8.x as part of the pre-1.0 readiness sweep ([sibling tracker]). ## Refs - **Operator framing 2026-06-26**: "there was the idea of controlling this using labels, if I remember correctly" - **Sibling trackers**: pre-v1.0 readiness sweep, README + docs refresh - **AGENTS.md §8 Axis A** — substrate-state-care discipline applies to the new Forgejo API dependency - **ADR-0004** — push-trigger architecture this composes with
Author
Owner

Design correction note 2026-06-26: the original scope I filed (per-source-PR label scanning in the walk window, bump/skip semantics, max-wins composition) was over-engineering from misinterpreting the operator's original idea.

Actual scope (per operator clarification 2026-06-26):

  • Rolling-PR-only mechanism (extends existing read_rolling_pr_bump_label)
  • Slash-namespace (bump/patch|minor|major) to enable Forgejo's exclusive-label group behavior
  • Labels on any other PR/issue: no effect (documented openly)
  • No bump/skip (redundant in the rolling-PR-only scope)
  • No backward-compat with bump: (colon) — zero adopters at the namespace shift

Implementation: PR #120. Closes this issue with the corrected scope.

Leaving this note so future readers of the tracker history don't re-derive the over-engineered design from the original tracker body.

**Design correction note 2026-06-26**: the original scope I filed (per-source-PR label scanning in the walk window, `bump/skip` semantics, max-wins composition) was over-engineering from misinterpreting the operator's original idea. **Actual scope** (per operator clarification 2026-06-26): - Rolling-PR-only mechanism (extends existing `read_rolling_pr_bump_label`) - Slash-namespace (`bump/patch|minor|major`) to enable Forgejo's exclusive-label group behavior - Labels on any other PR/issue: no effect (documented openly) - No `bump/skip` (redundant in the rolling-PR-only scope) - No backward-compat with `bump:` (colon) — zero adopters at the namespace shift Implementation: PR #120. Closes this issue with the corrected scope. Leaving this note so future readers of the tracker history don't re-derive the over-engineered design from the original tracker body.
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#107
No description provided.