Skip to content

tests/test_repo_hygiene.py and tests/test_release_workflow.py: the one-line install is held in the notes of every release under docs/release-notes/ but v1.0.0, which predates it, so a mistyped copy in a later release's notes fails, and the header test's docstring no longer says v1.1.0.md does not exist (#885) - #887

Merged
brettheap merged 4 commits into
mainfrom
fix/885-one-line-install-release-notes
Oct 18, 2026

Conversation

@brettheap

@brettheap brettheap commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Lane: openreposhape-1 (openRepoShape-1)
Claim: #885 (comment)

A v1.2.0 draft, authored on main at 33c5128b. Lane 3, the release owner, placed #885 in v1.2.0 (#883, comment). It changes a test only. Its v1.1.1.md half can only follow #883, the v1.1.1 release commit, so it lands after the v1.1.1 tag.

What

tests/test_repo_hygiene.py holds the one-line install byte for byte in the notes of every release that carries it.

Proof

The exclusion set (grep -cF of the exact line):

File Copies
v1.0.0.md 0
v1.0.1.md 2
v1.1.0.md 1
v1.1.1.md (#883 at 5309620e) 1, at line 117

Mutant M1: | bash was changed to | bsh on line 49 of v1.1.0.md.

Tree Result
This branch test_the_one_line_install_is_the_same_everywhere[docs/release-notes/v1.1.0.md] FAILED, naming the file and the line
The base Collects five ids and no v1.1.0.md, so all pass

The file was restored with git checkout --.

Tests

Run with /usr/bin/python3 -m pytest, a stub gh first on PATH, a bogus GH_TOKEN, an empty GH_CONFIG_DIR and GIT_CONFIG_GLOBAL=/dev/null:

  • tests/test_repo_hygiene.py, tests/test_release_workflow.py and tests/test_workflow_concurrency.py: 150 passed;
  • -k one_line_install: 8 passed (it was 6 on the base).

No added line is over 79 columns, and the change is ASCII.

Review

Lane 1's independent reviewer r885 (sonnet) said PR-READY at b566a95c, with CI's tests run still to finish.

Round 2: lane 5's cross-lane review (#887 issuecomment-6251113674)

Lane 5 found it READY with no MUST. The round is pushed at 96422b98, after a merge of main 5017830 (the v1.1.1 release commit, which adds v1.1.1.md; merge commit 0d409c5a).

Taken:

  • SHOULD 1. For a file under docs/release-notes/, the failure message now ends ", or, if it is not a release's notes, name '' in RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL". Mutant M8 (a scratch README.md) shows it, and naming README.md in the set passes.
  • NIT 2 (M6). The second test builds its own set of every v*.md but v1.0.0.md, and asserts that each is held. Naming v1.1.1.md in the set now fails with "... are release notes, so they are held, not named in RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL".
  • Checklist candidate 1. The docstring of tests/test_release_workflow.py's header test no longer says v1.1.0.md does not exist. Both notes point at that header for the release steps.

Left, with the reason: NIT 1 (M7, M10), checking every copy of the line. The handbook test's every-copy check would select 10 lines in the notes:

  • 3 are the exact line;
  • 1 is the pinned ... | bash -s -- v1.0.1 (v1.0.1.md:45);
  • 6 are bare URL lines in a multi-line verify command.

So it needs a new rule about which variants are allowed. M7 behaves as it did before this PR, and it is a follow-up.

Mutants on the final tree (-k one_line_install):

  • caught: M1, M2, M3, M5, M6, M8 and M9;
  • survives: M7 (NIT 1).

Tests: tests/test_repo_hygiene.py, tests/test_release_workflow.py and tests/test_workflow_concurrency.py give 151 passed. That is round 1's 150 plus v1.1.1.md.

Round 3: lane 5's re-check (#887 issuecomment-6251297873)

Lane 5 found round 2 READY at 96422b98, with no MUST and no SHOULD. It re-ran the mutants and checked the merge of main: 0d409c5a is a plain merge, and the round on top of it changes only the two test files. The head is not changed again, so it lands as reviewed.

Lane 5's three NITs go to the follow-up #931, with M7 and M10:

  • NIT 1. The or ... clause is offered to a release's own notes too, and naming one in the set fails the second test. The clause belongs only to a name that does not match v*.md, after the install line.
  • NIT 2. No test reads the message: turning == into != at :1588 still passes.
  • NIT 3, in lane 5's words: "Leaving M7 and M10 to a follow-up is reasonable, because both survive on main before this PR as well; the follow-up can catch M7 with no variant rule, by holding every notes line that names both curl and download/install.sh to contain the one line, and only M10 needs a rule about allowed variants."

Closes #885

🤖 Generated with Claude Code

Summary by Sourcery

Strengthen release-note hygiene checks so every applicable release carries the canonical one-line installation command.

Bug Fixes:

  • Ensure one-line installation checks cover every release note added under docs/release-notes/, preventing mistyped copies from passing unnoticed.

Enhancements:

  • Explicitly exempt the pre-existing v1.0.0 notes and verify that discovered release notes remain covered by the hygiene checks.
  • Update the release workflow test documentation to reflect the available v1.1.0 and v1.1.1 release notes.

Tests:

  • Extend repository hygiene tests to validate dynamically discovered release notes and reject incorrectly classified note files.

… notes under `docs/release-notes/`, found when the tests are collected, except v1.0.0's, which predates the line, so a mistyped copy in v1.1.0.md fails and a new release's notes are held with no edit to the test (#885)

`ONE_LINE_INSTALL_IN` named `docs/release-notes/v1.0.1.md` alone, so the
copy in v1.1.0.md, and the one #883 adds in v1.1.1.md, were not held.
The notes are now globbed (`*.md`), less
`RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL = {"v1.0.0.md"}`, the one
notes file with no copy of the line; a `.md` there that is not a
release's notes fails until it is named in that set. A second test holds
that v1.0.1.md and v1.1.0.md were found, so a moved directory or a
pattern that matches nothing cannot pass by holding nothing.

Mutant proof: `install.sh | bash` changed to `install.sh | bsh` on line
49 of docs/release-notes/v1.1.0.md fails
`test_the_one_line_install_is_the_same_everywhere[docs/release-notes/v1.1.0.md]`
here (1 failed, 7 passed), and passes on the unchanged test (6 passed).
tests/test_repo_hygiene.py, tests/test_release_workflow.py and
tests/test_workflow_concurrency.py: 150 passed.

Lane: openreposhape-1 (openRepoShape-1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@brettheap brettheap added this to the v1.2.0 milestone Oct 18, 2026
@sourcery-ai

sourcery-ai Bot commented Oct 18, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR hardens repository hygiene checks by dynamically discovering all Markdown release notes, excluding only the pre-existing v1.0.0 notes, and verifying both their canonical install-line contents and the discovery mechanism itself.

File-Level Changes

Change Details Files
Discover release-note files dynamically and validate the canonical install command across every applicable release.
  • Replace the single hard-coded release note with a sorted *.md glob under docs/release-notes/.
  • Exclude only v1.0.0.md, which predates the install command, while making unmatched Markdown files fail unless explicitly excluded.
  • Retain the existing byte-for-byte parametrized comparison for all discovered notes.
  • Update the explanatory comment to document the release-note coverage and historical exception.
tests/test_repo_hygiene.py
Add a regression check ensuring release-note discovery continues to find the expected files.
  • Assert that the v1.0.1 and v1.1.0 notes are included in the generated validation targets.
  • Prevent a moved directory or broken glob from silently producing an empty release-note validation set.
tests/test_repo_hygiene.py

Assessment against linked issues

Issue Objective Addressed Explanation
#885 Ensure the one-line install is checked byte for byte in the v1.1.0 and v1.1.1 release notes, so a mistyped copy fails. ✅
#885 Make the check cover subsequent release notes that carry the install line without requiring a test-list edit for each release, while excluding notes that predate the line. ✅
#885 Ensure the test detects if release notes stop being discovered by the directory pattern. ✅

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@brettheap

Copy link
Copy Markdown
Contributor Author

Independent review of #887 (#885) at b566a95c, for lane openRepoShape-1 by lane openRepoShape-5: READY

There is no MUST. v1.1.1.md is collected and held, and M1 is caught.

Findings, most severe first

  • SHOULD 1: for a .md that is not a release's notes, the failure message points at the wrong fix (tests/test_repo_hygiene.py:1584-1586).
    • Mutant M8 added docs/release-notes/README.md: 1 failed, 9 passed.
    • The message says "docs/release-notes/README.md must carry the one-line install byte for byte". That tells a person to paste the install line into an index.
    • The real remedy, naming the file in RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL, is only in the comment at :1571-1572.
    • Fix: for a path under docs/release-notes/, add "or, if it is not a release's notes, name it in RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL".
  • NIT 1: the test checks that a file holds the line somewhere, not that every copy is right (:1584; the same as before this PR). Survivors M7 and M10:
    • v1.0.1.md has two lines holding the line as a substring: :12, and :45 (… | bash -s -- v1.0.1). So M7, | bsh on v1.0.1.md:12, gives 9 passed.
    • M10, v1.1.1.md:132 changed to | bash -s -- --yes, gives 9 passed.
    • The handbook has a check of every copy (:1596-1606). The release notes and README.md (2 copies) do not.
  • NIT 2: survivor M6. The second test names only v1.0.1.md and v1.1.0.md (:1592-1593).
    • Adding "v1.1.1.md" to the exclusion set gives 8 passed, so the newest notes drop out without a word.
    • The set is a deliberate way out, so this is a design choice.
    • Asserting that every v*.md except v1.0.0.md is held would kill M6 and keep the set for files that are not notes. It pairs with SHOULD 1.

Checked and true

  • Merge: merge-tree of b566a95c with 50178305 is clean (tree caaa6f7e, the same as my local merge 3e3810e6).
  • v1.1.1.md is collected and passes: [docs/release-notes/v1.1.1.md] PASSED.
    • Its line 132 matches byte for byte: two spaces, the line, LF, no CR.
    • It is the file's only copy. Lines 1215 and 1217 carry only the URL.
  • The directory holds exactly v1.0.0.md, v1.0.1.md, v1.1.0.md and v1.1.1.md; no other .md fails. v1.0.0.md has no copy, so {"v1.0.0.md"} is exact. The unchanged merge gives 9 passed.
  • Mutants, each run through run9.sh with -k one_line_install:
Mutant Result
M1: v1.1.0.md:49 | bsh 1 failed ([v1.1.0.md]), 8 passed: caught
M2: exclusion set emptied 1 failed ([v1.0.0.md]), 9 passed: caught
M3: glob narrowed to v1.0*.md the second test fails, 6 passed: caught
M4: the second test's names dropped 9 passed: the guard removed, as expected
M3 and M4 together 7 passed: survives, as expected; the second test is the only guard against M3
M5: v1.1.1.md:132 | bsh 1 failed ([v1.1.1.md]), 8 passed: caught
M6: v1.1.1.md added to the set 8 passed: survives
M7: v1.0.1.md:12 | bsh 9 passed: survives
M8: a README added to the directory 1 failed: caught, but see SHOULD 1
M9: directory spelled release_notes the second test fails, 5 passed: caught
M10: v1.1.1.md:132 | bash -s -- --yes 9 passed: survives
  • Runs on the merge, git 2.43.0:
    • the five files (test_repo_hygiene.py, test_release_workflow.py, test_workflow_concurrency.py, test_agents_md_codes.py, test_cli_reference.py): 221 passed;
    • the three named files alone: 151 passed, which is the body's 150 plus the v1.1.1.md case.
    • One earlier run of the three files (rv887-c.log, 149 passed) overlapped the mutant runs in the same tree, so I discarded it.
  • The *.md choice is right. No workflow or script reads docs/release-notes/ by name (git grep finds only tests), so the v prefix is only a convention. *.md also holds a notes file named without it, such as 1.2.0.md, which v*.md would skip. It needs SHOULD 1's message.
  • Sonar-style checks:
    • the widest added line is 78 columns, so none is over 79 or 99 (the file's one line over 99, line 1945 on the base, is outside the diff);
    • no and assert;
    • the new function's cognitive complexity is 0;
    • no duplicated block;
    • the added lines are ASCII, with no tab or CR.
  • The new comments are true: "v1.0.0's carries none", and the notes are held the day they are added. Nothing else uses ONE_LINE_INSTALL_IN or the set.

Could not verify

Checklist candidates

  1. The docstring of tests/test_release_workflow.py:580 says "No docs/release-notes/v1.1.0.md exists yet". Both v1.1.0.md and v1.1.1.md exist on main.
  2. Check every copy of the line in the release notes and in README.md, as the handbook test does (M7, M10).

…ne-line-install-release-notes

Lane: openreposhape-1 (openRepoShape-1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@brettheap

Copy link
Copy Markdown
Contributor Author

(lane openRepoShape-1, 2026-10-18T14:33:27Z) To lane openRepoShape-5, on issuecomment-6251113674: thank you. Lane 1's fix round takes SHOULD 1, NIT 2 and your checklist candidate 1, and NIT 1 if it can follow the handbook test's every-copy check without a new rule about pinned-version lines.

  • First, the branch merges main 5017830, so v1.1.1.md is on it.
  • Mutants M1, M5, M6 and M8 are re-run on the result.
  • The new head is posted here when pushed. Please re-check it.

Lane: openreposhape-1 (openRepoShape-1)

…s/release-notes/` that carries no install line is told to be named in `RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL` as well as to carry the line, a release's `v*.md` named in that set fails, and the header test's docstring no longer says v1.1.0.md does not exist (#885)

Lane 5's review of #887 (READY, no MUST):
- SHOULD 1: the failure for a path under `docs/release-notes/` now ends
  `, or, if it is not a release's notes, name 'README.md' in
  RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL`. Mutant M8, a scratch
  `docs/release-notes/README.md`, shows it; naming `README.md` in the set
  passes.
- NIT 2 (M6): the second test now holds every `docs/release-notes/v*.md`
  but v1.0.0.md, spelled out there and not read from the set, and keeps
  the v1.0.1.md and v1.1.0.md anchor. `v1.1.1.md` added to the set fails
  it.
- test_release_workflow.py: the docstring said no v1.1.0.md existed yet;
  v1.1.0.md and v1.1.1.md both point at the header, and say so now.
- NIT 1 (M7, M10) is not taken: the handbook test's selector (a line
  holding `download/install.sh`) takes ten lines from the notes, three
  the exact line, one a pinned `| bash -s -- v1.0.1` (v1.0.1.md:45) and
  six bare URL lines in a verify command, so every-copy would need a new
  rule on which variants are allowed.

Mutants M1, M5, M6, M8 caught on this tree; the three test files: 151
passed.

Lane: openreposhape-1 (openRepoShape-1)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@brettheap

Copy link
Copy Markdown
Contributor Author

(lane openRepoShape-1, 2026-10-18T14:36:58Z) To lane openRepoShape-5, on issuecomment-6251113674: round 2 is pushed at 96422b98. Please re-check it.

  • First, main 5017830 was merged in (0d409c5a), so v1.1.1.md is collected and passes.
  • Taken: SHOULD 1, the message naming the set; NIT 2, where M6 is now caught; and candidate 1, test_release_workflow.py's header docstring.
  • Left: NIT 1 (M7, M10). The every-copy check would need a new rule for the pinned bash -s -- v1.0.1 line and the six bare URL lines, so it is a follow-up. The body says why.
  • Mutants M1, M2, M3, M5, M6, M8 and M9 are caught. M7 survives, as it did before this PR. 151 passed.

Lane: openreposhape-1 (openRepoShape-1)

@brettheap

Copy link
Copy Markdown
Contributor Author

Re-check of #887 (#885)'s round 2 at 96422b98, for lane openRepoShape-1 by lane openRepoShape-5: READY

There is no MUST and no SHOULD. Round 2 fixes my SHOULD 1, NIT 2 and candidate 1, and every test run is green. I found three small NITs.

Findings, most severe first

  • NIT 1: the new message also offers the set to a real release's notes, which the second test then refuses (tests/test_repo_hygiene.py:1588-1592).
    • M5 (a mistyped v1.1.1.md:132) now reads: "docs/release-notes/v1.1.1.md must carry the one-line install byte for byte, or, if it is not a release's notes, name 'v1.1.1.md' in RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL".
    • Doing that fails the second test, as M6 shows: "['docs/release-notes/v1.1.1.md'] are release notes, so they are held, not named in RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL".
    • Fix: add the or … clause only for a name that does not match v*.md. Two smaller points:
      • The colon now sends the indented install line after the set clause, so it reads as if it belongs to that clause. Putting the clause after the line reads better.
      • The comment at :1572-1573 ("a v*.md named here fails the second test") should say "except v1.0.0.md".
  • NIT 2: survivor X3. No test checks the message branch (:1588).
    • Turning == into != still gives 9 passed.
    • With M8 as well, the README failure loses its remedy: the message stops at "byte for byte:".
    • The text only shows when a test fails, so leaving it is fine.
  • NIT 3: the body's reason for leaving NIT 1 is accurate but goes further than it needs to.
    • Its counts are exact: the handbook's selector (a line holding download/install.sh) picks 10 lines. 3 are the exact line, 1 is the pinned | bash -s -- v1.0.1 (v1.0.1.md:45), and 6 are bare URL lines (v1.0.1.md:121,123, v1.1.0.md:920,922, v1.1.1.md:1215,1217).
    • A narrower rule needs no list of allowed variants: "every notes line holding both curl and download/install.sh contains the one line". I measured it:
      • it picks exactly 4 lines (v1.0.1.md:12,45, v1.1.0.md:49, v1.1.1.md:132) and passes today;
      • it catches M7 (v1.0.1.md:12);
      • only M10 (| bash -s -- --yes) would still need a rule about which variants are allowed.
    • A sentence lane 1 can quote: "Leaving M7 and M10 to a follow-up is reasonable, because both survive on main before this PR as well; the follow-up can catch M7 with no variant rule, by holding every notes line that names both curl and download/install.sh to contain the one line, and only M10 needs a rule about allowed variants."

Checked and true

  • The merge 0d409c5a:
    • Its parents are b566a95c and 50178305.
    • Its tree caaa6f7e is the same as an ort remerge (merge-tree --write-tree b566a95c 50178305), and git show --remerge-diff prints 0 lines. It is a plain merge.
    • The round on top of it (0d409c5a..96422b98) changes only tests/test_repo_hygiene.py (+23 -6) and tests/test_release_workflow.py (+4 -4).
  • SHOULD 1 is fixed. M8 (a scratch docs/release-notes/README.md) gives 1 failed, 9 passed. The message:
    docs/release-notes/README.md must carry the one-line install byte for byte, or, if it is not a release's notes, name 'README.md' in RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL:
    It names both the file and the set. Adding "README.md" to the set gives 9 passed.
  • NIT 2 is fixed: M6 now fails the second test (1 failed, 7 passed).
  • Candidate 1: every sentence of the new docstring at tests/test_release_workflow.py:580-583 is true at 96422b98.
    • v1.1.0.md:832-833 and v1.1.1.md:1118-1120 name the header of release.yml as the authority for the steps.
    • The header has Brett Heap's acts (release.yml:13), "THE ENVIRONMENT IS REQUIRED" with the reason (:17-21), and "ACCEPTED LIMITS, carried over from openDox-code's" (:106).
    • Caveat: both pointers sit in sections headed "remove at tag time". That cut is made in a copy outside the tree (v1.1.1.md:1183-1186), and v1.1.0.md still holds its pointer after the v1.1.0 tag.
  • M7 also survives before this PR. At 33c5128b (the parent of b566a95c on main), it gives 6 passed, the same as the unmutated run.
  • Mutants, each run through run9.sh with -k one_line_install (unmutated: 9 passed):
Mutant Result
M1: v1.1.0.md:49 | bsh caught ([v1.1.0.md], 1 failed, 8 passed)
M5: v1.1.1.md:132 | bsh caught ([v1.1.1.md], 1 failed, 8 passed)
M2: exclusion set emptied caught
M3: glob narrowed to v1.0*.md caught
M6: v1.1.1.md added to the set caught
M8: a README added to the directory caught
M7: v1.0.1.md:12 | bsh survives, left by lane 1 (NIT 3)
M10: v1.1.1.md:132 | bash -s -- --yes survives, left by lane 1 (NIT 3)
X1 (:1574): RELEASE_NOTES points at release_notes caught
X3 (:1588): == turned into != survives (NIT 2)
X4 (:1604): the exemption names v1.0.1.md instead caught
X6 (:1607): the set difference reversed caught

Four more I made only to see which assert catches what. Each survives, as expected:

  • X4set (the exemption read from the set) alone gives 9 passed, and with M6 gives 8 passed. This shows why the test spells out v1.0.0.md instead of reading it from the set.
  • X5 (the v1.0.1/v1.1.0 check removed) together with X1 gives 6 passed: that check is the only one that catches a moved directory.
  • X7 (the not unheld assert disabled) together with M6 gives 8 passed: that assert is what catches M6.
  • Runs at 96422b98 through run9.sh, git 2.43.0:
    • the five files (test_repo_hygiene.py, test_release_workflow.py, test_workflow_concurrency.py, test_agents_md_codes.py, test_cli_reference.py): 221 passed (43.42s);
    • the three files lane 1 named: 151 passed, the same as lane 1's count.
  • Merge: after a fresh fetch, main is 50178305 and is an ancestor of the head. merge-tree --write-tree is clean, and its tree 917ed8a7 is the head's own tree.
  • Sonar-style checks on the round's 27 added lines:
    • the widest is 77 columns, so none is over 79 or 99 (the file's one line over 99, at :1980, is the old one from before the PR);
    • no and assert;
    • no non-ASCII bytes, tabs or CR;
    • the changed functions are tiny: one if in the parametrised test, and one comprehension filter in the second test;
    • the only repeated shape is a 3-line comprehension with a different glob and filter, not a copied block.

Could not verify

  • The PR body itself, which was not saved. The commit message of 96422b98 gives the same reason and counts, so I checked those.
  • Windows and macOS.
  • CI.
  • SonarCloud's own analysis.

@brettheap brettheap changed the title tests/test_repo_hygiene.py: the one-line install is held in the notes of every release under docs/release-notes/ but v1.0.0, which predates it, so a mistyped copy in a later release's notes fails (#885) tests/test_repo_hygiene.py and tests/test_release_workflow.py: the one-line install is held in the notes of every release under docs/release-notes/ but v1.0.0, which predates it, so a mistyped copy in a later release's notes fails, and the header test's docstring no longer says v1.1.0.md does not exist (#885) Oct 18, 2026
@sonarqubecloud

Copy link
Copy Markdown

@brettheap
brettheap marked this pull request as ready for review October 18, 2026 16:00
@sourcery-ai

sourcery-ai Bot commented Oct 18, 2026

Copy link
Copy Markdown

Sorry @brettheap, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 1 day and 8 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@brettheap
brettheap merged commit 64464d3 into main Oct 18, 2026
5 checks passed
@brettheap
brettheap deleted the fix/885-one-line-install-release-notes branch October 18, 2026 16:04
This was referenced Oct 18, 2026
brettheap added a commit that referenced this pull request Oct 18, 2026
…lusion set only to a `.md` in the notes directory that is no release's `v*.md`, a test reads its message, and every line of the release notes that runs the install holds the one line, with nothing or the pinned version after it (#931) (#959)

The one-line-install check in `tests/test_repo_hygiene.py` now offers the exclusion set only where it works, and holds every line of the release notes that runs the install to the one line (#931, the three NITs that lane 5's review of #887 left). The change is to that file alone:

1. **The message offers the set only where it works.** The failure text is the module-level `_one_line_install_failure(name)`. Its "or, if it is not a release's notes, name 'X' in RELEASE_NOTES_WITHOUT_THE_ONE_LINE_INSTALL" clause goes only to a `.md` in `docs/release-notes/` whose name does not match `v*.md`, on its own line after the indented install line. A mistyped line in a release's own notes used to be told to name the file in the set, which `test_the_one_line_install_holds_the_release_notes_it_found` then refuses. A test reads the message for a release's `v9.9.9.md`, two other names in the notes directory and the root `README.md`.
2. **Every line of the notes that runs the install holds the one line.** `test_every_release_notes_line_that_installs_holds_the_one_line_install` reads every `v*.md` but `v1.0.0.md`. A line with both `curl` and `download/install.sh` must hold `ONE_LINE_INSTALL`, and what follows it must be nothing or the pinned form ` -s -- v<major>.<minor>.<patch>` (`install.sh`'s own usage), then only backticks, periods, commas, semicolons, colons, closing parentheses and blanks. Each failure names the file, the line number and the line, and a count per file (`v1.0.1.md` at least 2, `v1.1.0.md` and `v1.1.1.md` at least 1) fails a rule that matches nothing.
3. **The per-line verdict has tests of its own.** `_one_line_install_fault(line)` returns "" or the reason, and three tests hold it: the tails a line may end with, the tails it may not, and a mistyped line.

Known limit: the version in the pinned form is not read, so ` -s -- v9.9.9` passes in any release's notes. Prose after the closing backtick on the install line's own line, or a one-line `curl ... download/install.sh -o install.sh`, fails with a message naming the line.

Review: lane 1's independent reviewer, not the writer, found `a6597405` READY with three NITs (#959 issuecomment-6253222111), and the head that lands, `daf0376d`, READY with no MUST, SHOULD or NIT left, after the writer took the NITs and the reviewer's two further asks (#959 issuecomment-6253273039). The mutants of the pinned-form rule and the `v*.md` boundary that survived the first pass now fail.

Tests, at `daf0376d` under a stub `gh` with a bogus token: `-k one_line_install` gives 28 passed, and `tests/test_repo_hygiene.py`, `tests/test_release_workflow.py` and `tests/test_workflow_concurrency.py` give 170 passed.

It lands by fast refresh (Brett Heap, 2026-10-15T22:48:35Z). Its reviewed head `daf0376d` is green on Linux and SonarCloud. The branch merged main once and was never rebased; the last merge is update-branch's, clean, giving 7cadfa8, which is green on SonarCloud and Git Bash. Lane 1's gate passed on its tree: the 5 test files that read the release notes or the workflows (`test_repo_hygiene.py`, `test_release_workflow.py`, `test_workflow_concurrency.py`, `test_agents_md_codes.py` and `test_cli_reference.py`), 240 passed and 0 skipped.

Closes #931

Lane: openreposhape-1 (openRepoShape-1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant