Repository navigation
Move Audit Tests to tests/, Parse YAML and Markdown, Add Check Registry - #3416
Conversation
The inline matrix in spec/audit.py becomes tests/test_audit_helpers.py, a unittest module with one subTest per case. Temporary git repositories are built by setUp-style helpers, and the globals() swaps are mock.patch calls. The invalid-byte probe tests follow the probe out of tests/test_audit.py. --selftest stays as a smoke check of each helper family that runs in well under a second.
spec/audit.py declares pyyaml and markdown-it-py in PEP 723 inline metadata. Workflow jobs, contract tokens, the python-directories input, the concurrency group, the schedule gate, and dependabot.yml's ecosystems are read from the parsed document. Headings, fenced blocks, the README title and intro, link stripping, and the License column are read from markdown-it-py tokens. The region reading the audit, carry.py, build_dist.py, and canonical_review.py share moves to spec/carried_text.py, standard library only, so those three keep running under a plain python3. workflow_reuse.py and fidelity_honesty.py import the audit, so they declare the same libraries and their command lines run through uv.
Each check audit_repo runs is an entry in spec/checks.json with an id, a 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, running the per-file checks file by file so findings keep their order. The per-check hub exceptions are the hub flag. The rest stay code. The suppression ids and the driftNote id parse resolve against the registry, and spec/validate.py checks the registry's shape and that every id a driftNote names is defined.
Each docstring keeps what a caller needs: what the function returns, what None or an empty result means, and what it raises. The Markdown reading and the README checks move to spec/audit_markdown.py, which depends on nothing else in the audit. A size test holds spec/audit.py under 3,000 lines and the new module under 1,000.
The validate action's coverage step runs tests/test_audit_helpers.py in place of the audit's --selftest, with tests/requirements.txt installed, since uvx alone reads no script's inline metadata. workflow_reuse.py's self-test gets the same libraries, and OPERATIONS.md's local commands match.
…istry-parsers # Conflicts: # pyproject.toml # tests/requirements.txt
A forbidden token anchored on a newline matches a job's first key again, since a job's token view opens with its key line. A driftNote naming a registered check says the audit evaluates it. spec/validate.py refuses a file check with no baseline check before it in its run. The invalid-byte probe's platform flag lives in the test module, and OPERATIONS.md names the suite CI runs of the audit.
An unparseable workflow is one interface finding, and the concurrency check no longer adds advice for a syntax error. The ambient GIT_DIR test runs the helper suite, since the smoke self-test runs no git. AUDIT.md names spec/checks.json where the runner resolves a driftNote id, and the stale comments and docstrings the moved self-test left are updated.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
|
A recorded local strict-review pass covers head |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #3416 +/- ##
==========================================
Coverage ? 80.78%
==========================================
Files ? 23
Lines ? 8848
Branches ? 0
==========================================
Hits ? 7148
Misses ? 1700
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:
|
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical and moderate findings affect audit correctness, validation robustness, Markdown handling, and CI smoke-test coverage.
15 open issues
Namespace colliding catalog and runner check IDs · New Handle flow-style job mappings instead of skipping them · New Preserve YAML parse failures as unreadable · New Avoid collisions between registry and catalog check IDs · New Only add validated string IDs to the set · New Reject non-scalar suppression types without raising · New Restore audit smoke-path self-test coverage · New Preserve source spelling when detecting code-span links · New Document the deliberate bypass actor exclusion · New Document account-wide token requirement for membership checks · New Document linear-history invariant for effective changes · New Document carried_text.py in the operations layout · New Make registry metadata operational or remove it · New Consolidate duplicated Git test fixtures · New Reuse the shared temporary-directory fixture · New
What changed in this PR
This pull request moves audit tests into tests/, adopts maintained YAML and Markdown parsers, introduces registry-driven audit checks, and updates shared tooling, validation, CI, and documentation.
Changes:
- Relocates audit helper and probe tests, adds size checks, and updates test dependencies and coverage commands.
- Adds PyYAML and markdown-it-py parsing while centralizing shared carried-text handling.
- Adds
spec/checks.json, registry validation, and registry-driven audit execution. - Updates standalone scripts, operational documentation, workflow commands, and mypy configuration.
| File | Description |
|---|---|
tests/test_spec_validate.py |
Tests check-registry validation and drift-note identifier handling. |
tests/test_git_env.py |
Runs the relocated helper suite under ambient Git environments. |
tests/test_fidelity_honesty.py |
Updates references to the moved helper tests. |
tests/test_build_dist.py |
Updates lazy-import tests for shared carried-text handling. |
tests/test_audit.py |
Removes relocated probe coverage and updates audit test references. |
tests/test_audit_size.py |
Enforces size ceilings for audit modules. |
tests/requirements.txt |
Adds the PyYAML test dependency. |
spec/workflow_reuse.py |
Adds parser dependencies and updates standalone usage. |
spec/validate.py |
Validates registry structure, ordering, and drift-note IDs. |
spec/fidelity_honesty.py |
Adds parser dependencies and updates standalone usage. |
spec/checks.json |
Registers audit checks and execution metadata. |
spec/carried_text.py |
Provides shared standard-library text boundary helpers. |
spec/audit_markdown.py |
Provides parser-backed Markdown and README checks. |
scripts/carry.py |
Uses shared carried-text handling for carried regions. |
scripts/canonical_review.py |
Uses shared carried-text handling for canonical content. |
scripts/build_dist.py |
Uses shared carried-text handling for distribution processing. |
RESYNC.md |
Updates the fidelity report invocation. |
pyproject.toml |
Adds the YAML missing-import override for mypy. |
OPERATIONS.md |
Updates local audit and coverage commands. |
docs/reusable-workflows.md |
Updates the workflow reuse command. |
AUDIT.md |
Documents registry-backed checks and drift-note behavior. |
.github/actions/validate/action.yml |
Updates CI coverage and audit helper execution. |
Review effort: Lite
A driftNote id the catalog defines keeps its catalog reading, and only a registry-only id reads as evaluated, so the full fleet sweep now matches develop line for line. A link-free tagline is returned unchanged rather than rebuilt from tokens. An unparseable dependabot.yml is one finding rather than a missing ecosystem. The smoke self-test is gated by a test, the test module has one git identity and one temporary-directory helper, the dropped rationales are back as one line each, and OPERATIONS.md names spec/carried_text.py among the shared primitives.
Each line that invokes spec/audit.py, the generated issue body, the configure.sh note, AUDIT.md, RESYNC.md, and the audit-a-repo skill, now spells it uv run --no-project --script, since the script imports PyYAML. scripts/README.md and a test docstring name spec/carried_text.py's region reading, and spec/validate.py refuses an unknown check key and a ground false outside a repo check.
A tagline carrying an image reads as carrying markup again, with the image reduced to its alt text. AUDIT.md says only an id spec/checks.json alone defines reads as evaluated, matching the catalog's precedence. The audit drops two urllib imports the Markdown split left unused, and canonical_review.py names spec/carried_text.py's normalize.
|
A recorded local strict-review pass covers head |
spec/validate.py reports a malformed check id or suppression type rather than raising on it, and holds the baseline-before-file rule on the hub's filtered run too. The remaining invocation lines run the audit and the fidelity report through uv, AUDIT.md's id-resolution sentence says what the runner does, the test module derives its init sequence from one identity tuple, and OPERATIONS.md drops a code span markdownlint refuses.
check_interface parses its workflow once, through the same YAML helper the concurrency and dependabot reads use. driftnote_findings resolves an id with one catalog lookup and the registry, and the unused owner helper goes. The validate action's description names the audit helper suite.
OPERATIONS.md says which tools share the fence step and which share the region reading, AUDIT.md's secrets runbook runs the audit through uv, and a validate.py docstring drops a pointer to code that no longer exists.
|
A recorded local strict-review pass covers head |
A test holds registry.driftnotes as the last registered check, since it counts the findings before it. OPERATIONS.md and scripts/README.md scope the shared fence reading to the audit's region extraction, and AUDIT.md states the registry-only id as the exception after its conclusion.
GOVERNANCE.md, spec/validate.py, and spec/resolve_description.py name spec/audit_markdown.py as description_findings' home. The concurrency refusal names the shapes the parser actually refuses, and a test helper module drops a standard-library-only claim that no longer holds.
AUDIT.md says a registry-only id's finding names the check the audit evaluates and the note goes once that check reports nothing, rather than calling it an exception the run decides. OPERATIONS.md names both audit suites CI runs.
|
A recorded local strict-review pass covers head |
A positive case holds dependabot_ecosystems reading each declared package-ecosystem, and OPERATIONS.md says carry.py shares only the comparable form and the fence step from spec/carried_text.py.
strip_md_links takes a code span from the source rather than rebuilding it, since the parser trims its padding. New tests pin which checks skip the hub, which baseline slot each file check reads, and split_jobs at a sibling key and at a file with no final newline. build_dist.py states the reason it imports spec/carried_text.py lazily as it now stands.
audit_repo run as the hub skips only the hub-false checks and still runs the file checks after them. check_dependabot_ecosystems reports an unparseable file as one finding, and the schedule gate reads a list and a scalar on: as well as a block mapping.
|
A recorded local strict-review pass covers head |
The CI unit job runs under coverage, where markdown-it's pass over 20000 unmatched brackets took 1.08 s against the 1 s bound. The test now times 5000 and 20000 brackets and holds the larger under eight times the smaller, which a quadratic reader exceeds and a linear one does not.
|
A recorded local strict-review pass covers head |
…#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)
…3431) The follow-up #3416 named: the audit, `scripts/carry.py`, `scripts/build_dist.py`, and `scripts/canonical_review.py` now split a document at headings and code blocks markdown-it-py reads, and `spec/carried_text.py`, the last hand-written fence reader they shared, is gone. ## What Changes ### One Reader, Now a Parser - `spec/fidelity_text.py` replaces `spec/carried_text.py`. It parses block structure only, CommonMark plus tables. `headings()` reads top-level ATX headings, `code_blocks()` and `code_lines()` read fenced and indented code at any depth, and `sections()` is the one place a level-two region's extent is decided. `section_span()`, `extract_section()`, `strip_sections()`, and `canonical_review.split_markdown()` all slice from it. - `normalize()` and the two workflow-YAML masks it applies, `_ACTION_PIN` and `_JOB_NEEDS`, move into the same module unchanged. The audit, `spec/audit_markdown.py`, and `scripts/carry.py` all call `normalize()`, so one shared home is what the masks need. - **The audit:** `spec/audit.py` and `spec/audit_markdown.py` import from the new module. `_atx_headings()` and `unfenced_text()` read through it too, so presence checks and region extraction split a document alike. - **`scripts/carry.py`:** `h2_headings()` and `section_span()` call the shared reader. `fence_step()` is gone. - **`scripts/canonical_review.py`:** `split_markdown()` cuts regions at the shared reader's level-two headings. - **`scripts/build_dist.py`:** include markers and heading bodies read code lines and headings from the shared reader. A body leaving a fence open is a fence the parser reads as unclosed. `_MAX_INDENT` stays only for a marker line itself. ### Running Them - `scripts/carry.py`, `scripts/build_dist.py`, and `scripts/canonical_review.py` each declare `markdown-it-py>=4` in a PEP 723 block, in `spec/audit.py`'s form. - Every caller now runs them as `uv run --no-project --script`: - the validate action and `canonical-review-sweep.yml`, which now sets up uv rather than Python; - `host-setup/menu.sh` and `host-setup/menu.ps1`, whose plain-Python helpers had no caller left and are removed; - `RESYNC.md`, `STANDUP.md`, `OPERATIONS.md`, `scripts/README.md`, `docs/token-efficiency-plan.md`, and the `local-strict-review` and `skill-lifecycle` skills, regenerated; - each script's own usage text and the commands its messages print. - **Two plain-`python3` importers stay safe.** `scripts/skills_install.py` imports `build_dist`, and `scripts/handoff.py` imports `carry`. Both modules import the shared reader lazily, on the path that reads a region, so neither importer loads markdown-it-py. ### Tests - `tests/test_build_dist.py`'s check that importing `build_dist` loads no `carried_text` now imports `skills_install` in a fresh interpreter and checks that neither `fidelity_text` nor `markdown_it` loads. That is the invariant the plain-`python3` install path relies on. `tests/test_carry.py` gains the same check for `handoff`. - The two per-line cache tests are gone, since nothing reads per line any more. The test that the accessor adds `spec/` to `sys.path` once stays. - `test_an_indented_heading_is_a_boundary_as_it_is_to_the_audit` asserted the old reader's quirk, a four-space `## ` line read as a heading. It now asserts what the parser reads: three spaces open a heading, and four open an indented code block. - `tests/test_fidelity_text.py` covers the shared reader on constructed documents, a quoted or listed heading and a fence ending a file with no final newline among them. `tests/import_probe.py` holds the import probe both laziness tests share. - CI already installs `tests/requirements.txt`, which carries `markdown-it-py`, before the suite runs. ## Behavior - The full audit sweep, every cataloged repository plus the fleet membership check, ran at develop 9f19b2a before the change and on this branch after it, both against the same hub `main`. The two outputs match line for line apart from the run stamp. - `uv run --no-project --script scripts/canonical_review.py list` and `status` print byte-identical output before and after, so every review unit key and digest is unchanged. - `uv run --no-project --script scripts/build_dist.py --check` reports the generated trees current, and a no-flag run rewrote nothing beyond the two edited skills' mirrors. - A probe compared the old and new region readers over every local Markdown file, heading boundaries, `extract_section`, and `strip_sections` alike. The fleet's own documents read identically. The only differences are in vendored third-party documents and are the parser being right where the line reader was not: a fence indented four spaces inside a list item, a fence whose closer is indented differently from its opener, and a `## ` inside an HTML comment block. ## Local Review `local-strict-review` passes ran at the `frontier` tier over the whole branch diff, each recorded before the next commit and attested after each push. The fixes they drove before the pull request opened: - A fence left open at a file with no final newline read as closed, so `build_dist.py` stopped refusing that include body. The last content line now counts. - A heading quoted in a blockquote or nested in a list item opened a region. Only top-level headings do now, which no tracked document's split depends on. - The rule for where a region ends was written three times. `sections()` now holds it. - `build_dist.py` rebuilt a code-line set the shared reader already returns. - The `code_blocks()` docstring claimed every region copier refuses an open fence. Only the include fill does, and it now says so. The `heading_body()` docstring names where an include body ends differently from a fidelity region. - `scripts/README.md`, `host-setup/README.md`, and the menu comments still described plain-Python paths. - The shared import probe moved out of a test module into `tests/import_probe.py`. ### After the Pull Request Opened The third pass, after the edit budget for the opening push was spent, and Copilot's round on that head raised the first two points below. Later passes raised the rest, and the last pass, on the current head, raised nothing: - An include body holding a fence its blockquote or list item ends, with no closing line, is refused, which the old stepper did not do. Filling one was tried and reverted. An end marker indented to a list item's content continues that item past the blank line the fill writes, so the fence swallows the marker on the next scan. Refusing is the loud outcome, no tracked source holds such a fence, and tests pin the list item and blockquote cases. The docstrings now give that reason. - The `audit_markdown.py` heading docstrings read as if only fenced headings are skipped. `_atx_headings()` now states that it reads top-level `#` headings only, and the readers built on it point there. - "which the fidelity checks read with too" read awkwardly in three docstrings, and now says "also use". - The laziness tests imported `build_dist` and `carry` directly. They now import `skills_install` and `handoff`, the real plain-`python3` importers. - `_unindented()`'s docstring said a line indented past three spaces is code or a paragraph's continuation, which is false in a list item. It now says the bound is held on the line's own indentation in every container. - `heading_body()`'s docstring, and the `skill-lifecycle` skill, said a body ends at the next heading at its level or above. They now say a top-level `#` heading, since the shared reader reads a setext heading and one in a blockquote or list item as content. ## Pre-Existing Findings, Filed - #3432: `scripts/build_dist.py` skips an include marker indented past three spaces without refusing it, so the region stays empty and `--check` exits 0. Class: pre-existing correctness defect. ## Pre-Existing Findings, Not Filed - `--check sentence-length` reports sentences this branch touched only to rename a command or a path: `.agents/skills/skill-lifecycle/SKILL.md:18` and `:19` and their generated copies, `OPERATIONS.md:40`, `RESYNC.md:77`, `host-setup/README.md:119`, `host-setup/menu.ps1:252`, `host-setup/menu.sh:394` and `:449`, `scripts/README.md:7`, `:381`, and `:385`, `scripts/build_dist.py:313` and the comment it moved into `heading_body()`, and `scripts/carry.py:420`. Class: style, on prose this change did not write. ## Deferred - #3426 covers `spec/validate.py`'s own Markdown readers and the `references()` against `_LINK_DEF` split in `spec/audit_markdown.py`. `repo-config/configure.sh` runs `spec/resolve_description.py`, which imports `validate`, under a probed Python 3.7+, and reading link targets from tokens changes what the carried-link check sees. Each needs its own comparison, so this change stops at deleting `carried_text.py`. ## Verification Each command below ran in the worktree on this branch. - `uv run --no-project --with-requirements tests/requirements.txt python -m unittest discover -s tests` at the final head -> `Ran 2872 tests ... OK (skipped=7)` - `uv run --no-project --script spec/audit.py`, before and after -> identical apart from the run stamp, rerun after the review fixes that touched region code. One downstream repository's own `main` moved between runs, which only its header line shows. - `uv run --no-project --script scripts/build_dist.py --check` -> `Generated skill distributions are current.` - `uv run --no-project --script scripts/canonical_review.py list` and `status`, before and after -> byte-identical - `uvx ruff@latest format --check .` and `uvx ruff@latest check .` -> clean - `uvx mypy@latest` -> `Success: no issues found in 76 source files` - `python3 scripts/repo_gate.py` -> `composite-actions`, `eol`, `eol-coverage`, and `sha-pin` report 0 issues - `uvx --from actionlint-py actionlint .github/workflows/canonical-review-sweep.yml` -> clean - `npx markdownlint-cli2` over the changed Markdown -> `0 issues` - `shellcheck host-setup/menu.sh` -> clean, and `host-setup/menu.ps1` parses with no errors under pwsh - `python3 spec/validate.py` -> `Spec validation OK` - The prose gate over the diff reports only `comment-added` lines, which is why this pull request carries the `comments` label. Most are comments that moved with the code they describe. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>



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 inspec/audit.py, is nowtests/test_audit_helpers.py, a unittest module with onesubTestper case.globals()swaps are nowunittest.mock.patchcalls.tests/test_audit.pyalong with the probe.--selfteststays, as a smoke check of each helper family that runs in under a second.Parsers
spec/audit.pydeclarespyyamlandmarkdown-it-pyin PEP 723 inline metadata.python-directoriesinput, the concurrency group, the schedule gate, anddependabot.yml's ecosystems are now read from the parsed document.if:condition.pyproject.toml: the audit reads only whether the file is present, never its content, so there was no read to move totomllib.The One Hand-Written Reader That Stays
The fence step and the
##region reading are still hand-written. They now live inspec/carried_text.py, which uses the standard library only.fence_step. The audit andscripts/carry.pyalso usenormalize, and the audit usesextract_sectionandstrip_sections.scripts/carry.py,scripts/build_dist.py, andscripts/canonical_review.pyrun under a plainpython3, 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.uv run --no-project --script.Registry
spec/checks.jsonregisters 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_repowalks the registry in order and callscheck_<id>for each entry. It runs the per-file checks file by file, so findings keep their order.hubflag. The hub's verbatim-section excision and the hub argument to the baseline read stay in code, since neither belongs to one check.CHECK_ID_REmoves intospec/validate.py.spec/validate.pynow checks:ground: false;registry/repos.jsonnames 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.tests/test_audit_size.pyspec/audit.pyspec/audit_markdown.pyspec/checks.jsonregisters 33 checks.Callers
spec/workflow_reuse.pyandspec/fidelity_honesty.pyimport the audit, so they declare the same libraries. Their usage lines, RESYNC.md, and docs/reusable-workflows.md now run them throughuv run --no-project --script.tests/requirements.txtgainspyyaml>=6. The merge with develop keeps Restructure the Prose Gate into Extract, Normalize, and Evaluate Layers #3411's lines beside it.yaml.Validate Action
The coverage step now runs the helper suite, with the suite's requirements installed, in place of
spec/audit.py --selftest:uvxalone reads no script's inline metadata, sospec/workflow_reuse.py --selftestgets 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.
python-directoriesvalue, or a double-quoted one with escapes, is now read the way GitHub passes it, rather than refused.interfaceDRIFT saying its contract is unread, rather than one finding per missing job.[text][ref]in the README tagline counts as a link only whererefis 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 formatteduvx ruff@latest check .->All checks passed!uvx mypy@latest->Success: no issues found in 75 source filesnpx markdownlint-cli2over 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 PASSpython3 scripts/prose_lint.py . --allow-comments --diff origin/develop-> no violations. Without--allow-comments, every reported line iscomment-added, which is why this pull request carries thecommentslabel.python3 scripts/repo_gate.py->composite-actions,eol,eol-coverage, andsha-pinall 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 plainpython3, as didscripts/canonical_review.py report.Local Review
local-strict-reviewpasses ran at thefrontiertier 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:interfacefinding.dependabot.ymlproduces onedependabotfinding.spec/validate.pyrefuses:ground: falseoutside a repo check;registry.driftnotesrunning last,split_jobsat a sibling key and at a file with no final newline, and the schedule gate reading everyon:shape.test_strip_md_links_stays_linearchecks 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.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 whichspec/carried_text.pyprimitive.Declined with evidence:
The validate action's helper-suite run duplicates the Python leg, and
--selfteststays. The brief fixes both ("runs the test module under coverage instead", "--selfteststays as a smoke check").spec/validate.pyrefuses a driftNote whose parenthesized dotted token names no check, and spec/checks.json carriesfamily,description, andspec. 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:
## X ##closing sequence reads differently for presence than for verbatim extraction;[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_jobsreturns{}for a flow-stylejobs:mapping, exactly as develop's reader did, and no contract declaresverbatimJobs.Pre-Existing Findings, Not Filed
--check sentence-lengthreports 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'scontains_description_markdown_linkstill matches brackets by hand.CHECK_ID_REreads any parenthesized lowercase dotted token as a check id, a file name such as(cspell.json)included.scripts/canonical_review.pyandscripts/carry.pyeach write the unfenced##predicate inline rather than callingspec/carried_text.py. The follow-up lane moves them.tests/test_audit_size.pyfollows the shape of the two size tests already in tests/. Those two disagree onassertLessversusassertLessEqual.tests/workflow_steps.pyandtests/test_docker_task_workflow.pyread workflows by indentation, where PyYAML is now available to the suite.reports/*.mdheaders still printpython3for their generators. The generator strings now sayuv run, so the next regeneration rewrites the headers.scripts/carry.pykeeps its own region reading (section_span,comparable_region) besidespec/carried_text.py. The follow-up lane covers it.🤖 Generated with Claude Code