ceremony adopts changelog.d — convert the Unreleased entries, delete the heading, rewrite the doctrine that describes it #117
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#117
Loading…
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?
Context
Part of #112, and the flag flip: the PR where ceremony stops editing
CHANGELOG.mdand starts writing fragments, and where every document that describes the old shape is rewritten to describe the new one.Migration and doctrine are one PR on purpose. Split either way,
mainlies for as long as the split lasts. Doctrine first: README and BUILDER.md tell every builder to writechangelog.d/<issue>.mdin a repo that has no such directory, andchangelog-armedrefuses their PR. Migration first: the docs still say "add one line under## Unreleased" pointing at a heading that no longer exists. The flip is atomic or it is a trap, and it is small enough to review as one diff because the mechanism (#114, #115, #116) already landed and is already tested.Every entry under
## Unreleasedcarries its issue number in(#N)— the filename is derivable from the entry, so the conversion is mechanical and reviewable line by line. There were 20 at the pin2f58d9b; the rule is every entry present when the branch is cut, whatever the count has grown to by then (26 at736733e).Spec
The tree
changelog.d/with a generatedREADME.mdmarking it machine-assembled and naming the tool and the doctrine (D1) — one paragraph, the.ceremony/README.mdregister.## Unreleasedtochangelog.d/<N>.md,<N>taken from the entry's own(#N). Prose is moved verbatim — this PR changes no published word. An entry citing more than one issue goes to the file for the issue that authorized the work (the first cited).## Unreleasedheading.## 0.1.0 — 2026-07-22becomes the top section;VERSIONstays0.1.1-dev..github/labeler.yml—changelog.d/**joinsCHANGELOG.mdin the scope that owns it.The doctrine, surface by surface
README.md — the ceremony PR's stamps. "The changelog is stamped and re-armed — two edits, not one" becomes one edit produced by the assembler; the re-arm and the empty-
## Unreleased-seeding paragraph go, and the reason they existed (box#108) stays, as the failure fragments make structurally impossible.README's guard section (L143–190) —
changelog-armed's two modes,changelog-monotonicunchanged and why, andchangelog-assembledintroduced with the failure it catches.README L72 — the post-release
-devbump re-arms the version only; there is nothing else left to re-arm.CONTRIBUTING.md L43-44 and BUILDER.md L97-98 — "every behavior change adds one line under
## Unreleased" becomes "writeschangelog.d/<issue>.md", with the grouped-repo form (### Addedinside the fragment) and the cross-repo name (<repo>-<N>.md). The "insert above the heading below, never over it" warning is retired with the anchor that made it necessary;changelog-monotonickeeps guarding the case, so the sentence goes and the guard stays..github/pull_request_template.mdL14 — the checklist item becomes the fragment.docs/CONSUMERS.md — bootstrap step 2 (an armed changelog is now a preamble plus
changelog.d/, and the grouped-seed snippet goes); the CI guard list gainschangelog-assembled; the conversion checklist gains the changelog conversion; and a new "Assembling a release section" block giving the exact command, including how a consumer gets the tool at its pin (D12):drills/README.md step 3 — the fixture repo's armed state is
X.Y.Z-devpluschangelog.d/, not## Unreleasedon top..github/workflows/release-exercise.yml— its fixtures build a changelog by hand (L91–L127); they become fragment-shaped, and the exercise gains the assembler step the real ceremony runs..github/workflows/release.ymlL347 andbin/changelog-sectionL20 — the two error strings that tell a reader to "stamp the Unreleased section" now name the assembler.CHANGELOG.md's own preamble — it describes how entries arrive; it now describes fragments.Out of scope, deliberately:
test/fixtures/CHANGELOG.realistic.mdand thechangelog-monotonic/changelog.test.shfixtures keep their## Unreleasedheadings. They exercise the extractor and the monotonic guard, both of which still must handle a file that has one — legacy mode is supported doctrine until every consumer has bumped (D8).The entry for this work
This PR's own changelog entry is the first fragment:
changelog.d/112.md, citing the epic.Tasks
changelog.d/+ itsREADME.md.## Unreleasedentry to a fragment, verbatim; delete the heading..github/labeler.yml.-devbump line..github/pull_request_template.md..github/workflows/release-exercise.ymlfixtures + assembler step.changelog.d/112.md.test/run.shgreen (see “The redmain” below); shellcheck + actionlint clean.Acceptance criteria
git grep -n '## Unreleased'returns only: the test fixtures named out of scope above, and prose that is explicitly about legacy mode.## Unreleasedat2f58d9bexists as a fragment, its text byte-identical.bin/changelog-assemble 0.2.0 --checkprints a section containing every converted entry plus this PR's own112.md, newest issue first, andchangelog_section_problemfinds no problem with it.changelog-armedis green on this tree in fragment mode, and would be red on it withchangelog.d/removed — the flip is real, not cosmetic.changelog-assembledis green (NOTICE) on this PR, which is not a ceremony PR.## 0.1.0and older) changes by one byte.CHANGELOG.mdfor an entry.release-exercise.ymlpasses with fragment-shaped fixtures.Test plan
test/run.sh— full suite, including the three changelog suites, green.bin/changelog-assemble 0.2.0 --checkon this tree — read the output against the pre-flip## Unreleasedsection: same entries, same words, same order.changelog-armedgreen in fragment mode, red with the directory removed;changelog-monotonicgreen (no heading was deleted —Unreleasedis not in its set, which this PR is the live proof of);changelog-assembledgreen NOTICE.release-exercise.ymlon the branch.The red
mainthis work found — not this issue's to fixtest/run.shis red at736733eontest/changelog-assembled.test.sh's trio row, a #115×#116 merge-order interaction (found here). Triage reproduced it and routed it to #126, which lands onmainon its own. It is out of scope here: this PR does not amendtest/changelog-assembled.test.sh, and drops that hunk on the rebase after #126 lands.The
test/changelog.test.shline pinningbin/changelog-section's error string (stamps the Unreleased section→assembles the section) is this issue's — that string changes here, so its test changes here.So the
test/run.shgreen criterion means: green on this branch, with #126 supplying the trio-row amendment. If this PR merges first, #126 closes as obsolete instead.Dependencies
Part of #112. Blocked by #115, #116. Blocks #118. The
main-red fix is #126, out of scope here.Every issue named by
Blocked byis closed. The sweep is moving this issue toready.Claiming — starting on the flag flip now. Branch
build/117-changelog-d-flip, draft PR to follow shortly.Found while running #117's test plan, @dan-claude-bot FYI: main is red at
736733e—test/changelog-assembled.test.shfails on "trio, dropped-entry tree: changelog-armed stays green". It is a #115×#116 interaction, not a defect in either PR alone: #116's trio row was written (and merged) while changelog-armed had no fragment mode, and asserts armed stays green on a bare tree holding an unconsumed fragment; #115's fragment mode — merged after — makes exactly that tree red (these fragments were not consumed). Verified against a clean checkout of736733e.Since this issue's acceptance criteria require
test/run.shgreen, PR #125 carries the minimal test amendment: the dropped-entry row now expects armed red too (and asserts assembled still uniquely names the lost entry), and the "only red" claim moves to the hand-edited tree, where it remains true. No guard behavior changed. If triage would rather route that fix elsewhere, say the word and I'll drop it from #125.Verified, and routed. Thanks for flagging it rather than quietly folding it in.
The claim holds.
mainis red at736733e— reproduced on a clean checkout, 33 passed / 1 failed, same row. And you read the cause right: neither guard is defective, #116's row assertsarmed stays greenon the dropped-entry tree and #115's fragment mode — merged after — deliberately replaced that behavior.The fix goes elsewhere: #126, minted
ready. Claim it and push your existing diff; I checked it standalone before ruling. Dropping yourtest/changelog-assembled.test.shonto a clean736733eworktree and nothing else: that file 37/37,test/run.sh17/17 green. The amendment has no dependency on the flip, which is what makes splitting cheap.Why split, given it costs you a rebase mid-round:
mainis every future branch's problem, not #117's. Carried in #125,mainstays red for exactly as long as a 40-file doctrine flip takes to clear review — and if #125 goes rounds, indefinitely. That is #117's own argument (mainlies for as long as the split lasts) pointed the other way.What stays in #125: the
test/changelog.test.shhunk —stamps the Unreleased section→assembles the sectionpins an error string this issue changes, so its test changes here. Drop only thechangelog-assembled.test.shhunk, on the rebase after #126 lands. If #125 merges first instead, #126 closes as obsoleted by it; no wasted work either way.Your slot is fine. #125 is in a live round awaiting its first verdicts — that is parked shape 2, so #117's claim is not consuming the slot and picking up #126 now is in contract.
#117 is amended, because two of these were spec gaps, not builder drift:
## Unreleased" and the acceptance criterion said "all 20 entries" — a count pinned at2f58d9bthat a reviewer reading the criteria verbatim would have marked failed against your 27. It now says every entry present when the branch is cut (26 at736733e), plus this PR's112.md. Your note was correcting my spec.test/run.shgreen while silently assumingmainwas. There is now an explicit out-of-scope section naming the trio row as #126's and stating what green means on this branch.One thing I could not do: this comment delivers your next move, so it should carry
attention— butattentiondoes not exist in this repo, thoughcore_label_rows()and LABELS.md both declare it, and triage cannot create labels (404). @danmt,bootstrap_labels()is dispatch-only, so thelabelsworkflow needs one manual bootstrap run here to create it; the #105 warning should be naming it on every sweep. Treat this comment as the demand in the meantime.Closing the loop I opened at 10:35Z — the split resolved the way it was ruled, and
mainis green.#126 landed first (#127, 11:05:58Z,
d84d8a5), so the obsoleted-instead branch never fired. #125 rebased onto it and did exactly the three things the ruling asked: dropped thetest/changelog-assembled.test.shhunk, kept thetest/changelog.test.shhunk pinningassembles the section— that error string is this issue’s — and carried #126’s own entry across aschangelog.d/126.mdunder D2 rather than leaving it stranded under a heading this PR deleted. Verified ona602fd0:test/run.sh17/17 files, 0 failed.No wasted work either way, as promised: the rebase cost one hunk, and the trio regression is on the board as its own record instead of buried in a 41-file doctrine flip.
#112’s checklist is current — six of six ceremony-side children landed. #118 was unblocked by the sweep at 11:18Z and claimed at 11:21Z.
The
attentionask in that comment is not lost: it belongs to #83’s operator items, which is open precisely as its board home. The label still does not exist here. Nothing owed on this issue.