feat(fragments): release-notes vs CHANGELOG bifurcation — fragment frontmatter approach (B1) #77
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit#77
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Concrete motivation from v0.4.0
The v0.4.0 cut rolling PR (#76) surfaced the operator-fold pattern in detail: fragment prose-paragraphs work well as CHANGELOG.md entries (developer audience, detailed root-cause + reasoning preserved in repo history) but render too long as release-notes body (consumer audience, scanning the release page on Forgejo).
The v0.4.0 §Fixed block went from 7 long-paragraph lines (post-workflow) to 2 short-bullet lines (post-fold). The substantive content moved from fragment-prose to commit messages + tracker bodies — a manual fold the operator had to request and QM had to execute. The substrate doesn't support short-prose-out + long-prose-stays-internal automatically.
This is concretely the ADR-0006 path (a3) substrate-honesty bite landing in production: Forgejo team's "release notes are not changelogs" position (Codeberg discussion #155) mapping to release-toolkit's actual operator workflow.
Proposed shape — fragment frontmatter (B1)
Add YAML frontmatter to
changelog.d/<id>.<kind>.mdfragments with two slots:Behavior
summary:frontmatter field if present, falling back to the body's first paragraph if not. New behavior.Composition mechanics
lib/fragments.shgets a new helperfragment_get_summary PATHthat:summary:fieldsummary:draft-release.sh's body-source step usesfragment_get_summaryfor each fragment + falls back to first paragraph of cc-parsed commit body.release-prep.sh'slib/changelog.shcomposition uses the full body for CHANGELOG.md (existing behavior).Why (B1) over the alternatives
Per the original Layer B comparison from operator surfacing 2026-06-25:
<id>.<kind>.mdshort +<id>.<kind>.detail.mdlong)(B1) gives the bifurcation cleanly without the architectural shift of (B3).
Substrate-honest connection to ADR-0006
ADR-0006's path (a3) names per-artifact-lifecycle as the dissolving option for the edit-lifecycle tension. (B1) is a lighter version of (a3) — it bifurcates the prose without bifurcating the lifecycle:
(B1) doesn't preclude (B3) later; it gives the substrate-axis the operator wants WITHOUT the architectural commitment.
Implementation sketch
lib/fragments.sh: addfragment_get_summary PATHhelper + extendfragment_get_body PATHto skip frontmatter when presentlib/changelog.sh: composition step uses body verbatim (existing behavior, but skip frontmatter parsing)draft-release.sh: body-source step iterates fragments viafragment_get_summaryinstead of bodylib/conventional-commits.sh: cc-parsed commits get the first paragraph of body as summary (already approximate; may not need change)Summaries for release-notessection explaining the frontmatter patternAcceptance criteria
lib/fragments.shexposesfragment_get_summary+ parses frontmatter — partially superseded. Landed at commite565bb6 feat(fragments): release-notes/CHANGELOG bifurcation via summary frontmatter (closes #77).fragment_get_summarywas REMOVED atd88b131 feat(release)!: retire .release-toolkit-release-notes.md sidecar (#301)per operator directive 2026-07-02 (single source of truth = CHANGELOG.md). Frontmatter-parsing helpers_fragment_frontmatter_lines+_fragment_body_linessurvive (fragments.sh:388, 401) and still strip frontmatter from CHANGELOG.md body composition. AC state at 2026-07-24:fragment_get_summarydoes NOT exist; frontmatter parsing does.draft-release.shuses summary path for the release body — superseded. Landed ate565bb6; retired atd88b131(#301).draft-release.shnow sources release-body verbatim from the## [vX.Y.Z]CHANGELOG.md section (perdocs/integration.md:823§ "Release-body source (CHANGELOG.md, single source of truth)"). AC state currently FALSE by design of #301.categorize_fragments()inlib/fragments.shuses_fragment_body_lineswhich strips YAML frontmatter but retains full body prose for the CHANGELOG section (fragments.sh:462: comment references#77)._fragment_body_linesreturns the whole file if no frontmatter present (fragments.sh:401). Every fragment authored since #301 exercises this path.d88b131(#301). Currenttests/fragments.batscovers frontmatter parsing + body extraction; the summary-vs-CHANGELOG bifurcation is no longer a code path.docs/integration.md:823-838§ "Release-body source (CHANGELOG.md, single source of truth)", naming the historical v0.5.0–v0.22.0 span, the #301 retirement in v0.23.0, and the inert-frontmatter guidance (fragments retainsummary:inertly; sidecar can begit rm'd).e565bb6; SUPERSEDED byd88b131's #301 directive. Current migration guidance = "delete legacy sidecar file; strip frontmatter or leave inert" perdocs/integration.md:835. The opt-in-per-fragment framing no longer applies.Scope and sequencing
v0.4.x patch — additive change; v0.3.x consumers unaffected (no frontmatter required). Could ship as v0.4.1 once v0.4.0 GA lands.
Not blocking v0.4.0 GA — the operator-fold workflow handles the immediate cut. Filed now per Layer B commitment from 2026-06-25 operator surfacing.
Refs
AC-hygiene sweep 2026-07-24 (Quartermaster; per Bosun 3f6b dispatch): tracker was substrate-honest at close (2026-06-26 via
e565bb6); ACs 1/2/5/7 subsequently superseded by #301'sd88b131(2026-07-02) reversal per operator directive — annotated inline rather than back-ticked, since ticking a state-assertion whose substrate was retired would misrepresent current reality. ACs 3/4/6 remain substrate-true and are ticked with evidence pointers. Not a "lying tracker" (close-time state was honest); a "state moved on" case.4 ACs ticked — hand-applied, and why each one was safe
Part of the
--closed-untickedhygiene sweep.--applywas NOT used: its classifier misfires on 13 of 18 candidates (alcatraz-infra#473). These four were verified by reading, not by the tool.Each carries an explicit supersession annotation naming the landing commit — that is a genuine deferral/supersession signal, not a bare
#NNNcitation:Why ticking is honest here rather than a lie: each names work that did land at a stated commit and was then superseded by a later directive. The tick records the action; the annotation records what happened to it. Per
/srv/CLAUDE.md§ Acceptance-criteria tick discipline, that is the action-AC shape — restating a state-AC as the action that occurred — not a state-assertion about the world now.What this does NOT assert: that
fragment_get_summary's summary-preference path is live today. It is not —d88b131retired it, and the annotations say so in the AC text itself.