feat: add canonical changelog section extractor #29

Merged
codex-bot-andresmgsl merged 2 commits from build/4-changelog-section into main 2026-07-22 19:12:02 +00:00
codex-bot-andresmgsl commented 2026-07-22 18:38:50 +00:00 (Migrated from github.com)

Closes #4

Summary

  • add the single sourced changelog_section implementation
  • add a fail-loud executable wrapper preserving <version> [<changelog>]
  • cover section boundaries, whole-version matching, refusal paths, the default changelog path, and a production-shaped changelog fixture

Acceptance criteria

  • One awk program in the whole repo knows what a section is; #5 and #9 can import it.
  • All specified cases pass; shellcheck-clean; mawk-compatible.
  • The header comment records the converged box/cast and rig histories at their pinned SHAs.

CHANGELOG.md is intentionally omitted per the issue clarification: #11 owns its bootstrap and will backfill pre-#11 component entries.

Verification

  • bash test/run.sh
  • bash .github/scripts/shellcheck-all.sh
  • bash .github/scripts/actionlint-all.sh
  • git diff --check
Closes #4 ## Summary - add the single sourced `changelog_section` implementation - add a fail-loud executable wrapper preserving `<version> [<changelog>]` - cover section boundaries, whole-version matching, refusal paths, the default changelog path, and a production-shaped changelog fixture ## Acceptance criteria - [x] One awk program in the whole repo knows what a section is; #5 and #9 can import it. - [x] All specified cases pass; shellcheck-clean; mawk-compatible. - [x] The header comment records the converged box/cast and rig histories at their pinned SHAs. `CHANGELOG.md` is intentionally omitted per the issue clarification: #11 owns its bootstrap and will backfill pre-#11 component entries. ## Verification - `bash test/run.sh` - `bash .github/scripts/shellcheck-all.sh` - `bash .github/scripts/actionlint-all.sh` - `git diff --check`
danmt (Migrated from github.com) reviewed 2026-07-22 18:38:50 +00:00
grok-bot-andresmgsl commented 2026-07-22 19:00:27 +00:00 (Migrated from github.com)

🔎 reviewing head 8b27cf61db

🔎 reviewing head 8b27cf61dbe22c266623704fd110e7c041540052
kimi-bot-andresmgsl commented 2026-07-22 19:00:46 +00:00 (Migrated from github.com)

🔎 reviewing head 8b27cf61db

🔎 reviewing head 8b27cf61dbe22c266623704fd110e7c041540052
grok-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-22 19:01:41 +00:00
grok-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: approve

Reviewed head 8b27cf61dbe22c266623704fd110e7c041540052 against issue #4.

Acceptance criteria

  1. One awk program knows what a section is — met. Only lib/changelog.sh implements $2 == ver section matching; bin/changelog-section is a thin fail-loud wrapper that sources it and reorders args. #5 / #9 can import the function.
  2. Specified cases pass; shellcheck-clean; mawk-compatible — met.
    • bash test/run.sh → changelog suite 16/16 (plus the other two suites on this branch, all green)
    • bash .github/scripts/shellcheck-all.sh → clean (includes the new scripts)
    • CI test check SUCCESS on this head
    • System awk is mawk 1.3.4; awk body is identical to rig's found/body shape (no gawk-isms, no \x)
  3. Header records box/cast + rig at pinned SHAs — met. Both blob URLs use the SHAs named in #4; comment states the convergence purpose.

Spec semantics (spot-checked)

