feat: actions/changelog-monotonic — shipped release headings are append-only #41
No reviewers
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#41
Loading…
Reference in a new issue
No description provided.
Delete branch "build/6-changelog-monotonic"
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?
Closes #6
Acceptance criteria
uses: ./actions/changelog-monotonicin this repo's CI — a scratch fixture job until #11 gives the repo a changelog of its own, and a real one: the exercise commits a fixture base in the job's checkout, commits an insert-above edit on top, and runs the action against that history, so green means a genuine merge-base containment run, not an action.yml parse.Builder notes
exit. This repo's canonical extractor (changelog_section, #4) is theif (found) exitshape — so the header and the duplicate error message tell the truth for this repo (truncation; the stranded entry is dropped from this release's notes and the next's), while preserving both shapes' history per cast#133.changelog-monotonic.sh [<base-ref>] [<changelog>], env fallbacksCHANGELOG_MONOTONIC_BASE/CHANGELOG/CHANGELOG_MONOTONIC_STRICT(script default0for sensible local degradation, exactly as the issue specifies; the action defaultsstrictto"1"because it runs in CI).action.ymldocuments thefetch-depth: 0requirement and what its absence looks like (a red STRICT failure naming the checkout fix). No version source — the guard reads the diff, never VERSION/package.json.origin/maindefault, because the exercise job's shallow PR checkout carries noorigin/main; consumers get the default viafetch-depth: 0, which is the action's documented requirement.Worklog
actions/changelog-monotonic/changelog-monotonic.shfrom box (origin), fold in cast#133 port notes, adapt references to this repo'slib/changelog.shextractoraction.yml— composite, inputsbase-ref/changelog/strict(default "1"), fetch-depth: 0 requirement documentedtest/changelog-monotonic.test.sh— constructed git repos covering every case in the issue's test listuses: ./actions/changelog-monotonicagainst a scratch history with real containmentChangelog
CHANGELOG.mdintentionally does not exist on main yet — #11 owns its bootstrap and backfills pre-#11 entries (family precedent: PRs #28/#29/#31/#33/#39).🔎 reviewing head
a0bea573a1🔎 reviewing head
a0bea573a1Verdict: approve
Reviewed head
a0bea573a14fcc4a0b43eaacc3bbfc583b047171against #6.Acceptance criteria
Action + script + tests; CI green; shellcheck clean —
actions/changelog-monotonic/{action.yml,changelog-monotonic.sh}andtest/changelog-monotonic.test.shland. CItest+action-exerciseboth SUCCESS. Local: full suite 7/7 files green (monotonic 20/20), shellcheck clean on the new scripts.CI exercise via
uses: ./actions/changelog-monotonic—action-exercisebuilds a real two-commit history (fixture base branch → insert-above mutation) and runs the composite against it with an explicitbase-ref, so green means genuine merge-base containment, not anaction.ymlparse. Correct choice given the shallow PR checkout has noorigin/mainfor the default.Header / incident lore — box#122 / box#118, the three-reasons-for-a-separate-file essay, cast#133 extractor shapes, and box#143 uniqueness-before-history are all present and accurate for this repo's
if (found) exitextractor.Spec fidelity
## X.Y.Zset members;## Unreleasedexcluded by version shape."1"in the action,"0"in the script; skip path namesfetch-depth: 0.base-ref/changelog/strict); no version source.Changelog exception
No
CHANGELOG.mdentry is correct here — file does not exist on main yet; #11 owns bootstrap (family precedent with prior guard PRs).Approve.
Verdict: I agree with everything and have no additional feedback.
Reviewed the complete current head
a0bea57against issue #6. Uniqueness runs before every history-dependent gate, containment and STRICT behavior match the contract, the composite inputs and documentation are correct, and the CI exercise performs a real merge-base containment run. Current test and action-exercise checks are green.Approve at
a0bea57. Verified, not just read:Acceptance criteria (issue #6)
testjob includes the shellcheck and actionlint gates). Locally:test/changelog-monotonic.test.sh20/20 pass; the 3 failing files in the suite are pre-existing environment gaps here (no node/npm/jq on this box), unrelated to this PR.uses: ./actions/changelog-monotonicin theaction-exercisejob — and it is a genuine containment run: the job commits a fixture base, branches it, commits an insert-above edit, and runs the action against that history withstrictat its CI default of "1". The explicitly-passedbase-ref(rather than the input'sorigin/maindefault) is correct for a shallow PR checkout and documented in the job comment.The rule, tested against constructed repos I drove myself
fetch-depth: 0, and0.7.0vs0.7.0-rc1as distinct set members.0.7.0-rc1and adding0.7.0passes (all 1 release heading(s) at the merge base ... are still present), confirming superset is exact and the whole-field set membership works in both directions.Port fidelity
changelog_section/lib/changelog.sh for release-notes.sh, tree's version for VERSION), plus the specified interface additions (CHANGELOG/CHANGELOG_MONOTONIC_BASEenv fallbacks). Zero logic drift. The extractor-shape adaptation (truncation here vs absorption in box) is truthful for this repo'sif (found) exitextractor.action.yml
base-refdefaultorigin/${{ github.base_ref || github.ref_name }},changelogdefaultCHANGELOG.md,strictdefault"1"with the script's local default staying0, and thefetch-depth: 0requirement documented in the description along with the red-STRICT failure shape its absence produces. No version source, as specified.Changelog exception stated and consistent with family precedent (#28/#29/#31/#33/#39 — #11 owns the bootstrap).
Nothing blocking. Non-blocking note: the
## 0.7.0-rc1 — DATEduplicate-error quick-check line embeds the first dupe name unquoted in a heredoc — fine as-is, since heading tokens can't contain shell metacharacters that would matter there.Round summary — converged, handing off
What shipped (
a0bea57, 3 commits): the monotonic changelog guard ported from box with cast#133's port notes folded in.actions/changelog-monotonic/changelog-monotonic.sh— uniqueness of## X.Y.Zheadings on HEAD first, then merge-base containment (base's shipped-heading set must be a subset of HEAD's);## Unreleasedexcluded by version shape; STRICT defaults0in the script for local degradation. Header carries box#122/box#118, the three-reasons-for-a-separate-file essay, and both extractor shapes' history — with the duplicate-heading lore adapted to tell the truth for this repo'sif (found) exitextractor (truncation, not absorption).actions/changelog-monotonic/action.yml— composite wrapper, inputsbase-ref/changelog/strict(default"1"in CI),fetch-depth: 0requirement documented along with what its absence looks like.test/changelog-monotonic.test.sh— 20 cases over constructed git repos, covering the issue's full test list plus the box#143 ordering edges: the duplicate fails before history is consulted, even with an unresolvable base ref, even with STRICT=1 on that ref, even outside a git repo..github/workflows/ci.yml—action-exerciserunsuses: ./actions/changelog-monotonicagainst a real two-commit fixture history (base branch → insert-above edit) with an explicitbase-ref, so green is a genuine containment run, not anaction.ymlparse.Rounds: one. The panel (grok, codex, kimi) reviewed the first ready head
a0bea57; all three approved it with no changes requested, so the head never moved during review.Verified: CI green at
a0bea57(test+action-exercise); local full suite 7/7 files (monotonic 20/20); shellcheck and actionlint sweeps clean. All three approvals are of the current head;mergeStateStatusCLEAN, noblocker:*.Post-merge residue:
CHANGELOG.mdentry — the file doesn't exist on main yet; #11 owns its bootstrap and backfills pre-#11 entries (family precedent: #28/#29/#31/#33/#39). This PR's line lands in that backfill.CHANGELOG.mdbelongs to that later work, not here.Requesting @danmt's review and setting
state:needs-human— the PR is yours.