Conversation
… grammar and it had drifted (#375) `tests/test_claude_md_currency.py` counted pending fragments with `\A\d+\.[a-z]+\.md\Z`, written before the grammar grew its optional `<slug>` segment in #308. A cycle whose pending fragments were all slug-form therefore parsed as an empty directory, and the guard skipped with "no unfolded changelog fragments, so no release is being prepared" -- an absence produced by the parser rather than by the directory, which is this repository own defect class pointed at its own instrumentation. The fix is one spelling fewer, not one more: `FRAGMENT` is now `assemble_changelog._NAME_RE`, taken from the module that owns the grammar. The name grammar and not `parse_fragment_name`, which also refuses a section outside the six -- `1.bogus.md` is a file somebody filed as a fragment and the assembler will refuse the release over it, so counting it as absent here would be the same defect one layer down. The two CI gates were re-derived rather than trusted from the issue and are correct: the pattern in `.github/workflows/changelog.yml:96` and the same shape in the workflow `scripts/scaffold.py:799` writes both accept the slug form and both refuse `README.md`. Neither can import; this one could. The test drives the guard rather than the pattern -- an all-slug fixture must make it run, because asserting only that the regex matches a slug name would pass against a version that still skipped. Paired with an empty directory and a README-only directory, both of which must still skip. `pytest.skip.Exception` is pinned rather than caught as `Exception`: `Skipped` derives from `BaseException`, so the enclosing test would have skipped instead of failing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015HuQoqn4iLmW2ULpvhKnwj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #375.
What was wrong
tests/test_claude_md_currency.pycounts unfolded changelog fragments to decide whether a release is being prepared, and it counted them with its own copy of the fragment name grammar:That copy predates the optional
<slug>segment the grammar grew in #308. A cycle whose pending fragments were all slug-form therefore parsed as an empty directory, and the guard skipped with "no unfolded changelog fragments, so no release is being prepared" -- an absence produced by the parser rather than by the directory, which is this repository's own defect class pointed at its own instrumentation. Harmless so far only because every cycle to date has carried two-segment fragments alongside.The judgment call: derive, do not add a fourth copy
The issue asks for one spelling fewer rather than one more, so
FRAGMENTis nowassemble_changelog._NAME_RE-- taken from the module that owns the grammar and that a fragment must already satisfy to reachCHANGELOG.md. There is precedent for exactly this intests/test_docs_state_slug_grammar_308.py, which reads the grammar out of the assembler at runtime for the same stated reason, so no new module was invented to hold a regex.The name grammar and not the public
parse_fragment_name, which additionally refuses a section outside the six:1.bogus.mdis a file somebody filed as a fragment and the assembler will refuse the release over it, so counting it as absent here would be the same defect one layer down.The two CI gates were re-derived, not taken on trust
The issue asserts both are already correct. Checked rather than believed, by running their patterns against this range's own fragments:
308.fixed.slug-form-documented.md228.fixed.mdREADME.md.github/workflows/changelog.yml:96scripts/scaffold.py:799writesBoth correct. Both are shell and cannot import; this one could, which is why it is the copy that was removed rather than repaired.
A sweep of
scripts/for the two character classes the grammar is built from finds the remaining spellings:assemble_changelog._NAME_RE(the owner) andrelease_version.FRAGMENT_NAME(a transcription). The transcription is not an unguarded fourth copy --tests/test_release_version_fragment_names_297.py::test_the_version_rule_and_the_assembler_agree_on_which_names_are_fragmentsmeasures the two against each other behaviourally. No finding there.The test drives the guard, not the pattern
Asserting only that the regex matches a slug name would pass against a version that still skipped, so the new test points
_fragment_dirat an all-slug fixture and reads which arm the guard took. Paired with an empty directory and a README-only directory, both of which must still skip -- without that control the first test would pass against a guard that never skips at all.pytest.skip.Exceptionis pinned rather than caught asException:Skippedderives fromBaseException, soexcept Exceptionandpytest.raises(Exception)both sail past it and skip the enclosing test -- a green tick over an assertion that never ran.Evidence
Red, before the fix:
The empty-directory control passed at that point too, so the red was the finding and not the harness.
Green, after:
15 passed in 0.06sfor the file, and2611 passed, 2 skipped in 247.91sfor the full suite (python3 -m pytest tests/ -q, coverage 91.69% against an 85% floor). Both pre-existing skips are unrelated and name their own reasons.Platform
Observed on macOS/darwin, Python 3.13 locally. Reasoned for the other twelve legs: the diff adds no path-separator or suffix logic, builds every path through
pathlib, pinsencoding="utf-8"on every write, prints nothing, adds no platform branch and no narrowexcepton a platform-specific type, and introduces no non-ASCII into the test source.pytest.skip.Exceptionis a pytest fact, not a platform one.Verified by the maintainer
The red re-run does not have its usual shape here and that is worth recording rather than leaving
absent: the defect and its test are the same file, so checking the branch's test file out onto
mainbrings the fix with it and the run comes back green. Reconstructed instead — branch test fileon
origin/mainin a detached worktree, thenFRAGMENTalone reverted to the pre-fix pattern:The empty-directory and README-only controls passed in that same run, so the red is the defect and
not a broken harness. That is the whole of my independent check; everything else above is the
author's and stands on its own evidence.