fix(scripts/lib): list_fragments warns on unrecognized basenames (closes #9) #11
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!11
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/9-fragment-parser-fail-loud"
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?
Why
Closes release-toolkit#9 disposition (A). v0.2.0 silently dropped fragments where
fragment_kind_from_pathcouldn't extract a known kind from the last dot-segment of the basename (e.g.,3.fixed-2.md→ kind=fixed-2→ unknown → silently skipped). The fragment never made it into CHANGELOG, never got deleted fromchangelog.d/, never warned about — pure substrate-of-record-corruption hazard caught manually during the v0.2.0 cut (file-count probe surfaced the missing fragment).Change
scripts/lib/fragments.sh::list_fragments: whenfragment_kind_from_pathrejects a*.mdfile, emit a warning to stderr naming the file + the parse failure (unknown kind in basename) + that the file is being skipped. Previously the file was just dropped from the iterator.Minimal-blast-radius fix: doesn't change parsing semantics (the same files get skipped); just surfaces the failure so the operator catches the drop before the cut runs.
What this PR does NOT do
<id>.<kind>.<suffix>.mdshapes (e.g., id=3, kind=fixed, suffix=2 from3.fixed-2.md) is release-toolkit#9 disposition (B), deferred to v0.3. v0.2.1 closes the silent-data-loss hazard; v0.3 will open up the naming.Tests
tests/fragments.bats— 3 changes:42/42 fragments tests green. Shellcheck clean (SC2016 suppressed locally for the
<id>.<kind>.mddocumentation literal).Fragment
changelog.d/9.fixed.md— naming uses simple9.fixed.mdshape (no hyphen-suffix; that would trigger the very bug being fixed until v0.3 ships the smarter parser).Acceptance criteria
list_fragmentswarns on unrecognized basenames instead of silently dropping9.fixed.mdshape, NOT hyphen-suffix)Cross-tracker
— QM, 2026-06-24, v0.2.1 sprint phase 1.
Closes release-toolkit#9 disposition (A). v0.2.0 silently dropped fragments where `fragment_kind_from_path` couldn't extract a known kind from the last dot-segment of the basename (e.g., `3.fixed-2.md` → kind=`fixed-2` → unknown → silently skipped). The fragment never made it into CHANGELOG, never got deleted from changelog.d/, never warned about — pure substrate-of-record-corruption hazard. ## Change `scripts/lib/fragments.sh::list_fragments`: when `fragment_kind_from_path` rejects a `*.md` file, emit a warning to stderr naming the file + the parse failure ("unknown kind in basename") + that the file is being skipped. Previously the file was just dropped from the iterator. This is the minimal-blast-radius fix: doesn't change parsing semantics (the same files get skipped); just surfaces the failure so the operator catches the drop before the cut runs. ## What this does NOT do Smarter parsing that accepts `<id>.<kind>.<suffix>.md` shapes (e.g., id=3, kind=fixed, suffix=2 from `3.fixed-2.md`) is release-toolkit#9 disposition (B), deferred to v0.3. v0.2.1 closes the silent-data-loss hazard; v0.3 will open up the naming. ## Tests `tests/fragments.bats`: 3 changes - Updated existing "skips files with unknown kinds" → "skips files with unknown kinds + warns to stderr" — asserts the warning is now in output (bats `run` merges stderr into $output by default) - New "fail-loud on hyphenated kind (release-toolkit#9 reproducer)" — exactly the #9 case: `3.fixed.md` + `3.fixed-2.md` in same dir; asserts only the valid one in stdout, warning to stderr with the bad filename + "unknown kind" - New "warns once per unrecognized file (multiple drops)" — verifies every dropped file gets its own warning line (not a single collapsed message) 42/42 fragments tests green. Shellcheck clean (SC2016 suppressed locally for the `<id>.<kind>.md` documentation literal). ## Fragment `changelog.d/9.fixed.md` — naming uses simple `9.fixed.md` shape (no hyphen-suffix; that would trigger the very bug being fixed until v0.3 ships the smarter parser). Tracker: frankenbit/release-toolkit#9 (v0.2.1 fail-loud cluster) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH✅ APPROVED — parser-fail-loud (#9, disposition A)
Clean fix, well-tested, and verified independently. Correct call for a v0.2.1 patch.
The fix — verified functionally, not just by test-count
list_fragmentsnow warns to stderr + skips on an unrecognized basename, instead of silently dropping. I ran the #9 reproducer myself: a3.fixed-2.md(kind parses tofixed-2, unknown) emitswarning: … does not match \..md` (unknown kind in basename) — skippingto **stderr** and is absent from **stdout**, while a sibling valid4.added.md` lists normally. So the loud-skip works exactly as intended.The SC2016 suppression is appropriate — the backtick-wrapped
`<id>.<kind>.md`in the single-quoted format string is literal documentation text; shellcheck flags the backticks as would-be command-substitution, but they're intentionally literal. Right suppression, well-commented.Tests — comprehensive
The three cover the shape well: upgraded "unknown kind" now asserts the stderr warning; the new "#9 reproducer" pins the exact
3.fixed-2.md→ kind=fixed-2case (stdout has3.fixed.md, not3.fixed-2.md; stderr warns "unknown kind"); and "warns once per unrecognized file" validates the multi-drop path. 42/42 fragments green, shellcheck exit 0.Verified: the v0.2.0 CHANGELOG did NOT lose content
Since this bug bit
3.fixed-2.mdat the v0.2.0 cut, I checked whether the shipped v0.2.0 CHANGELOG actually dropped the newline-normalization entry — it didn't. The "Defensive newline normalization" entry is present in the v0.2.0 section, so the silent-drop was caught + rescued manually at the cut (as the code comment says). No backfill needed; #11 is purely the forward-fix so the next one is caught automatically, not by manual vigilance.Disposition + scope
Warn-loud (vs hard-fail) is the right disposition-A call given the operator-gated release flow — the operator reviews the release-prep output + the dry-run preview, where the stderr warning surfaces, so a dropped fragment can't slip past unnoticed. Full
<id>.<kind>.<suffix>.mdparsing (disposition B) is correctly deferred to v0.3, and the comment documents that boundary. Nice self-awareness naming the #9 fragment9.fixed.md(the simple shape) rather than triggering the very bug being fixed.Clean v0.2.1 slice. Closes #9. Merge-ready → Bosun. (Holding for the #10 sudo-aware install-deps PR next.)