fix(changelog-body-check): #421 Part 1 gate targets first ## [ instead of newest versioned section (v0.28.1 must-fix) #440

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

Motivation

v0.28.1 must-fix per Bosun bus 7a40 constraint. Load-bearing for ALL future adopter CHANGELOGs (not just release-toolkit-self), because the check is machinery adopters inherit via reusable-changelog-body-check.yml.

Surveyor review 3668 on PR#438 (v0.28.0 rolling cut) surfaced: find_target_section in scripts/changelog-body-check.sh grabs the FIRST ## [ heading in the file, which on a composed CHANGELOG is always the empty [Unreleased] section (release-prep pushes the newly-composed content into [vX.Y.Z] BELOW the still-empty [Unreleased]).

Result: the check runs against the empty [Unreleased] block and passes vacuously. The real newly-composed section is never scanned by the density gate.

Empirical confirmation: PR#438 body → my initial density-check-on-body report to Bosun (bus b77c) had extracted the v0.28.0 section manually because I noticed the check targeting [Unreleased] (the first ## [). Without manual extraction, the check reported PASS on the composed body — but running against the real section showed 3 FAILs (2 sentences >30w, 3 paragraphs >100w).

Scope

Update find_target_section in scripts/changelog-body-check.sh:

  1. If the newest ## [ heading is [Unreleased] and there is a ## [vX.Y.Z] heading BELOW it: target the versioned section (the composed one), not the empty Unreleased one.
  2. If ONLY [Unreleased] exists (pre-transition state, no versioned section yet): keep current behavior — target Unreleased so pre-release-prep CHANGELOG state is still gated.
  3. If there is no [Unreleased] above the versioned section (some adopters may not use [Unreleased]): target the newest versioned section (current behavior in that case).

Alternative simpler heuristic: always target the newest ## [vX.Y.Z] heading (with version), treating [Unreleased] as a special-case that only fires when NO versioned section exists.

Verification AC

  • Bats: composed CHANGELOG with [Unreleased] above [v0.28.0] targets [v0.28.0] (density fires on real body)
  • Bats: pre-transition CHANGELOG with only [Unreleased] still targets [Unreleased]
  • Bats: CHANGELOG with only versioned sections (no Unreleased header) still targets newest versioned
  • Regression: current bats fixtures (which dont have [Unreleased] above their target) all still pass
  • Empirical: run against PR#438-shape composed CHANGELOG; density fires on the v0.28.0 body
  • release-toolkit#421 (parent Part 1 tracker, closed)
  • Surveyor review 3668 (bug surfaced)
  • release-toolkit#438 (empirical PR)
  • Sibling: workflow_dispatch bypasses release-prep pipeline (this bug + that gap combined to allow the defects to ship)

Anchor

Surveyor review 3668 on PR#438 (2026-07-06). QM own reverse-dogfood earlier same session confirmed the same finding (had to manually extract v0.28.0 section to run the check meaningfully).

## Motivation **v0.28.1 must-fix** per Bosun bus 7a40 constraint. Load-bearing for ALL future adopter CHANGELOGs (not just release-toolkit-self), because the check is machinery adopters inherit via `reusable-changelog-body-check.yml`. Surveyor review 3668 on PR#438 (v0.28.0 rolling cut) surfaced: `find_target_section` in `scripts/changelog-body-check.sh` grabs the FIRST `## [` heading in the file, which on a composed CHANGELOG is always the empty `[Unreleased]` section (release-prep pushes the newly-composed content into `[vX.Y.Z]` BELOW the still-empty `[Unreleased]`). Result: the check runs against the empty `[Unreleased]` block and passes vacuously. The real newly-composed section is never scanned by the density gate. **Empirical confirmation**: PR#438 body → my initial density-check-on-body report to Bosun (bus b77c) had extracted the v0.28.0 section manually because I noticed the check targeting `[Unreleased]` (the first `## [`). Without manual extraction, the check reported PASS on the composed body — but running against the real section showed 3 FAILs (2 sentences >30w, 3 paragraphs >100w). ## Scope Update `find_target_section` in `scripts/changelog-body-check.sh`: 1. **If the newest `## [` heading is `[Unreleased]`** and there is a `## [vX.Y.Z]` heading BELOW it: target the versioned section (the composed one), not the empty Unreleased one. 2. **If ONLY `[Unreleased]` exists** (pre-transition state, no versioned section yet): keep current behavior — target Unreleased so pre-release-prep CHANGELOG state is still gated. 3. **If there is no `[Unreleased]` above the versioned section** (some adopters may not use `[Unreleased]`): target the newest versioned section (current behavior in that case). Alternative simpler heuristic: **always target the newest `## [vX.Y.Z]` heading (with version)**, treating `[Unreleased]` as a special-case that only fires when NO versioned section exists. ## Verification AC - [x] Bats: composed CHANGELOG with `[Unreleased]` above `[v0.28.0]` targets `[v0.28.0]` (density fires on real body) - [x] Bats: pre-transition CHANGELOG with only `[Unreleased]` still targets `[Unreleased]` - [x] Bats: CHANGELOG with only versioned sections (no Unreleased header) still targets newest versioned - [x] Regression: current bats fixtures (which dont have `[Unreleased]` above their target) all still pass - [x] Empirical: run against PR#438-shape composed CHANGELOG; density fires on the v0.28.0 body ## Related - release-toolkit#421 (parent Part 1 tracker, closed) - Surveyor review 3668 (bug surfaced) - release-toolkit#438 (empirical PR) - Sibling: workflow_dispatch bypasses release-prep pipeline (this bug + that gap combined to allow the defects to ship) ## Anchor Surveyor review 3668 on PR#438 (2026-07-06). QM own reverse-dogfood earlier same session confirmed the same finding (had to manually extract v0.28.0 section to run the check meaningfully).
alex closed this issue 2026-07-06 23:06:33 +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#440
No description provided.