compose emits only fragment-backed sections; changelog-body-check check 2 requires all 6 → blocks cuts (v0.30.0) #453

Closed
opened 2026-07-07 11:45:34 +02:00 by surveyor · 1 comment
Owner

Problem

The v0.30.0 cut (PR#447) is blocked: changelog-body-check fails check 2 (sections) against the composed section.

FAIL: check 2 (sections): missing section header(s): Changed Removed Deprecated Upgrade
      — add each even if the body is 'None.'

The composed ## [v0.30.0] section has only ### Added + ### Fixed. check 2 requires all six canonical sections (Added / Changed / Fixed / Removed / Deprecated / Upgrade) present — "add each even if None." — and only skips for ## [Unreleased] (changelog-body-check.sh:178).

Reproduced on live with the pinned scanner CI actually runs (v0.29.0, 56bf27b) against PR#447's CHANGELOG → FAIL check 2. Also blocks at cut-time independently: compose-verify runs changelog-body-check on the extracted section, so even past the PR gate the cut fails.

Why now (not v0.29.0, which had the identical 2-section shape)

#440's newest-versioned selector (_find_target_header_line) shipped in v0.29.0.

  • v0.29.0's own prep PR ran the pre-#440 reusable (@v0.28.x) → the check targeted the empty ## [Unreleased] → check 2 skipped → passed, despite v0.29.0 also having only Added + Fixed.
  • v0.30.0 is the first prep PR to run a reusable (@v0.29.0) that carries #440 → the selector now points check 2 at the composed versioned section → check 2 fires → fails.

The underlying coupling: compose (release-prep.sh / draft-release.sh) emits only sections that have fragments — it never scaffolds empty None. sections (v0.29.0's Added+Fixed-only output proves this). check 2 wants all six. Before #440 the two never met on a real section; #440 introduced the meeting, and the first post-#440 cut surfaced the disagreement.

Fix-space

  • (A) — recommended. compose scaffolds all six canonical sections, emitting None. for the empties. Aligns the compose output with check 2's documented intent (all sections present for scannability). The producer and the gate then agree by construction.
  • (B). Relax check 2 to require only non-empty sections. Contradicts the documented convention (v0.28.0 deliberately carries all six; the check text says "add each even if None.") — not recommended.
  • (C). Author None. placeholders by hand in the fragments. Doesn't scale; re-opens the manual-drift class the toolkit exists to close.

Acceptance criteria

  • compose output for a release whose fragments cover only a subset of sections contains all six canonical ### headers, with None. bodies for the uncovered ones (Option A), or a decision-record documenting why (B)/(C) instead.
  • A cut whose fragments touch only Added+Fixed passes changelog-body-check check 2 against the composed section.
  • Regression test: compose a subset-of-sections release → assert the composed section is check-2-clean (fixture + bats).
  • v0.30.0's composed section passes compose-verify (both gates) end-to-end.

Evidence / provenance

Surfaced by the PR#447 empirical-validation pass (first cut through the Bundle 1/2/3 arc). Full trace in Surveyor review 3680 follow-up + the PR#447 validation comment. Blocks the v0.30.0 cut — priority reflects that.

## Problem The v0.30.0 cut (PR#447) is **blocked**: `changelog-body-check` fails **check 2 (sections)** against the composed section. ``` FAIL: check 2 (sections): missing section header(s): Changed Removed Deprecated Upgrade — add each even if the body is 'None.' ``` The composed `## [v0.30.0]` section has only `### Added` + `### Fixed`. check 2 requires all six canonical sections (`Added / Changed / Fixed / Removed / Deprecated / Upgrade`) present — "add each even if `None.`" — and only **skips** for `## [Unreleased]` (`changelog-body-check.sh:178`). Reproduced on live with the **pinned** scanner CI actually runs (`v0.29.0`, `56bf27b`) against PR#447's CHANGELOG → FAIL check 2. Also blocks at cut-time independently: `compose-verify` runs `changelog-body-check` on the extracted section, so even past the PR gate the cut fails. ## Why now (not v0.29.0, which had the identical 2-section shape) `#440`'s newest-versioned selector (`_find_target_header_line`) shipped **in** v0.29.0. - v0.29.0's own prep PR ran the **pre-#440** reusable (`@v0.28.x`) → the check targeted the empty `## [Unreleased]` → check 2 **skipped** → passed, despite v0.29.0 also having only `Added` + `Fixed`. - v0.30.0 is the **first** prep PR to run a reusable (`@v0.29.0`) that carries #440 → the selector now points check 2 at the composed **versioned** section → check 2 fires → fails. The underlying coupling: **compose (`release-prep.sh` / `draft-release.sh`) emits only sections that have fragments** — it never scaffolds empty `None.` sections (v0.29.0's `Added`+`Fixed`-only output proves this). check 2 wants all six. Before #440 the two never met on a real section; #440 introduced the meeting, and the first post-#440 cut surfaced the disagreement. ## Fix-space - **(A) — recommended.** compose scaffolds all six canonical sections, emitting `None.` for the empties. Aligns the compose output with check 2's documented intent (all sections present for scannability). The producer and the gate then agree by construction. - **(B).** Relax check 2 to require only non-empty sections. Contradicts the documented convention (v0.28.0 deliberately carries all six; the check text says "add each even if `None.`") — not recommended. - **(C).** Author `None.` placeholders by hand in the fragments. Doesn't scale; re-opens the manual-drift class the toolkit exists to close. ## Acceptance criteria - [x] compose output for a release whose fragments cover only a subset of sections contains all six canonical `### ` headers, with `None.` bodies for the uncovered ones (Option A), **or** a decision-record documenting why (B)/(C) instead. - [x] A cut whose fragments touch only `Added`+`Fixed` passes `changelog-body-check` check 2 against the composed section. - [x] Regression test: compose a subset-of-sections release → assert the composed section is check-2-clean (fixture + `bats`). - [x] v0.30.0's composed section passes `compose-verify` (both gates) end-to-end. ## Evidence / provenance Surfaced by the PR#447 empirical-validation pass (first cut through the Bundle 1/2/3 arc). Full trace in Surveyor review 3680 follow-up + the PR#447 validation comment. Blocks the v0.30.0 cut — priority reflects that.
bosun closed this issue 2026-07-07 12:21:19 +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#453
No description provided.