Repository navigation
Restructure the Prose Gate into Extract, Normalize, and Evaluate Layers - #3411
Conversation
The rule names, defaults, and messages, the charset tiers, the British spelling families, the exemption lists, the per-language comment data, and the file-to-lexer mappings become data beside the script. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pygments replaces the hand-written comment, string, and docstring parsing, with its bash heredoc rule corrected to end only on the terminator line. markdown-it-py replaces the Markdown block approximation. A YAML run block and an ESPHome lambda are lexed again as the script or C++ they hold. Each rule is a function of one text unit, registered by name, and the sentence boundaries share one definition. A repository may add exemptions in .prose-gate.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One class per rule, one per language for extraction and normalization, one for Markdown, and one for the override merge, with the single-incident classes folded into them. Cases that exercised the replaced parser are dropped, and the size ceiling is asserted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pygments read a C# collection expression opening on its own line as an attribute and lost the comments inside it, so that rule is patched the way the bash heredoc rule is. A comment line's sentence boundary takes no closing quote or bracket, which kept a quoted `'.'` from reading as two sentences. The whole command line moves into prose-gate.json, so the local shim can answer --help from it without starting the gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both ran the gate in-process through runpy, which ignores its PEP 723 block, so its first dependency raised ImportError in every downstream hook. Each now runs it as `uv run --no-project --script`, and hub_fetch_run.py fetches prose-gate.json from the same commit beside it. The shim answers --help and refuses an unknown argument itself. Closes #3408 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A comment after a block indicator no longer empties the script under it, a heredoc label opens on a letter so a shift hides nothing, a multi-line HTML comment is no Markdown paragraph, an inline comment keeps its line past a wrapped code span, and a shebang's assignment is not its interpreter. A run reading only line rules skips the lexers. The stale statements on scripts needing no packages are corrected, and pr_review's block names are held to markdown-it-py's list again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The line search for an inline HTML comment resumes after the previous one, so two identical comments keep their own lines. The shim help test turns argparse color off, and the host tools entry says the tests need the gate's packages where the gate itself does not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
A recorded local strict-review pass covers head |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical findings affect dependency installation, override validation, and downstream runtime compatibility.
5 open issues
What changed in this PR
This pull request restructures the prose gate into extraction, normalization, and evaluation layers, moving configuration into prose-gate.json and updating runners to use uv.
Changes:
- Adds Pygments and markdown-it-py extraction, nested-language handling, repository overrides, and data-driven rules.
- Updates the hub fetcher, local shim, tests, hook fixtures, specifications, and documentation for the companion data file and new runtime.
- Expands rule, language, Markdown, CLI, override, and runner test coverage.
Outstanding findings remain in the final review:
.github/actions/prose-gate/prose_lint.py: unresolved critical findings cover empty tool-directive handling (1 vote) and missing runtime packages in the lint-only test leg (2 votes). Moderate findings cover Pygments compatibility, apostrophes and indentation in YAML run blocks, instruction HTML comments, empty spelling configuration, and EOF block scalars (1 vote each). A nit remains for CLI abbreviation handling (1 vote).tests/test_prose_lint.py: a moderate finding (4 votes) requires normalizing color settings in the help comparison.catalog/snippets/hub_fetch_run.py: a critical downstream resync finding and a nit concerning the loader contract remain (1 vote each).pyproject.toml: a critical test-environment dependency finding remains (2 votes).scripts/prose_lint.py: a nit remains for disabling CLI abbreviation (1 vote).
| File | Description |
|---|---|
tests/test_repo_gate.py |
Updates the gate-copy documentation test. |
tests/test_pre_commit_hook.py |
Includes the companion gate data file in hook fixtures. |
tests/test_pr_review.py |
Aligns CommonMark block-name validation with markdown-it-py. |
tests/test_hub_fetch_run.py |
Tests companion fetching, uv delegation, provenance, and failure handling. |
spec/host-tools.json |
Documents the prose gate’s dependency and interpreter requirements. |
scripts/README.md |
Documents the layered gate, data file, overrides, and uv usage. |
scripts/prose_lint.py |
Provides the dependency-free local shim and delegates execution through uv. |
RESYNC.md |
Updates resynchronization guidance for the data-driven exemption file. |
pyproject.toml |
Configures mypy handling for the gate’s external packages. |
GOVERNANCE.md |
Documents companion fetching and uv-based gate execution. |
docs/fleet-map.md |
Updates the renamed dead-path test reference. |
catalog/snippets/hub_fetch_run.py |
Fetches companion data and runs the fetched gate through uv. |
.github/actions/prose-gate/prose-gate.json |
Stores the data-driven rules, mappings, messages, exemptions, and CLI metadata. |
Review effort: Lite
A hook that still imports the gate in-process gets one message naming `uv run --no-project --script` and the stale snippet to resync, rather than a traceback. Both packages carry the versions tested against as a lower bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The old in-process snippet catches SystemExit and drops its message, so the remedy is printed before the exit rather than carried by it. A missing prose-gate.json beside the script names the same remedy, and the test runs the gate the way that snippet did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |
…e-layers # Conflicts: # pyproject.toml # spec/host-tools.json # tests/test_pr_review.py
|
A recorded local strict-review pass covers head |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #3411 +/- ##
==========================================
Coverage ? 80.13%
==========================================
Files ? 21
Lines ? 9661
Branches ? 0
==========================================
Hits ? 7742
Misses ? 1919
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
An empty directive name escaped to an empty pattern that matched every comment and stood the comment rules down, so a blank entry under any override key refuses the run. The shim help test sets NO_COLOR in the child too, since FORCE_COLOR otherwise colors only that side. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |
…ry (#3416) Implements the maintainer's decision of 2026-10-23 on #3391's follow-ups for the audit, in his words: "audit, agree on moving tests to tests and that should be consistent for the fleet to have tests and keep them in tests, no hand written parser when a field tested and maintained versions readily exists, so switch it and proceed". ## What Changes ### Tests Move to tests/ - `_selftest_cases`, the inline matrix in `spec/audit.py`, is now `tests/test_audit_helpers.py`, a unittest module with one `subTest` per case. - The temporary git repositories are built by helpers on the test classes. - The `globals()` swaps are now `unittest.mock.patch` calls. - The invalid-byte probe tests move out of `tests/test_audit.py` along with the probe. - `--selftest` stays, as a smoke check of each helper family that runs in under a second. ### Parsers - `spec/audit.py` declares `pyyaml` and `markdown-it-py` in PEP 723 inline metadata. - **YAML:** workflow jobs, contract tokens, the `python-directories` input, the concurrency group, the schedule gate, and `dependabot.yml`'s ecosystems are now read from the parsed document. - A job's verbatim region is cut at the parser's own marks. - Contract tokens are matched against a view of the parsed job, indented two spaces per level, with block-scalar bodies left out except an `if:` condition. - **Markdown:** headings, fenced blocks, the README title and intro, link stripping, and the License column are now read from markdown-it-py tokens. - **Text scans that stay:** link definitions, image references, and tool rows are still read as text. A parsed link keeps its target but drops the reference name and position those checks read, and a comment beside each scan says so. - **`pyproject.toml`:** the audit reads only whether the file is present, never its content, so there was no read to move to `tomllib`. ### The One Hand-Written Reader That Stays The fence step and the `## ` region reading are still hand-written. They now live in `spec/carried_text.py`, which uses the standard library only. - **What shares it:** the audit and all three scripts below use `fence_step`. The audit and `scripts/carry.py` also use `normalize`, and the audit uses `extract_section` and `strip_sections`. - **Why it stays hand-written:** `scripts/carry.py`, `scripts/build_dist.py`, and `scripts/canonical_review.py` run under a plain `python3`, in CI and from the host menus, and carry.py writes the verbatim regions the audit then hashes. The four tools must split a document at the same boundaries, so moving the audit alone onto markdown-it-py would let carry.py write a region the audit reads as drift. - **Follow-up:** a later lane moves the region reading of all four tools onto markdown-it-py together, along with the switch of their callers to `uv run --no-project --script`. ### Registry - `spec/checks.json` registers one entry per check: its id, family, a one-line description, the spec file it reads, its scope, and whether it runs on the hub itself. - `audit_repo` walks the registry in order and calls `check_<id>` for each entry. It runs the per-file checks file by file, so findings keep their order. - Hub special cases that apply to a single check are now the registry's `hub` flag. The hub's verbatim-section excision and the hub argument to the baseline read stay in code, since neither belongs to one check. - The suppression ids and the driftNote id parse now resolve against the registry. `CHECK_ID_RE` moves into `spec/validate.py`. - `spec/validate.py` now checks: - the registry's shape; - that every file check has a baseline check before it in its run, on the hub's filtered run too; - that no check carries an unknown key, and that only a repo check sets `ground: false`; - that every id a driftNote in `registry/repos.json` names is defined. ### Size Trimming the docstrings reached the ceiling only by dropping what a caller needs, so the Markdown reading and README checks move to `spec/audit_markdown.py`. That family depends on nothing else in the audit. Each docstring keeps what a caller needs: what the function returns, what None or an empty result means, and what it raises. | File | Lines | Ceiling in `tests/test_audit_size.py` | | --- | --- | --- | | `spec/audit.py` | 2442 | 3000 | | `spec/audit_markdown.py` | 665 | 1000 | `spec/checks.json` registers 33 checks. ### Callers - `spec/workflow_reuse.py` and `spec/fidelity_honesty.py` import the audit, so they declare the same libraries. Their usage lines, RESYNC.md, and docs/reusable-workflows.md now run them through `uv run --no-project --script`. - `tests/requirements.txt` gains `pyyaml>=6`. The merge with develop keeps #3411's lines beside it. - mypy's missing-import override adds `yaml`. ### Validate Action The coverage step now runs the helper suite, with the suite's requirements installed, in place of `spec/audit.py --selftest`: ```sh uvx --with-requirements tests/requirements.txt coverage@latest run --source=scripts,spec,host-setup -m unittest discover -s tests -p test_audit_helpers.py ``` `uvx` alone reads no script's inline metadata, so `spec/workflow_reuse.py --selftest` gets the same `--with-requirements`. OPERATIONS.md's local commands match. ## Before and After Audit Comparison The full sweep, covering every cataloged repository plus the fleet membership check, ran once at develop f646430 and once at this branch's head. The finding lists match line for line, apart from the run stamp. Before the parser commit, the hub plus PlexCleaner, ESPHome-Config, and Blog also matched at 7862c48. Where a parser now reads a shape the hand-written reader refused, the helper suite asserts the new reading. None of these shapes occurs in the audited repositories. - A folded or continued concurrency group, or one written as a flow mapping, is now read rather than reported as unreadable. A sequence is still refused. - A folded `python-directories` value, or a double-quoted one with escapes, is now read the way GitHub passes it, rather than refused. - A workflow that does not parse as YAML produces one `interface` DRIFT saying its contract is unread, rather than one finding per missing job. - A `[text][ref]` in the README tagline counts as a link only where `ref` is defined, which is how GitHub renders it. ## Verification Each command below ran in the worktree after the last commit. - `uvx ruff@latest format --check .` -> `269 files already formatted` - `uvx ruff@latest check .` -> `All checks passed!` - `uvx mypy@latest` -> `Success: no issues found in 75 source files` - `npx markdownlint-cli2` over the changed Markdown -> `Summary: 0 error(s)` - `python -m unittest discover -s tests`, with tests/requirements.txt installed -> `Ran 2837 tests ... OK (skipped=7)` - `uv run --no-project --script spec/audit.py --selftest` -> `SELFTEST PASS` - `python3 scripts/prose_lint.py . --allow-comments --diff origin/develop` -> no violations. Without `--allow-comments`, every reported line is `comment-added`, which is why this pull request carries the `comments` label. - `python3 scripts/repo_gate.py` -> `composite-actions`, `eol`, `eol-coverage`, and `sha-pin` all report 0 issues, exit 0. - `python3 spec/validate.py` -> `Spec validation OK: 22 cataloged repos classify cleanly. ...` - `python3 scripts/build_dist.py --check` -> `Generated skill distributions are current.` It ran under a plain `python3`, as did `scripts/canonical_review.py report`. ## Local Review `local-strict-review` passes ran at the `frontier` tier over the whole branch diff. Each pass was recorded before the push it covers, and each push is attested on this pull request. The fixes they drove: - **Workflow reading:** - Contract tokens anchored on a newline match a job's first key. - A workflow is parsed once. - An unparseable workflow produces one `interface` finding. - An unparseable `dependabot.yml` produces one `dependabot` finding. - The concurrency refusal names the shapes the parser actually refuses. - **driftNote ids:** an id the catalog defines keeps its catalog reading, and only an id spec/checks.json alone defines reads as evaluated. This keeps the fleet sweep identical to develop. - **Taglines:** a link-free tagline is returned unchanged, an image counts as markup, and a code span is taken from the source as written. - **Registry validation:** `spec/validate.py` refuses: - an unknown key; - a `ground: false` outside a repo check; - a file check with no baseline check before it, on the hub's filtered run too; - a malformed id or suppression type. It reports that one rather than raising on it. - **Tests:** - New tests pin which checks skip the hub, the hub's own run, and the baseline slot each file check reads. - Others pin `registry.driftnotes` running last, `split_jobs` at a sibling key and at a file with no final newline, and the schedule gate reading every `on:` shape. - A declared Dependabot ecosystem is tested, and the smoke self-test is gated by a test. - `test_strip_md_links_stays_linear` checks a ratio rather than wall-clock time, since CI's coverage-traced run took 1.08 s against the old 1 s bound. It holds 20000 brackets under 8x the time for 5000, plus 0.05 s of slack. A quadratic reader fails that check unless it takes under about 6 ms at 5000 brackets, and the old wall-clock bound passed such a reader too. - **Pointers:** every line that invokes the audit, or a script that imports it, now spells `uv run --no-project --script`. Every pointer to a moved function names its new home. The trim's dropped rationales are restored as one line each. OPERATIONS.md says which tools share which `spec/carried_text.py` primitive. Declined with evidence: - The validate action's helper-suite run duplicates the Python leg, and `--selftest` stays. The brief fixes both ("runs the test module under coverage instead", "`--selftest` stays as a smoke check"). - `spec/validate.py` refuses a driftNote whose parenthesized dotted token names no check, and spec/checks.json carries `family`, `description`, and `spec`. The brief requires both. - The following stay as they read today, since a full sweep of every cataloged repository matches develop and GitHub renders each case the same way: - markdown-it reads a heading inside an HTML block, a fence, or a container differently from the old line regexes; - a `## X ##` closing sequence reads differently for presence than for verbatim extraction; - an undefined `[x][ref]` in a tagline reads as literal text. The follow-up lane that moves all region and link reading onto markdown-it-py removes the remaining split. - `split_jobs` returns `{}` for a flow-style `jobs:` mapping, exactly as develop's reader did, and no contract declares `verbatimJobs`. ## Pre-Existing Findings, Not Filed - `--check sentence-length` reports pre-existing sentences that this branch only touched to rename a path: docs/reusable-workflows.md:40, scripts/build_dist.py:198, :202, :321, scripts/canonical_review.py:157, scripts/carry.py:418, :492, and tests/test_build_dist.py:949. - `spec/validate.py`'s `contains_description_markdown_link` still matches brackets by hand. - `CHECK_ID_RE` reads any parenthesized lowercase dotted token as a check id, a file name such as `(cspell.json)` included. - `scripts/canonical_review.py` and `scripts/carry.py` each write the unfenced `## ` predicate inline rather than calling `spec/carried_text.py`. The follow-up lane moves them. - `tests/test_audit_size.py` follows the shape of the two size tests already in tests/. Those two disagree on `assertLess` versus `assertLessEqual`. - `tests/workflow_steps.py` and `tests/test_docker_task_workflow.py` read workflows by indentation, where PyYAML is now available to the suite. - The `reports/*.md` headers still print `python3` for their generators. The generator strings now say `uv run`, so the next regeneration rewrites the headers. - `scripts/carry.py` keeps its own region reading (`section_span`, `comparable_region`) beside `spec/carried_text.py`. The follow-up lane covers it. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…#3417) ## Summary Promotes the pull requests merged into develop since release 2.0.1148. Each carries a maintainer decision of 2026-10-23 recorded on #3391. - [#3407](#3407): rewrites the write guard as a small lexer of 1,653 lines. It fails open under its stated threat model and fails closed only on requirement 4. A test holds it at 2,500 lines or fewer (item 1). - [#3409](#3409): adds CODESTYLE rules. Tests live in `tests/`, and a maintained parser replaces a hand-written one. A script declares its dependencies in PEP 723 metadata and runs as `uv run --no-project --script`. It switches the callers to that spelling and adds a managed allow rule to the agent-safety installer (item 1 follow-ups). - [#3410](#3410): splits `pr_review.py` into the gate, a Copilot adapter reading its vocabulary from JSON, and `pr_cleanup.py`. It collapses the exit codes and adds `tests/requirements.txt` and the CI runners. - [#3411](#3411): rebuilds the prose gate on Pygments and markdown-it-py, with its vocabulary and exemptions in `prose-gate.json` and a repo-local override. - [#3415](#3415): holds the Merge Gate on a part of a Copilot review body the tooling cannot place. The hold lasts until an owner acknowledges it with outcomes (item 4 follow-up). - [#3416](#3416): moves the audit self-test to `tests/` and reads YAML and Markdown with PyYAML and markdown-it-py. It adds the check registry `spec/checks.json` and splits out `spec/audit_markdown.py`. It shares `spec/carried_text.py` with carry, `build_dist`, and `canonical_review`. - [#3418](#3418): fixes the findings this promotion's first review round raised on the content above. It aligns the drive-pr escalation line with pr-review-conduct and names `tests/requirements.txt` where the prose said the tests need nothing installed. It also restores the `uvx` launcher in a release-guard assertion. - [#3419](#3419): fixes the finding the second review round raised. The Copilot adapter's prose path reads a coverage count longer than `COUNT_DIGITS` as `unknown`, sharing `count_state` with the marker path. - [#3420](#3420): fixes the finding the third review round raised, under the maintainer's ruling. `hub_fetch_run.py` falls back to `git ls-remote` where the API lookup of `main` fails, so the prose gate and its data are fetched at one commit. Where neither lookup resolves, the documented fail-open against `main` stays. - [#3421](#3421): fixes the findings the fourth review round raised. The Copilot adapter reads a finding count longer than `COUNT_DIGITS` as unknown rather than zero, through one length check and one None-aware sum. The host-setup gates-and-tests row says `uv` installs the test requirements. Closes #3408 ## Constituent coverage The Copilot rounds on this promotion ran at Lite effort and state no full coverage, so Merge Gate item 2 rests on the promotion case. Each change this promotion carries had full coverage on its own pull request into develop, at its merged head: | Pull request | Merged head | Coverage | | --- | --- | --- | | [#3407](#3407) | `9efc1002` | attested local pass, `coverage=local` | | [#3409](#3409) | `bcc7a9e1` | attested local pass, `coverage=local` | | [#3410](#3410) | `00cec726` | attested local pass, `coverage=local` | | [#3411](#3411) | `bd128136` | attested local pass, `coverage=local` | | [#3415](#3415) | `5be9db87` | attested local pass, `coverage=local` | | [#3416](#3416) | `b914f083` | attested local pass, `coverage=local` | | [#3418](#3418) | `3a86cb51` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | | [#3419](#3419) | `6e7b868d` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | | [#3420](#3420) | `9b492290` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | | [#3421](#3421) | `743010e6` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | 🤖 Generated with [Claude Code](https://claude.com/claude-code)


Summary
Restructures the prose gate into three layers and moves its data out of code, as decided for the prose follow-ups.
.github/actions/prose-gate/prose-gate.json. Comment markers, documentation and help forms, trailing checker directives, docstring section names, and nested lexes: a YAMLrun:block is lexed as bash, and alambda:key or!lambdatag scalar as C++, each numbered by the file's own lines.RULE_TABLE. The rules that lived inline incheck_filemoved out, and the sentence boundaries share one terminator definition.hub_hosted, the instruction documents, service accounts,dupword_allow, generated trees, the runbook exemption, and the not-prose and tool-directive pattern lists. The ledger test forhub_hostedreads the JSON..prose-gate.jsonat its root with additions to the exemption lists only. Any other key, a non-list value, or unreadable JSON refuses the run.requires-python = ">=3.13"(thespec/host-tools.jsonfloor),markdown-it-py>=4.2.0andpygments>=2.21.0, the versions tested against as a lower bound only, per the maintainer's ruling. A missing package or a missingprose-gate.jsonbeside the script prints one message naminguv run --no-project --scriptand the stalehub_fetch_run.pysnippet to resync, then exits 1, so a downstream hook still running the gate in-process fails with the remedy rather than a traceback.mypyignores their missing stubs in the generic validator leg, and the gate type-checks clean againsttypes-Pygmentswith the script's own interpreter.$STUB_DIRended aSTUBheredoc) and read no double-quoted label, and C#'s attribute rule swallowed a collection expression opening on its own line, comments included.catalog/snippets/hub_fetch_run.pyandscripts/prose_lint.pyrun the gate throughuv run --no-project --scriptinstead ofrunpy. The snippet fetchesprose-gate.jsonfrom the same ref beside the script. The shim answers--helpand refuses an unknown argument from the same data, with no uv start, and a test holds its help equal to the gate's.prose_lint.py.prose_lint.pyis 1799 lines (from 3519),prose-gate.json172.Languages the gate reads comments in: Python (comments and docstrings), bash and
sh(with the corrected heredoc), TOML, Terraform, Makefile, Ruby, Caddyfile, C, C++, Arduino, C#, JavaScript, TypeScript, JSON, JSON5, JSONC and.code-workspace(as JSON), CSS and SCSS (as CSS), HTML, XML and the MSBuild project formats (as XML), PowerShell, INI,.editorconfig,.conf, YAML (with the nested bash and C++ lexes), Dockerfile, git pattern files and extensionless scripts (as bash), and Markdown through markdown-it-py.Closes #3408
Verdicts
python3 scripts/prose_lint.py . --summaryon develop at4a77a1d1python3 <develop prose_lint.py> . --summary, on this branch's treeuv run --no-project --script .github/actions/prose-gate/prose_lint.py . --summaryPSScriptAnalyzerSettings.psd1, no lexer, as before)A wider comparison ran the old and the new
check_fileover every rule, opt-in ones included, on the committed trees of 23 local fleet clones, 6112 files. Every difference falls in one of these classes:lambdaC++ comments, which the nested lex now reads by design.#lines the old parser read because its heredoc detection failed on them. Bash reads a heredoc body as data, and so does the gate now. In a YAMLrun:block the body is still read as code, which keeps the workflow verdicts the old YAML reading gave.sentence-lengthandsentence-splitonly: markdown-it-py's CommonMark blocks differ from the old approximation at a setext underline under a multi-line paragraph, a table needing its delimiter row, and the<search>and<source>block names. The shared sentence boundary now carries the ellipsis guard the comment rules already had.Verification
Each command was run from the worktree, with the gate's packages on
PYTHONPATHfor the in-process test imports.uvx ruff@latest format --check .uvx ruff@latest check .uvx mypy@latestuvx --with types-Pygments mypy@latest --python-executable <script env python> .github/actions/prose-gate/prose_lint.pypython -m unittest discover -s tests, in a venv holdingtests/requirements.txt, after merging developuv run --no-project --script .github/actions/prose-gate/prose_lint.py . --summaryPROSE_ALLOW_COMMENTS=1 uv run --no-project --script .github/actions/prose-gate/prose_lint.py . --diff origin/developpython3 scripts/repo_gate.pypython3 spec/validate.pyThe
commentslabel applies: this change writes code comment lines throughout the restructured script and tests.Local review
Seven recorded
local-strict-reviewpasses, the last three clean. A hosted review raised five findings on 0caa9ad, each now answered: two fixed in bd12813 (a blank override entry is refused, and the help test turns color off on both sides), two fixed by the merge of develop (the test requirements), and one declined under the maintainer's transition ruling. Fixed from the first two: a comment after a block indicator emptying the script under it, a shift<< 2read as a heredoc, multi-line HTML comment lines read as paragraphs, inline comment line numbers, thegenerated_treeswording, an unused constant, a shebang assignment read as the interpreter, the line-rule-only sweep lexing every file (the warn-onlycharset-unknownsweep went from about 9 s to 1.4 s), stale statements inspec/host-tools.json,tests/test_repo_gate.py, and the snippet, and thepr_review.pyblock-name cross-check, restored against markdown-it-py's list.Introduced findings left after the local edit budget, each with its outcome:
didn't) opens a bash single-quoted string that runs to the next'in the script, hiding the comments between. The old YAML reading did not. No current fleet file shows it in the comparison above. Reading the body as data instead would lose the inline-script comments workflows carry today. Deferred to Read a Run-Block Heredoc Body Without Letting Its Apostrophes Hide Later Comments #3413.code_inlinechildren in the line search. Deferred to Skip Inline Code Spans When Numbering an Inline Markdown Comment #3414.FORCE_COLORon Python 3.14. Fixed in bd12813.The test suite's packages come from
tests/requirements.txt, which this branch extends withpygmentsand raisesmarkdown-it-pyto the tested floor.Ruled by the maintainer: the downstream transition window is accepted, the fleet snippet being resynced right after the promotion, and the packages carry lower bounds only, the two Pygments patches refusing to load loudly if a release respells either stock rule.
Declined: a shared copy of the parser-building loop between the gate and the shim. The shim exists to answer
--helpwithout the gate's packages, so it cannot import the gate, and the new help-equality test holds the two copies together.Pre-existing findings, not filed
sentence-length(opt-in) reports 152 sentences over the cap across the files this branch touches, most of them in text the branch moved rather than wrote.🤖 Generated with Claude Code