[Unreleased] heading look-alikes: an H2 after an accepted H3 is misfiled ungraded, and a fenced ### line is refused with a misleading reason #1492
Labels
No labels
bump
major
bump
minor
bump
patch
kind
bug
kind
chore
kind
docs
kind
epic
kind
feature
loop/paused
mirror-drift
priority
critical
priority
high
priority
low
priority
medium
size
L
size
M
size
S
size
XL
status
blocked
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
frankenbit/release-toolkit#1492
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?
Two edge cases left by #1486, raised in its review (notes 1 and 2). Neither loses text today; both mislead the author.
1. An H2 after an accepted H3 is filed under the previous kind
Measured on 2026-10-02 with
rt prep --dry-runon a throwaway repo. The output is byte-identical between v0.63.1 and #1486's tree.[Unreleased]:Start of the sealed
[v0.2.0]section:The author's
## Fixedentry ships under Added, with a literal## Fixedline inside the release section. Nothing grades it:rt compose-verify's check 6 counts only###duplicates, and every other check reads an H2 inside a section as body text.2. A
###line inside a fenced code block is refused as if it were a headingMergeSectionshas no fence awareness, so### not a headinginside a fenced block under[Unreleased]is read as a heading. #1486 correctly refuses it, because the merge would drop that line and the rest of the fence. But the reason it prints is<- not an accepted heading. An author who wrote the line as literal code will not see why it was refused.Acceptance criteria
##line (other than## [) under an accepted###heading in[Unreleased]is either refused byrt prepwith its line and reason, or graded at cut time. The PR picks one, as a decision tree (AGENTS.md section 7).###line inside a code fence says so, anddocs/conventions.mdmentions the case.[Unreleased]shapes stays byte-identical, pinned as in #1486.A pointer from #1508 (landed as
de49186), for whoever picks this up. It does not change either case here.Both uncarried-text refusals now print each line through
changelog.UncarriedLine.Render(where, reason).rt preppassesl.Reason(). The fold-back refusal inrt recover-pending-cutpassesl.Reason()too, except for a pending line above that section's first###heading, where it passes its own text. So a fence-aware reason computed inUncarriedLine.Reason(criterion 2) would reach both verbs. A fixture per verb would show that it does.###at column 0 ships its entries under the kind above, and nothing reports it #1591##was a fourth silent spelling, and the kind test read a map's keys #1592Fixed by PR #1589, merged fast-forward-only at
4e7a3bc4on review 8030 (@surveyor,official=true,stale=false), 5 of 5 required contexts green, rebased onto main first.All four ACs tick. AC1's decision was refuse-at-prep, as a tree: the author is still there with the CHANGELOG in hand, and a cut-time grade reports a misfiling already composed into a prepared section to whoever happens to be cutting. AC2 names the fence in the reason and
docs/conventions.mddocuments both shapes plus the third case. AC3 holds by construction —MergeSectionsis untouched — with #1486's pins and the 30-package suite as evidence. AC4 is five mutations, each firing on its own arm.Three corrections of mine, in review, worth recording together:
UncarriedLinesand broke three existing tests, including the one grading the reporter againstMergeSections. They were right: a misfiled line is carried, so reporting it there made that function's contract false.isLevel2LookAliketrimmed all leading space whileisFenceRecordthree lines above bounded at 3, so## Fixedwas refused, which is exactly whatdocs/conventions.mdin the same change tells authors to write.Edge not covered by these ACs, and in PR #1592 rather than left implied: a tab after
##was a fourth silent spelling. The ACs speak of a##line;##\tFixedis whitespace-separated and so sat on the unwritten side of my own boundary. #1592 takes any whitespace and pins the boundary as a test table.Related: #1591 carries the silent direction — a heading at any level but
###at column 0 — which needs the merge to read new lines as headings and so was deliberately not folded in here.The 34-of-34 corpus measurement, the literal-code instance, the spelling fold, the info-string rule and both nits are @surveyor's.