Repository navigation
Retire the block rule format (#761) - #786
Merged
Merged
Conversation
Every rule in docs/design/rules/ is in the skeleton format, so the block format's parser, measures, checks, tests and docs go. A rule written in the old format is now refused rather than skipped. Also fixes the four parser minors #768's review deferred: an assertion in a backtick span, a #-led bullet continuation, a second When or Tolerated paragraph, and the S10 comment naming an Except bullet by description. The README's Signal tag list now names every tag, held by a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refuse a block-format rule line inside a field too, and a nested list in any marker under a bullet, so the docs' refusal lists hold; qualify the README's refusal list for backtick spans; complete the guard list in docs/design/AGENTS.md; and fix three descriptions of deleted behavior (parse_example_line, axis 12, test_corpora's floor). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #786 +/- ##
=======================================
Coverage 99.05% 99.05%
=======================================
Files 47 47
Lines 4642 4642
=======================================
Hits 4598 4598
Misses 44 44 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Refuse text outside any rule other than a section heading and its one Background paragraph, and a numbered list at the start of a line, both of which were read as nothing or as prose; delete Rule.tolerated, which nothing read; give the bullet-lead and signal-tag checks synthetic rows that can fail; ratchet test_corpora's rule floor to 70; and correct the comments and docs the review found stale. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refuse structure glued to a Background paragraph (a fence, heading, field label, list item or example; a quote-led wrapped line stays prose), a section heading with no Background and a section letter headed twice; make prose_blocks end a Background at a section heading as parse_rules_doc does; refuse a bare numbered item ending a line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Background check's own arrow pattern ran only on wrapped lines and ignored backtick spans; ask rules_skeleton.holds_assertion, the rule side's predicate less its quote-lead half, of every Background line, the first included. A list item interrupts a Background only numbered 1, as in CommonMark. The docs state the glued check's column-0 scope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
derek73
added a commit
that referenced
this pull request
Oct 21, 2026
…retired-ID guard (#761 follow-up) (#788) * Quote the bullet a citation comment names (#761 follow-up) Fourteen comments named a rule's Except or Accepted bullet by description and quoted nothing, so test_doc_citations could not check them. Each now quotes the bullet (an Except bullet by its whole bold lead, which bullet_lead_findings holds it to) beside its rule ID, says which clause the code implements or pins, and points at the decisions entry. Two named the wrong bullet: test_parser.py's 'M2 Accepted row' is M2's Except bullet on post-comma text, and test_pieces.py's 'no-comma peel's Accepted limit' is S7's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add the Except-fence check to the design review's axis 3 (#761 follow-up) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Refuse a rule file that reuses a retired rule's ID (#761 follow-up) PR #786 replaced the tombstone with 'A retired rule's decisions entry records the retirement', which left 'never reused' unenforced. A retired rule's decisions file now carries a line opening 'Retired:', and test_no_rule_reuses_a_retired_id refuses a rule file with that ID. The reader lives in tests/v2/design_docs.py. A misspelled Retired line and one in a file keyed by no rule ID are findings too, since either would switch the refusal off silently. No rule is retired yet, so the real-tree test refuses nothing; test_a_rule_file_reusing_a_retired_id_is_refused builds a synthetic decisions file and a rule file reusing its ID and is the negative control (it fails with the ID check disabled, measured). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address the design-docs review (#761 follow-up) - test_properties: drop the two maiden-clause pairs said to differ; measured, both spellings of each read alike since #601, and M2's bullet the new citation quoted accepts no such split. - _extract: the M3 contrast is a suffix word ('née PhD'), not V, which M2 also reads as the maiden name. - Retired: a numbered '1. Retired:' line is a misspelling too (the new row failed against the old pattern first). - docs/design/AGENTS.md axis 3: two incidents on the record (H1 in #779, S3's Msc.Ed. row in #783), not three; a row Then decides may belong under Accepted. The skip list names the new guard. - cases.py: shape 7's U+00B7 half is what the W4 Except decides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Every rule in
docs/design/rules/is now in the skeleton format (PRs #768, #770, #772, #777, #779, #781, #782 and #783). This PR removes the old indentation-based block format: its parser, its measures and checks, and its tests and docs. It also fixes the four parser minors that PR #768's review left for this PR.Closes #761
No rule text, no example and no reading moves. I dumped
parse_rules_docandprose_blocksover the real rules on master and on this branch and compared them. The parsed rules (every field, example and pointer) are byte-identical. The only difference in the quotable text is the droppedAccepted:prefix described below. The budget record is unchanged and holds skeleton rows only; nothing touches the corpus or the snapshot.Removed
tests/v2/rules_doc.py: the block branch ofparse_rules_docandprose_blocks, theinteracts:handling andRule.interacts, the near-miss checks for the block'stolerated:,Signal:andAcceptedlines, the per-file dispatch, and the docstring's account of the old grammar. Every# ID — nameheading now goes straight toparse_skeleton, sorules_skeleton.is_skeleton_blockand its near-miss dispatch are gone too. The hub andno-boundary:regexes moved intorules_skeleton.py, the only module that uses them.split_accepted, and theAccepted:prefixskeleton_proseadded. The brief listedsplit_acceptedas something to keep, but once the block paths were gone its only callers were tests. The prefix existed only so it could split the Accepted bullets back out. I checked by removing the prefix: no citation in the tree quotes it.tests/v2/rules_budget.py:BLOCK_MEASURESand the format-change path. A leftover block row now reads as measures missing and measures gone, never as a match (tested).tests/v2/test_doc_citations.py: the block branch ofhub_findings(along with its unusedproseargument) and theinteractshalf ofnamed_id_findings.test_interacts_ids_existis nowtest_the_rule_ids_a_rule_names_exist.rules/README.md(including the budget's block measures, the blocktolerated:/Signal:placement and the block hub map), the block half of the split-candidate grep, axis 13 ofdocs/design/AGENTS.mdand its other both-formats wording, and in root AGENTS.md the line-width exception for block bodies, the "moving to the skeleton" sentence, the block wording of the excerpt-discipline rule and the old "rule shape" list.Kept, as a refusal
Without the block parser, a rule written in the old format would be skipped silently and its examples would never run. A column-0
X1.line is now refused wherever it stands, with a message naming the retired format and the skeleton. That covers a line outside any rule, a line opening a rule's body, and a line inside or glued to a field, where it would otherwise have joined the prose. Tested in all five placements.Tests, sorted by the code they exercise
test_rules_doc_grammar.pyis rewritten around whatrules_doc.pystill owns: the example-line grammar (now tested directly throughparse_example_line, with rows added for a D-section subject, an unassertable field and a mismatcheddeviates:field), the annotation registry, the split into rules and Backgrounds, duplicate IDs, the retired-format refusal and a signal line outside any rule. Tests that guarded something the skeleton parser does were converted intotest_rules_skeleton.py:Deleted, because no skeleton code is left for them to reach: the block pointer-line test, the indentation and Accepted-spelling batteries, and the block
tolerated:marker tests. The skeleton's**Tolerated:**field has its own tests. The hub-findings rows that still had something to test (a hub naming itself,X21not counting asX2) became skeleton rows. The budget tests now use skeleton docs and rows.The four deferred minors, each with a test that fails on the pre-fix code
#761 …line in a bullet's continuation raised "nested list". It is prose now. A real heading there raises its own error, and a nested list still raises "nested list"._vocab.pynamed an Except bullet by description ("its one-letter Except"). It now quotes the bold lead, "A numeral of one letter needs words to spare". The comment has to name rules/S10 for the citation check to reach the quote. A new test,test_a_citation_naming_a_bullet_quotes_its_bold_lead, holds every comment that names an Except or Precedence bullet to a bold lead of that rule's bullets. The verbatim-excerpt check could not do this: another sentence of the same rule passes it, which I confirmed with a mutant.Also: the README's Signal tag list was missing
character,separatorandedge full stop(W3's second signal). It now names every tag, plus the two rules (A1/C11, C7) that write no tag.test_the_readme_lists_every_signal_tag_the_rules_useholds the list to the footers both ways, and fails when a tag is dropped (checked).Review
The design-docs-reviewer agent ran on the first commit and found seven things, all fixed in the second commit:
-.*,+and numbered markers are refused too.parse_example_linedocstring, axis 12, and the comment on test_corpora's floor.Each new refusal row fails on the first commit's parser, and every row the narrower checks already refused still passes. A second review of the fix commit found no defects: no real rule holds a column-0
ID.line, the new refusal never sees fence or footer lines, and every guard the list names exists.PR review (/pr-review-toolkit:review-pr)
Four reviewers ran on the PR (code, tests, comments, silent failures). Their findings are fixed in
b11faa3b. Two rounds of review on that fix commit found gaps in the new check, fixed in77f21dfdand67e4c293; the last round was clean, apart from a wording note fixed in161b88f7. None of these was a regression: master behaved the same way.Text outside any rule is refused. Before, a subheading after a rule's footer hid everything below it, and a fence or field in a section file was ignored; the rule count still matched the file count. Outside a rule the text may now hold only a
## Name (X)section heading, each letter once, and its oneBackground:paragraph. The following are refused:holds_assertion, newly split out of_looks_like_example.The two walkers now agree on a section heading glued to a Background.
A numbered list at the start of a line in a prose field is refused, as
*and+already were. Inside a Background only an item numbered 1 interrupts the paragraph, as in CommonMark, so a wrapped line like2026. Thenstays prose.Rule.toleratedis deleted. Nothing read it once the block parser was gone;Skeleton.toleratedholds the reason.Two tests were fixed whose assertions had never been shown to fail: the bullet-lead and signal-tag checks are now helpers with synthetic rows covering both directions. A rule heading with no fields gets its own rows: it used to produce no rule and drop its examples silently.
test_corpora's rule floor is ratcheted from 38 to 70, with the comment now stating what it guards.A convention change to note: rules/README.md said a retired rule "keeps its ID with a one-line tombstone". The parser can no longer hold one, and no rule has been retired, so the sentence now says a retired rule's decisions entry records the retirement. IDs are still never reused.
Comment and docstring fixes: about ten stale block-format phrasings.
Each new refusal row fails on the commit before its fix, and every row the narrower checks already refused still passes.
Where axis 13's lessons went
vdsweeping indoandmc.interacts:accounting is gone, with the field.Follow-ups noticed, not done here
Other comments name a skeleton bullet by description rather than by a quoted lead:
_pieces.py:808("C14's Except"),cases.py:280("W4's interpunct Except"),test_script_segment.py:987("W1's interpunct Except") and_comma.py:490. The new test reaches only a comment that names the bullet and quotes it. Those four quote nothing, so neither check reads them.🤖 Generated with Claude Code