Spec Result
Whole-field match (0.7.00.7.0-rc1, both directions) exact body asserts + manual edge fixture
Leading blanks dropped; mid-body blanks kept fixture asserts ### Added\n\n- …
Empty / missing section → empty from lib, exit 1 + teaching refusal from wrapper covered
CLI shape changelog-section <version> [<changelog>], default CHANGELOG.md covered (incl. cwd-default case)
usage exit 2; missing file exit 1 covered
Unreleased / preamble never leak into a version body covered by exact asserts + extra isolation probe
CHANGELOG.md omitted (pre-#11 waiver) correct; no changelog file in the PR

Implementation notes (non-blocking)

  • Awk body is a faithful port of rig's changelog_section; the wrapper preserves box/cast's CLI contract with the new binary name in messages — right split for the dual entry points #4 asked for.
  • Dropping box's local (#83) from the refusal string is appropriate here; the teaching clause about stamping Unreleased before the tag is intact.

No blockers. Ready for the rest of the panel.

## Verdict: approve Reviewed head `8b27cf61dbe22c266623704fd110e7c041540052` against issue #4. ### Acceptance criteria 1. **One awk program knows what a section is** — met. Only `lib/changelog.sh` implements `$2 == ver` section matching; `bin/changelog-section` is a thin fail-loud wrapper that sources it and reorders args. #5 / #9 can import the function. 2. **Specified cases pass; shellcheck-clean; mawk-compatible** — met. - `bash test/run.sh` → changelog suite 16/16 (plus the other two suites on this branch, all green) - `bash .github/scripts/shellcheck-all.sh` → clean (includes the new scripts) - CI `test` check SUCCESS on this head - System `awk` is mawk 1.3.4; awk body is identical to rig's found/body shape (no gawk-isms, no `\x`) 3. **Header records box/cast + rig at pinned SHAs** — met. Both blob URLs use the SHAs named in #4; comment states the convergence purpose. ### Spec semantics (spot-checked) | Spec | Result | |---|---| | Whole-field match (`0.7.0` ≠ `0.7.0-rc1`, both directions) | exact body asserts + manual edge fixture | | Leading blanks dropped; mid-body blanks kept | fixture asserts `### Added\n\n- …` | | Empty / missing section → empty from lib, exit 1 + teaching refusal from wrapper | covered | | CLI shape `changelog-section <version> [<changelog>]`, default `CHANGELOG.md` | covered (incl. cwd-default case) | | usage exit 2; missing file exit 1 | covered | | Unreleased / preamble never leak into a version body | covered by exact asserts + extra isolation probe | | `CHANGELOG.md` omitted (pre-#11 waiver) | correct; no changelog file in the PR | ### Implementation notes (non-blocking) - Awk body is a faithful port of rig's `changelog_section`; the wrapper preserves box/cast's CLI contract with the new binary name in messages — right split for the dual entry points #4 asked for. - Dropping box's local `(#83)` from the refusal string is appropriate here; the teaching clause about stamping Unreleased before the tag is intact. No blockers. Ready for the rest of the panel.
grok-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-22 19:02:21 +00:00
grok-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: Approve — I agree with this as-is.

Reviewed tip 8b27cf61dbe22c266623704fd110e7c041540052 against issue #4 (full contract after the 2026-07-22 CLI/CHANGELOG clarifications).

Why this lands

  • One awk definition in lib/changelog.sh matches rig’s found/body shape at the pinned SHA: whole-field $2 == ver (so 0.7.00.7.0-rc1), heading not printed, leading blanks dropped, empty/absent both refuse as empty output.
  • Wrapper preserves box/cast’s executable contract literally: changelog-section <version> [<changelog>], default CHANGELOG.md, usage→2, missing file→1, empty/absent section teaching refusal. Sourced API stays changelog_section <file> <version> for #5/#9.
  • Tests cover boundaries (Unreleased, adjacent sections, rc prefix pair, empty stamp, missing, date-less, default path) plus a production-shaped fixture. CI test is green.
  • CHANGELOG.md omitted correctly per #11 ownership.

No blockers. No material nits that would change the design.

**Verdict: Approve** — I agree with this as-is. Reviewed tip `8b27cf61dbe22c266623704fd110e7c041540052` against issue #4 (full contract after the 2026-07-22 CLI/CHANGELOG clarifications). ### Why this lands - **One awk definition** in `lib/changelog.sh` matches rig’s found/body shape at the pinned SHA: whole-field `$2 == ver` (so `0.7.0` ≠ `0.7.0-rc1`), heading not printed, leading blanks dropped, empty/absent both refuse as empty output. - **Wrapper** preserves box/cast’s executable contract literally: `changelog-section <version> [<changelog>]`, default `CHANGELOG.md`, usage→2, missing file→1, empty/absent section teaching refusal. Sourced API stays `changelog_section <file> <version>` for #5/#9. - **Tests** cover boundaries (Unreleased, adjacent sections, rc prefix pair, empty stamp, missing, date-less, default path) plus a production-shaped fixture. CI `test` is green. - **CHANGELOG.md omitted** correctly per #11 ownership. No blockers. No material nits that would change the design.
kimi-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-22 19:03:20 +00:00
kimi-bot-andresmgsl (Migrated from github.com) left a comment

Approve — head 8b27cf61db.

Verified, not eyeballed:

  • Spec (#4), every case: bash test/run.sh under mawk 1.3.4 — changelog suite 16/16. Whole-field match (0.7.0 vs 0.7.0-rc1, both directions), adjacent-section bleed, Unreleased isolation, em-dash and date-less headings, stamped-empty and absent-section refusal (exit 1 + teaching message), usage exit 2, missing-file exit 1, default CHANGELOG.md path, and the production-shaped fixture — all present and actually asserting failure modes, not just happy paths.
  • CLI contract vs box release-notes.sh @a17903f: usage/no-such-file/refusal exit codes and messages preserved literally, modulo the program rename and dropping box's (#83) — correct, that number means nothing in this repo. Arg reorder (CLI <version> [<file>] → function <file> <version>) is in the wrapper as specified.
  • Function vs rig release-lib.sh @7f8a0e0: the awk program is byte-for-byte rig's found/body shape — no sed pass, per the issue.
  • One awk program: grep for ^## section logic outside tests finds only lib/changelog.sh:18.
  • Header comment: both histories linked at their pinned SHAs, per acceptance criterion 3.
  • No CHANGELOG.md in the diff, per the issue's 2026-07-22 clarification (#11 owns bootstrap).
  • CI green on this head: shellcheck-all, actionlint-all, tests (ubuntu runners are mawk).

Local note: test/labels-reconcile.test.sh fails on my box with jq: command not found — missing local tool, unrelated to this diff; CI is green.

Non-blocking nit: the wrapper's no-args check only validates $1, same as box's original — fine as contract preservation, just noting it stays deliberately lenient about extra args.

**Approve** — head 8b27cf61dbe22c266623704fd110e7c041540052. Verified, not eyeballed: - **Spec (#4), every case**: `bash test/run.sh` under mawk 1.3.4 — changelog suite 16/16. Whole-field match (`0.7.0` vs `0.7.0-rc1`, both directions), adjacent-section bleed, Unreleased isolation, em-dash and date-less headings, stamped-empty and absent-section refusal (exit 1 + teaching message), usage exit 2, missing-file exit 1, default `CHANGELOG.md` path, and the production-shaped fixture — all present and actually asserting failure modes, not just happy paths. - **CLI contract vs box `release-notes.sh` @a17903f**: usage/no-such-file/refusal exit codes and messages preserved literally, modulo the program rename and dropping box's `(#83)` — correct, that number means nothing in this repo. Arg reorder (CLI `<version> [<file>]` → function `<file> <version>`) is in the wrapper as specified. - **Function vs rig `release-lib.sh` @7f8a0e0**: the awk program is byte-for-byte rig's found/body shape — no `sed` pass, per the issue. - **One awk program**: grep for `^## ` section logic outside tests finds only `lib/changelog.sh:18`. - **Header comment**: both histories linked at their pinned SHAs, per acceptance criterion 3. - **No `CHANGELOG.md`** in the diff, per the issue's 2026-07-22 clarification (#11 owns bootstrap). - **CI green** on this head: shellcheck-all, actionlint-all, tests (ubuntu runners are mawk). Local note: `test/labels-reconcile.test.sh` fails on my box with `jq: command not found` — missing local tool, unrelated to this diff; CI is green. Non-blocking nit: the wrapper's no-args check only validates `$1`, same as box's original — fine as contract preservation, just noting it stays deliberately lenient about extra args.
claude-bot-andresmgsl commented 2026-07-22 19:05:34 +00:00 (Migrated from github.com)

🔎 reviewing head 8b27cf61db

🔎 reviewing head 8b27cf61dbe22c266623704fd110e7c041540052
claude-bot-andresmgsl (Migrated from github.com) approved these changes 2026-07-22 19:07:08 +00:00
claude-bot-andresmgsl (Migrated from github.com) left a comment

Verdict: approve — head 8b27cf61dbe22c266623704fd110e7c041540052, reviewed against issue #4's full contract (including the 2026-07-22 CLI-shape and CHANGELOG clarifications).

I verified rather than eyeballed — independently of the other two reviews:

Against the pinned sources (fetched both at their SHAs):

  • lib/changelog.sh's awk program is byte-identical to rig's release-lib.sh found/body shape at 7f8a0e0 — early exit at the next heading, leading blanks dropped in awk (no sed pass), $2 == ver whole-field string compare.
  • bin/changelog-section preserves box's release-notes.sh executable contract at a17903f literally: <version> [<changelog>] arg order, CHANGELOG.md default, usage → exit 2, no-such-file → exit 1, and the teaching refusal message intact. The only deltas are the program rename in messages and dropping box's local (#83) — both correct for this repo. The wrapper reorders args into changelog_section <file> <version>, so #5/#9 import the explicit-file signature as specified.

Ran, on this checkout (mawk 1.3.4, same flavor as CI runners):

  • bash test/run.sh — changelog suite 16/16 (all three suites green: 96 checks total).
  • shellcheck-all.sh, actionlint-all.sh, git diff --check — all clean.
  • Extra probes beyond the suite, all behaving correctly: reverse prefix direction (0.7.0-rc1 requested when only 0.7.0 exists → refusal), trailing-space heading (## 0.7.0 still parses, $2 unaffected), last-section-at-EOF (body prints, no next-heading needed).
  • One awk program: a repo-wide grep for section-matching logic (/^## / + $2 ==) outside tests hits only lib/changelog.sh:18.

Acceptance criteria: (1) single implementation, importable by #5/#9 — met; (2) all specified cases pass in CI (CI test is SUCCESS on this head), shellcheck-clean, mawk-compatible — met; (3) header comment links both histories at their pinned SHAs and states the convergence — met. CHANGELOG.md correctly absent per the #11 waiver. Conventions hold: set -euo pipefail in the executable, set -u in the test file, comments carry the why.

No blockers, no nits worth the builder's time. With this, all three panel verdicts approve the current head.

**Verdict: approve** — head `8b27cf61dbe22c266623704fd110e7c041540052`, reviewed against issue #4's full contract (including the 2026-07-22 CLI-shape and CHANGELOG clarifications). I verified rather than eyeballed — independently of the other two reviews: **Against the pinned sources** (fetched both at their SHAs): - `lib/changelog.sh`'s awk program is **byte-identical** to rig's `release-lib.sh` found/body shape at `7f8a0e0` — early exit at the next heading, leading blanks dropped in awk (no `sed` pass), `$2 == ver` whole-field string compare. - `bin/changelog-section` preserves box's `release-notes.sh` executable contract at `a17903f` literally: `<version> [<changelog>]` arg order, `CHANGELOG.md` default, usage → exit 2, no-such-file → exit 1, and the teaching refusal message intact. The only deltas are the program rename in messages and dropping box's local `(#83)` — both correct for this repo. The wrapper reorders args into `changelog_section <file> <version>`, so #5/#9 import the explicit-file signature as specified. **Ran, on this checkout (mawk 1.3.4, same flavor as CI runners):** - `bash test/run.sh` — changelog suite 16/16 (all three suites green: 96 checks total). - `shellcheck-all.sh`, `actionlint-all.sh`, `git diff --check` — all clean. - Extra probes beyond the suite, all behaving correctly: reverse prefix direction (`0.7.0-rc1` requested when only `0.7.0` exists → refusal), trailing-space heading (`## 0.7.0 ` still parses, `$2` unaffected), last-section-at-EOF (body prints, no next-heading needed). - **One awk program**: a repo-wide grep for section-matching logic (`/^## /` + `$2 ==`) outside tests hits only `lib/changelog.sh:18`. **Acceptance criteria**: (1) single implementation, importable by #5/#9 — met; (2) all specified cases pass in CI (CI `test` is SUCCESS on this head), shellcheck-clean, mawk-compatible — met; (3) header comment links both histories at their pinned SHAs and states the convergence — met. `CHANGELOG.md` correctly absent per the #11 waiver. Conventions hold: `set -euo pipefail` in the executable, `set -u` in the test file, comments carry the why. No blockers, no nits worth the builder's time. With this, all three panel verdicts approve the current head.
codex-bot-andresmgsl commented 2026-07-22 19:10:44 +00:00 (Migrated from github.com)

Review round summary

All three eligible bench reviewers approved current head 8b27cf61dbe22c266623704fd110e7c041540052; no changes were requested in this round.

Verified across the round:

  • issue #4 acceptance criteria and clarified CLI/CHANGELOG contracts are met
  • the canonical awk implementation matches the pinned rig history and the wrapper preserves the pinned box/cast CLI behavior
  • whole-version and section-boundary behavior, refusal paths, default path, and production-shaped fixture are covered
  • bash test/run.sh, shellcheck, actionlint, and CI pass under mawk-compatible behavior
  • the PR is mergeable and carries no blocker labels

Handing off to the human for the merge decision.

## Review round summary All three eligible bench reviewers approved current head `8b27cf61dbe22c266623704fd110e7c041540052`; no changes were requested in this round. Verified across the round: - issue #4 acceptance criteria and clarified CLI/CHANGELOG contracts are met - the canonical awk implementation matches the pinned rig history and the wrapper preserves the pinned box/cast CLI behavior - whole-version and section-boundary behavior, refusal paths, default path, and production-shaped fixture are covered - `bash test/run.sh`, shellcheck, actionlint, and CI pass under mawk-compatible behavior - the PR is mergeable and carries no blocker labels Handing off to the human for the merge decision.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/ceremony#29
No description provided.