Skip to content

Repair regressions from the fleet sweep: art blocks, Args bodies, comment lines, term lead-ins, ignore at level 0, docs-only README variant (closes #27) - #28

Merged
thorwhalen merged 2 commits into
masterfrom
fix/repair-regressions
Sep 15, 2026
Merged

thorwhalen merged 2 commits into
masterfrom
fix/repair-regressions

Conversation

@thorwhalen

Copy link
Copy Markdown
Member

Closes #27. Part of #16 (WP6 fleet sweep).

The principle, now written down

epythet/normalizer.py states it and every rule enforces it: rewrite only what is unambiguous; otherwise report. What a rule leaves alone, epythet validate reports (DR014, DR002, DR031), so nothing is silently dropped.

The eight defects

# Defect Root cause Fix Fixture
1 blank lines inserted inside ASCII-art diagrams blank_lines_between_blocks fired on the varying indentation of drawing lines new ART line context (is_art_line, _art_runs); every rule treats it as code ascii_art_untouched
2 Args: entry name: + indented description became name:: literal_block_after_colon knew nothing about Google section bodies google_section_bodies(); the rule skips section bodies and lone term: lines google_args_bare_name_untouched
3 README snippet claimed the repo "ships tooling" when it only publishes agent-readable docs one snippet for every case agentic-readme-section-docs-only snippet, chosen by section_snippet_for() test_docs_only_project_gets_the_shorter_section
4 # comment lines in prose became rubrics (33 in one i2 run) markdown_headings_to_rubrics accepted any # line with alphanumeric text heading shape required (capitalised title, no code characters, no trailing :/., no TODO: tag); a lone # needs blank lines on both sides; never next to another # line or after code comment_lines_untouched, markdown_h1_heading
5 :return: nested into a preceding Note: body google_one_liners folded field-list lines as continuation only wrapped prose is folded; a field list, bullet or heading ends the section note_one_liner_then_field_list
6 specifying: + indented paragraph became a :: literal block no prose-vs-code test on the indented block the block must read as code (no line with four or more plain words); a lead-in over a paragraph is a definition list and DR014 reports it term_then_indented_prose_untouched
7 docstring-style module template tripped DR014 template put Main entry points: directly over an indented block template is now blank line + bullet list (what the swept repos already use) DR014.py: bad_entry_points_over_indented_block, good_entry_points_blank_line_then_list
8 validate -i tests/ not honoured at level 0/0.5 the level-0 linters (ruff, pydoclint) ran without the ignore list; parsing was fine in both argument orders is_ignored() is the one predicate; lint findings are filtered through it; -i a -i b now accumulates for validate and repair test_ignore_applies_to_the_linters_at_level_0, test_ignore_parses_the_same_in_every_argument_order

Also found while running the dry-runs

  • repair stripped an author's blank line before the closing quotes and counted it as a rewrite; the count of trailing blank lines is now preserved (test_trailing_blank_lines_before_the_closing_quotes_are_kept).
  • Blank lines were inserted between wrapped Args: entries; consecutive definition-list terms need none (google_args_wrapped_entries_untouched).
  • bare_headers_to_rubrics is no longer source-safe: napoleon renders a bare Examples: header as that rubric already, so the rewrite churned the source for no change on the page (now in UNSAFE_RULES with the reason; still runs at build time).

Verification

  • 548 tests green, module doctests green.
  • repair --dry-run over fresh read-only copies of dol and i2 (after their sweeps): 4 rewrites remain, all correct RST fixes (a blank line after a bullet list before prose; before a field list after an indented paragraph; before a nested list after can:; # Signature Calculus as the first line of a module docstring to a rubric). None of the eight patterns.
  • Independent adversarial review (separate agent, brief: refute the change) returned FIX-THEN-MERGE with three should-fix items, all folded in with fixtures: a lone Usage: / Output: lead-in over code keeps its literal block (_looks_like_code, usage_lead_in_literal); a lone # heading needs a blank line before it, not after (markdown_h1_glued_below); a doctest, bullet or field line ends a drawing run, and a bare >>> prompt is never art (arrows_then_doctest, bullets_with_arrows, bare_prompts_untouched). Its master-vs-branch comparison of build-time output over every docstring in dol, i2 and meshed (2215 docstrings, stale build copies included) now differs in 25, each one an intended fix.
  • Two of its nits are left as they were, on purpose: is_ignored() matches tokens against the absolute path (pre-existing in file discovery; a relative match needs the project dir threaded through iter_python_files), and google_section_bodies() is a separate pass rules opt into rather than part of line_contexts (a LineInfo refactor is the right next step if a fourth rule needs it).

Judgment call to know about

A # Title line that meets every heading condition (first line of a module docstring, blank line after, capitalised words) still becomes a rubric. If rubrics from # lines are unwanted altogether, the switch is one line: add markdown_headings_to_rubrics to UNSAFE_RULES.

…ment lines, term lead-ins, one-liner folding, docs-only README variant, ignore at level 0 (#27)

Normalizer (build-time and repair): the principle "rewrite only what is unambiguous, otherwise report" is now in the module docstring and enforced:
- a new ART line context keeps every rule out of box-drawing / arrow drawings (blank lines were being inserted inside diagrams);
- google_section_bodies() lets rules stay out of Google section bodies: no `x::` from an Args entry with its description below, no `error:` entry mistaken for a section, no blank line between wrapped Args entries;
- markdown_headings_to_rubrics wants a heading shape (capitalised title, no code characters, no trailing colon, no TODO: tag) and, for a lone `#`, blank lines around it; commented-out doctests and their `# True` outputs, and runs of `#` prose, stay as written;
- literal_block_after_colon skips a lone `term:` and any indented block that reads as prose (a definition list, reported as DR014), so `specifying:` + paragraph is no longer a literal block;
- google_one_liners folds only wrapped prose into the section body, never a field list or bullet list, so `:return:` no longer nests under `Note:`.

Repair: bare_headers_to_rubrics is no longer source-safe (napoleon renders a bare `Examples:` as that rubric already; a bare `Note:` is ambiguous and reported); the author's blank lines before the closing quotes are preserved instead of being stripped as a "rewrite".

Validate: `--ignore` now also filters the level-0 linters (ruff, pydoclint) through the same is_ignored() predicate as file discovery; `-i a -i b` accumulates for validate and repair.

Agentic README: a second snippet, agentic-readme-section-docs-only, for projects whose only agentic aspect is their agent-readable documentation; section_snippet_for() picks it, so the section no longer claims the project "ships tooling".

Docstring-style skill: the module template is `Main entry points:` + blank line + bullet list, which DR014 accepts (fixtures added to DR014.py).

Fixtures: ascii_art_untouched, google_args_bare_name_untouched, google_args_wrapped_entries_untouched, comment_lines_untouched, markdown_h1_heading, note_one_liner_then_field_list, term_then_indented_prose_untouched; tests for the ignore list at level 0 and in every CLI argument order, the trailing-blank invariant, and the docs-only variant.
…al block, a lone # heading needs a blank before not after, doctests and bullets end an art run

- literal_block_after_colon: no more lone-term refusal; the block must look like code (_looks_like_code: no prose line, a code signal somewhere), and a prose line needs sentence punctuation or six plain words, so `pip install foo bar` is still code.
- markdown_headings_to_rubrics: a title may start with a digit or a backtick; a lone `#` must follow a blank line (or open the docstring) but may be glued to the paragraph below.
- _art_runs: a doctest line always ends a run and is never art (a bare `>>>` prompt is all strokes); a bullet or field line ends a run unless drawn in strokes; a blank line before a block that follows a drawing is inserted again (it is outside the drawing).
- google_one_liners: a wrapped line inside a field body is folded like any other continuation; a new field or bullet still ends the section.
- quickstart --ignore accumulates like validate and repair.
- Fixtures: usage_lead_in_literal, markdown_h1_glued_below, arrows_then_doctest, bullets_with_arrows, bare_prompts_untouched.
@thorwhalen
thorwhalen merged commit 1ef791b into master Sep 15, 2026
10 of 12 checks passed
@thorwhalen
thorwhalen deleted the fix/repair-regressions branch September 15, 2026 10:39
thorwhalen added a commit that referenced this pull request Sep 15, 2026
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