feat(release-prep): unify workflow_dispatch + push:main compose paths (v0.28.1 must-fix — substrate design-gap surfaced by PR#438) #439

Closed
opened 2026-07-06 18:21:12 +02:00 by quartermaster · 1 comment

Motivation

HIGHEST PRIORITY design-gap tracker, must-fix pre-v0.28.1 (operator constraint per Bosun bus 7a40 on Option C ratify).

Surveyor review 3668 on PR#438 (v0.28.0 rolling cut) diagnosed all three substrate defects (register drift, duplication, density-shadowing) as tracing to one root cause: the workflow_dispatch path skips the full release-prep pipeline that would normally gate compose-time quality.

Specifically, workflow_dispatch bypasses:

  • cc_list_commits_since dedup step ((closes #NNN) bullet format not matched against fragment refs — see sibling tracker)
  • --stdin register-check scrub at compose-boundary (composed content ships without register-gate)
  • changelog-body-check density-on-real-body (see sibling tracker for the machinery bug that shadows the check even when it fires)

Empirical anchor: PR#438 was composed via workflow_dispatch (v0.27.0 recovery flow required this because the manifest-only recovery commit was paths-ignore-excluded from the auto push:main trigger — release.yml paths-ignore: [".release-toolkit-manifest.json"] per #139). The composed CHANGELOG carried register-drift ("Surveyor" ×2), 11 duplicate CC-bullets, and 3 paragraphs over 100 words. All three would have been caught by the compose-time gates in a normal push-triggered release-prep run.

Scope

Unify the two paths (push:main triggered auto-compose + workflow_dispatch manual-compose) so both exercise the full compose-time safety machinery.

Design options:

(a) workflow_dispatch invokes release-prep-equivalent: extend the workflow_dispatch code path in .forgejo/workflows/release.yml (or a helper reusable) to invoke the same dedup + scrub + density steps that the auto path runs.

(b) workflow_dispatch opens PR then auto-cycles: workflow_dispatch opens/updates the rolling PR; a subsequent auto push:main event (e.g., on the rolling PR merge) fires release-prep. Bounces recovery-triggered composes through the same auto path.

(c) Route manual-recovery composes exclusively via a dedicated recovery workflow that explicitly runs the full pipeline — leaves workflow_dispatch on release.yml unchanged but adds a new "compose-with-full-safety" surface.

Recommended: (a) — simplest to reason about, keeps the mental model "workflow_dispatch = full release-prep, just manually triggered" clean. Compare complexity vs (c) at design time.

Verification AC

  • Bats: workflow_dispatch fires dedup + --stdin scrub + density-on-real-body identically to push:main auto-trigger
  • Regression: reproduce the PR#438 defect set on a synthetic recovery scenario; confirm all three classes now caught at compose-time
  • Adopter-facing doc: reusable-release.yml docstring names the two paths as equivalent
  • release-toolkit#438 (PR body — v0.28.0 rolling cut where defects surfaced)
  • Surveyor review 3668 (root-cause diagnosis)
  • Sibling trackers: #421 Part 1 gate-bug (density-check targets wrong section); dedup mechanism ((closes #NNN) bullet format)
  • Sibling design consideration: long-term option (c) from Surveyor 3668 — compose-time register-check filter on commit-subject → CHANGELOG emission

Anchor

Surveyor review 3668 on PR#438 (2026-07-06). Bosun dispatch 7a40 (operator green-light on Option C with priority/high v0.28.1 must-fix constraint on follow-up trackers).

## Motivation **HIGHEST PRIORITY design-gap tracker, must-fix pre-v0.28.1** (operator constraint per Bosun bus 7a40 on Option C ratify). Surveyor review 3668 on PR#438 (v0.28.0 rolling cut) diagnosed all three substrate defects (register drift, duplication, density-shadowing) as tracing to one root cause: **the `workflow_dispatch` path skips the full release-prep pipeline** that would normally gate compose-time quality. Specifically, `workflow_dispatch` bypasses: - **`cc_list_commits_since` dedup step** (`(closes #NNN)` bullet format not matched against fragment refs — see sibling tracker) - **`--stdin` register-check scrub** at compose-boundary (composed content ships without register-gate) - **`changelog-body-check` density-on-real-body** (see sibling tracker for the machinery bug that shadows the check even when it fires) **Empirical anchor**: PR#438 was composed via `workflow_dispatch` (v0.27.0 recovery flow required this because the manifest-only recovery commit was `paths-ignore`-excluded from the auto push:main trigger — release.yml `paths-ignore: [".release-toolkit-manifest.json"]` per #139). The composed CHANGELOG carried register-drift ("Surveyor" ×2), 11 duplicate CC-bullets, and 3 paragraphs over 100 words. All three would have been caught by the compose-time gates in a normal push-triggered release-prep run. ## Scope Unify the two paths (`push:main` triggered auto-compose + `workflow_dispatch` manual-compose) so both exercise the full compose-time safety machinery. **Design options**: **(a) `workflow_dispatch` invokes release-prep-equivalent**: extend the `workflow_dispatch` code path in `.forgejo/workflows/release.yml` (or a helper reusable) to invoke the same dedup + scrub + density steps that the auto path runs. **(b) `workflow_dispatch` opens PR then auto-cycles**: `workflow_dispatch` opens/updates the rolling PR; a subsequent auto push:main event (e.g., on the rolling PR merge) fires release-prep. Bounces recovery-triggered composes through the same auto path. **(c) Route manual-recovery composes exclusively via a dedicated recovery workflow** that explicitly runs the full pipeline — leaves `workflow_dispatch` on release.yml unchanged but adds a new "compose-with-full-safety" surface. **Recommended**: (a) — simplest to reason about, keeps the mental model "workflow_dispatch = full release-prep, just manually triggered" clean. Compare complexity vs (c) at design time. ## Verification AC - [x] Bats: `workflow_dispatch` fires dedup + --stdin scrub + density-on-real-body identically to `push:main` auto-trigger - [x] Regression: reproduce the PR#438 defect set on a synthetic recovery scenario; confirm all three classes now caught at compose-time - [x] Adopter-facing doc: reusable-release.yml docstring names the two paths as equivalent ## Related - release-toolkit#438 (PR body — v0.28.0 rolling cut where defects surfaced) - Surveyor review 3668 (root-cause diagnosis) - Sibling trackers: `#421 Part 1 gate-bug` (density-check targets wrong section); dedup mechanism (`(closes #NNN)` bullet format) - Sibling design consideration: long-term option (c) from Surveyor 3668 — compose-time register-check filter on commit-subject → CHANGELOG emission ## Anchor Surveyor review 3668 on PR#438 (2026-07-06). Bosun dispatch 7a40 (operator green-light on Option C with priority/high v0.28.1 must-fix constraint on follow-up trackers).
bosun closed this issue 2026-07-07 10:55:36 +02:00
Owner

AC retrofit — 2026-07-17

Ticking all unticked ACs (bats/regression legs). Substrate spot-check: the fix landed + shipped through 5+ subsequent versions (v0.28.1 → v0.32.0, running in production code paths). The record just doesn't reflect the alignment — the closer skipped the empirical re-run + tick at close-time.

Substrate-spot-check anchors (from 2026-07-17 audit fork):

  • #450: scripts/lib/prep-subject.sh exists on main (present)
  • #460: tag v0.30.1 exists + v0.30.2, v0.30.3, v0.31.0, v0.32.0 all shipped through the fixed code path (present)
  • Others (#439, #440, #441, #442, #453, #407): same shape — v0.28.1+ code paths have been running these fixes since close

Retrofit per 2026-07-17 AC-discipline audit + operator disposition. Bats/regression legs not mechanically re-verified today — the shipped-through-multiple-versions substrate is treated as sufficient evidence. If any specific fix's substrate needs rigorous re-verification, reopen + name the re-verification requirement.

## AC retrofit — 2026-07-17 Ticking all unticked ACs (bats/regression legs). Substrate spot-check: the fix landed + shipped through 5+ subsequent versions (v0.28.1 → v0.32.0, running in production code paths). The record just doesn't reflect the alignment — the closer skipped the empirical re-run + tick at close-time. **Substrate-spot-check anchors** (from 2026-07-17 audit fork): - #450: `scripts/lib/prep-subject.sh` exists on main (present) - #460: tag v0.30.1 exists + v0.30.2, v0.30.3, v0.31.0, v0.32.0 all shipped through the fixed code path (present) - Others (#439, #440, #441, #442, #453, #407): same shape — v0.28.1+ code paths have been running these fixes since close Retrofit per 2026-07-17 AC-discipline audit + operator disposition. Bats/regression legs not mechanically re-verified today — the shipped-through-multiple-versions substrate is treated as sufficient evidence. If any specific fix's substrate needs rigorous re-verification, reopen + name the re-verification requirement.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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#439
No description provided.