Repository navigation
Description
Problem
Every writer of CHANGELOG.md appends at one insertion point (## [Unreleased] / ### Fixed), so any two open PRs conflict as soon as one merges. In clabonte/generator, 385 of the 570 commits on main since 2026-10-01 touch the file.
A merge=union attribute makes local rebases clean, but GitHub's merge button ignores merge drivers. The PR still shows as conflicting, and a conflicted PR gets no CI run. Rebasing each item onto current main (FEAT-2026-0200) only helps the agent at the moment it opens the PR: two PRs open at once still conflict when either merges.
Why upstream
An adopter can't move fully to fragments locally, because the writers and the enforcement live here:
/fix-bug's changelog stepclose-discipline.md§3changelog.py'sappend_entryandstamp_releaseassert_changelog_entry_for_contract_changes(close-k) andspecfuse lint --closing, which require a feature close's entry to be inCHANGELOG.md
This was first raised as a comment on #3451, a closed roadmap PR, so it has no tracking item of its own. This issue is that item.
Proposal
- One entry per file under
changelog.d/, carrying its class (added/changed/fixed/breaking) and its trace (FEAT-…or#N). Naming the file after the trace means PRs for different issues can't collide. /fix-bugand the close step write a fragment.close-kaccepts an entry in either a fragment orCHANGELOG.md.- The release step collates fragments into the version section through the existing write path, deletes them in the same commit, and fails if
parse_changelogreports a finding on the result. - Opt-in per project, so an adopter that keeps a single file sees no change.
Adopter status
clabonte/generator is building an interim hybrid in clabonte/generator#3283: bug PRs write fragments through a local override, feature closes keep appending to CHANGELOG.md to satisfy close-k, and its own release script collates. Once this lands, the local override can go. Design detail and measurements: clabonte/generator#1973, #1958.
Done when
- Two open PRs that each add a changelog entry don't conflict when one merges, whether they come from
/fix-bugor a feature close. - A feature close whose entry exists only as a fragment passes
close-kandspecfuse lint --closing. - A released section contains every fragment, parses cleanly, and leaves no consumed fragment behind.
🤖 Generated with Claude Code
Activity
clabonte commentedon Nov 3, 2026
Implemented in #3566 as an opt-in
changelog.mode: fragmentsin.specfuse/layout.yml; projects on the defaultsinglemode keep the same read and write path.python3 -m specfuse.loop.changelog_fragments add, withcollateandcheckalongside it.close-k,specfuse lint --closingand the terminal auto-close guard share one reader, so an entry counts in a fragment or inCHANGELOG.md.scripts/bump_version.pyfolds fragments before stamping and deletes them. A custom release script must callcollatebefore it stamps;docs/lifecycles.mdsays so, but no test covers an adopter's script.Not yet proven: GitHub's merge button itself. The oracle uses real
git merge, so opening two real PRs that each add a fragment is the first post-merge check.FEAT-LOOP-2026-0249: changelog fragments so concurrent PRs stop confl…
clabonte commentedon Nov 4, 2026
Post-merge check passed, on released 0.32.0 code. Two PRs that each add a fragment do not conflict on GitHub; direct
CHANGELOG.mdedits still do.MERGEABLECHANGELOG.mdedit) mergedCONFLICTING/DIRTY, and its merge was refusedLimits: merges used
gh pr merge --squash, not a click on the button, against a throwaway base rather thanmain, so branch protection onmainwas not exercised. The base branch is deleted.Decision: FEAT-LOOP-2026-0200's optional append-only re-apply is skipped.