Repository navigation
Read Carried Markdown Through markdown-it-py and Delete carried_text - #3431
Conversation
The audit, carry.py, build_dist.py, and canonical_review.py now split a document at the headings and code blocks markdown-it-py reads, through spec/fidelity_text.py, which replaces spec/carried_text.py and also holds normalize() and its workflow-YAML masks. The three scripts declare markdown-it-py inline and every caller runs them through uv run --no-project --script. build_dist and carry import the reader lazily, so skills_install.py and handoff.py, which import them under a plain python3, load no third-party library. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A heading quoted in a blockquote or nested in a list item no longer opens a region, since neither opens a section of the document. A fence left open at a file with no final newline now reads as open, so build_dist.py refuses that body again. The import probe both laziness tests share moves to tests/import_probe.py, and the READMEs and menu comments that still described a plain-Python path now describe uv. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fidelity_text.sections() returns each level-two heading with the line that ends its region, and section_span, strip_sections, and canonical_review.split_markdown all slice from it. build_dist.py takes its code lines from the shared reader, and its docstring names where an include body ends differently from a fidelity region. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
heading_texts() and ordered_headings() now say a quoted or listed heading is content. The open-fence refusal names every container, blockquote included, and a test pins that case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved moderate findings remain in fence handling and the lazy-import regression test, along with documentation nits.
2 open issues
What changed in this PR
This pull request replaces the shared hand-written Markdown reader with a markdown-it-py-based parser, updates dependent tooling and callers to use it through uv, and removes spec/carried_text.py.
Changes:
- Adds
spec/fidelity_text.pyfor shared headings, code blocks, sections, and normalization. - Updates audit, carry, distribution, canonical-review tooling, workflows, menus, documentation, and generated skill mirrors.
- Adds parser and lazy-import tests while preserving plain-Python importer behavior.
Review findings:
[P1]Moderate —scripts/build_dist.py: unclosed fences that end with a blockquote or list container should not be rejected; add the requested regression test.[P2]Nit —scripts/build_dist.py,scripts/canonical_review.py, andscripts/carry.py: correct the extra “with” in the changed docstrings.[P2]Nit —spec/audit_markdown.py: document that heading checks only inspect top-level headings.[P2]Nit —spec/fidelity_text.py: align the fence-refusal explanation with container boundaries.[P2]Moderate —tests/test_carry.py: probehandoffto verify the production lazy-import path.
| File | Reviewed change |
|---|---|
tests/test_fidelity_text.py |
Tests shared Markdown parsing and section behavior. |
tests/test_carry.py |
Tests carry’s lazy Markdown-reader import behavior. |
tests/test_canonical_review.py |
Updates canonical-review command expectations. |
tests/test_build_dist.py |
Tests parser-based generation and lazy imports. |
tests/import_probe.py |
Provides fresh-interpreter import checks. |
STANDUP.md |
Updates carry commands to use uv. |
spec/fidelity_text.py |
Adds the shared Markdown parser and fidelity helpers. |
spec/carried_text.py |
Removes the obsolete hand-written reader. |
spec/audit.py |
Imports fidelity helpers from the new reader. |
spec/audit_markdown.py |
Uses the shared reader for headings and fenced content. |
scripts/README.md |
Documents dependencies and updated commands. |
scripts/carry.py |
Uses lazy shared-reader access for section operations. |
scripts/canonical_review.py |
Uses shared section boundaries and adds script metadata. |
scripts/build_dist.py |
Uses shared code-block parsing and adds script metadata. |
RESYNC.md |
Updates resync carry commands to use uv. |
OPERATIONS.md |
Updates local build and canonical-review commands. |
host-setup/README.md |
Documents lazy uv requirements for menu actions. |
host-setup/menu.sh |
Replaces Python menu execution with uv script execution. |
host-setup/menu.ps1 |
Replaces Python menu execution with uv script execution. |
docs/token-efficiency-plan.md |
Updates skill regeneration instructions. |
.github/workflows/canonical-review-sweep.yml |
Sets up uv and runs canonical review through it. |
.github/skills/skill-lifecycle/SKILL.md |
Updates the generated GitHub skill mirror. |
.github/skills/local-strict-review/SKILL.md |
Updates the generated GitHub review mirror. |
.github/actions/validate/action.yml |
Runs validation commands through uv. |
.claude-plugin/fleet-skills/skills/skill-lifecycle/SKILL.md |
Updates the generated Claude skill mirror. |
.claude-plugin/fleet-skills/skills/local-strict-review/SKILL.md |
Updates the generated Claude review mirror. |
.claude-plugin/fleet-skills/.source-digests/skill-lifecycle |
Refreshes the generated skill digest. |
.claude-plugin/fleet-skills/.source-digests/local-strict-review |
Refreshes the generated skill digest. |
.agents/skills/skill-lifecycle/SKILL.md |
Updates the authored skill lifecycle commands. |
.agents/skills/local-strict-review/SKILL.md |
Updates the authored canonical-review commands. |
Review effort: Lite
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #3431 +/- ##
===========================================
- Coverage 80.81% 80.76% -0.05%
===========================================
Files 23 23
Lines 8859 8839 -20
===========================================
- Hits 7159 7139 -20
Misses 1700 1700
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:
|
_atx_headings() states that it reads top-level `#` headings only, and the readers built on it point there. The marker indentation comment and the menu prerequisite comment now say what they mean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |
build_dist.py refuses only a top-level fence left open, since the blank line the fill writes before the end marker ends a blockquote or a list item, and a fence it holds, in the destination too. CodeBlock records whether a container holds the block. The laziness tests now import skills_install and handoff, the real plain-python3 importers, rather than the modules they import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An end marker indented to a list item's content continues that item past the blank line the fill writes, so a fence the item leaves open swallows the marker on the next scan. build_dist.py again refuses every fence left open, and tests pin the list item and blockquote cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |
|
Answers to the findings with no thread in Copilot's round on c83c885 (3), #3431 (review)
|
heading_body() and the skill-lifecycle skill now say a body ends at the next top-level `#` heading, since a setext heading and one in a blockquote or list item are content to the shared reader. The marker indentation docstring no longer claims how CommonMark reads such a line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A recorded local strict-review pass covers head |
…xes to Main (#3434) ## Summary Promotes the pull requests merged into develop since release 2.0.1158. - [#3422](#3422): `drive-pr` and `backlog-burndown` have every draft of a pull request body go in a file named for its repository and branch. Two lanes sharing one `pr-body.md` had published each other's drafts. - [#3423](#3423): in `pr_review.py`, an earlier partial round outranks a head round reading `unknown`, printing `coverage=PARTIAL` and exiting 42. - [#3427](#3427): the prose gate takes run-block heredoc bodies from its patched Bash lexer's heredoc tokens and lexes each alone, so an apostrophe in a body no longer hides later comments. Inline Markdown comments are numbered with code spans masked. The gate's size ceiling moves from 1800 to 1840 lines, as the maintainer decided on that pull request. Two edge cases are deferred to #3429 and #3430, and a pre-existing one is filed as #3428. - [#3431](#3431): deletes `spec/carried_text.py` and reads carried Markdown regions through markdown-it-py in the new `spec/fidelity_text.py`. `carry.py`, `build_dist.py`, and `canonical_review.py` carry PEP 723 metadata, and every caller runs them as `uv run --no-project --script`. The full audit sweep is identical before and after. The `validate.py` remainder is #3426, and a pre-existing include-marker gap is #3432. - [#3433](#3433): `pr-review-conduct` and `scripts/README.md` say exactly when the earlier-partial path exits 42, following #3423. Closes #3412 Closes #3413 Closes #3414 Closes #3425 ## Constituent coverage Each change this promotion carries had coverage on its own pull request into develop, at its merged head: | Pull request | Merged head | Coverage | | --- | --- | --- | | [#3422](#3422) | `b645b429` | attested local pass, and a Copilot table naming exactly the changed files, `coverage=table` | | [#3423](#3423) | `3f893b65` | attested local pass, and a carried Copilot table, `coverage=carried:table` | | [#3427](#3427) | `2511b62b` | attested local pass, and a carried Copilot table, `coverage=carried:table` | | [#3431](#3431) | `92755285` | attested local pass, `coverage=local` | | [#3433](#3433) | `cceba3af` | attested local pass, `coverage=local` | 🤖 Generated with [Claude Code](https://claude.com/claude-code)


The follow-up #3416 named: the audit,
scripts/carry.py,scripts/build_dist.py, andscripts/canonical_review.pynow split a document at headings and code blocks markdown-it-py reads, andspec/carried_text.py, the last hand-written fence reader they shared, is gone.What Changes
One Reader, Now a Parser
spec/fidelity_text.pyreplacesspec/carried_text.py. It parses block structure only, CommonMark plus tables.headings()reads top-level ATX headings,code_blocks()andcode_lines()read fenced and indented code at any depth, andsections()is the one place a level-two region's extent is decided.section_span(),extract_section(),strip_sections(), andcanonical_review.split_markdown()all slice from it.normalize()and the two workflow-YAML masks it applies,_ACTION_PINand_JOB_NEEDS, move into the same module unchanged. The audit,spec/audit_markdown.py, andscripts/carry.pyall callnormalize(), so one shared home is what the masks need.spec/audit.pyandspec/audit_markdown.pyimport from the new module._atx_headings()andunfenced_text()read through it too, so presence checks and region extraction split a document alike.scripts/carry.py:h2_headings()andsection_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_INDENTstays only for a marker line itself.Running Them
scripts/carry.py,scripts/build_dist.py, andscripts/canonical_review.pyeach declaremarkdown-it-py>=4in a PEP 723 block, inspec/audit.py's form.uv run --no-project --script:canonical-review-sweep.yml, which now sets up uv rather than Python;host-setup/menu.shandhost-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 thelocal-strict-reviewandskill-lifecycleskills, regenerated;python3importers stay safe.scripts/skills_install.pyimportsbuild_dist, andscripts/handoff.pyimportscarry. 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 importingbuild_distloads nocarried_textnow importsskills_installin a fresh interpreter and checks that neitherfidelity_textnormarkdown_itloads. That is the invariant the plain-python3install path relies on.tests/test_carry.pygains the same check forhandoff.spec/tosys.pathonce stays.test_an_indented_heading_is_a_boundary_as_it_is_to_the_auditasserted 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.pycovers 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.pyholds the import probe both laziness tests share.tests/requirements.txt, which carriesmarkdown-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 listandstatusprint byte-identical output before and after, so every review unit key and digest is unchanged.uv run --no-project --script scripts/build_dist.py --checkreports 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, andstrip_sectionsalike. 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-reviewpasses ran at thefrontiertier 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:build_dist.pystopped refusing that include body. The last content line now counts.sections()now holds it.build_dist.pyrebuilt a code-line set the shared reader already returns.code_blocks()docstring claimed every region copier refuses an open fence. Only the include fill does, and it now says so. Theheading_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.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:
audit_markdown.pyheading 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.build_distandcarrydirectly. They now importskills_installandhandoff, the real plain-python3importers._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 theskill-lifecycleskill, 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
scripts/build_dist.pyskips an include marker indented past three spaces without refusing it, so the region stays empty and--checkexits 0. Class: pre-existing correctness defect.Pre-Existing Findings, Not Filed
--check sentence-lengthreports sentences this branch touched only to rename a command or a path:.agents/skills/skill-lifecycle/SKILL.md:18and:19and their generated copies,OPERATIONS.md:40,RESYNC.md:77,host-setup/README.md:119,host-setup/menu.ps1:252,host-setup/menu.sh:394and:449,scripts/README.md:7,:381, and:385,scripts/build_dist.py:313and the comment it moved intoheading_body(), andscripts/carry.py:420. Class: style, on prose this change did not write.Deferred
spec/validate.py's own Markdown readers and thereferences()against_LINK_DEFsplit inspec/audit_markdown.py.repo-config/configure.shrunsspec/resolve_description.py, which importsvalidate, 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 deletingcarried_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 testsat 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 ownmainmoved 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 listandstatus, before and after -> byte-identicaluvx ruff@latest format --check .anduvx ruff@latest check .-> cleanuvx mypy@latest->Success: no issues found in 76 source filespython3 scripts/repo_gate.py->composite-actions,eol,eol-coverage, andsha-pinreport 0 issuesuvx --from actionlint-py actionlint .github/workflows/canonical-review-sweep.yml-> cleannpx markdownlint-cli2over the changed Markdown ->0 issuesshellcheck host-setup/menu.sh-> clean, andhost-setup/menu.ps1parses with no errors under pwshpython3 spec/validate.py->Spec validation OKcomment-addedlines, which is why this pull request carries thecommentslabel. Most are comments that moved with the code they describe.🤖 Generated with Claude Code