Skip to content

The prose gate hand-rolls a CommonMark block parser — seven rounds landed (HTML block state + #226 shipped); RFC: markdown-it-py as the oracle, blocking nothing #227

Description

@thrillmot

check_prose_retention.py classifies each line of a SKILL.md as frontmatter, prose or code, and it does so with a hand-rolled block parser. Six review rounds have each taught that parser exactly one more CommonMark construct, and each round's fix exposed the next gap.

The arc, as it actually happened

round construct taught how it was found
5 fenced code (already present) + indented code blocks a critic asked "what Markdown forms does the gate not model?"
7 block quotes as a container the same question again — a quote defeats both code spellings
9 a paragraph model (headings, thematic breaks, setext underlines) round 7 disclosed its own residual; a panel weaponised it
10 HTML block state — outstanding round 9's fix closes a paragraph inside an open HTML block

Every one of those was a real defect. Three were exploitable as false greens on undeclared prose cuts; the current one is the mirror — a pure addition goes red and the only remedy printed is a permanent record asserting words were lost when none were.

Measured, the current regression:

base: a <table> block with indented rows
head: base + ONE inserted line, `<!-- generated from the release notes -->`
      (strict line-superset; 0 words removed)

round 8 (27747ed)   prose: -5  code:  0   -> does not fire
round 9 (e5c5fbc)   prose: 20  code:-25   -> FIRES, demands a row for 20 words

<details> / <summary> already ship in clud-bug-collaboration, logmind and token-frugal-tooling.

The observation this issue exists to record

Every round adjudicated its fix against markdown-it-py. The oracle has been in the loop the whole time — as the test, never as the implementation. Round 9 even refuted two constructs it had been handed by asking the oracle instead of assuming.

So the question is why the gate carries a second, worse CommonMark implementation at all. If markdown-it-py's block tokens (token.map line ranges, already how every round measured agreement) drove the split directly, the entire "form N+1" class would close by construction rather than one round at a time. Divergence from CommonMark would be zero because the classification is CommonMark.

What it would cost, honestly

  • A pinned dependency in CI. The workflow already installs pytest==8.3.4 and pyyaml==6.0.2; markdown-it-py is pure Python and pins the same way.
  • Re-deriving the FLOOR bands. They are justified by an empty band between each scope's floor and the smallest real removal in that scope, measured against the current split. A new splitter means re-deriving — the same work every round in this sequence already did.
  • Re-measuring the shipping-file scope set. Four files currently move under the container reading; that set is pinned by a symmetric-difference assertion and would need re-deriving, not loosening.
  • It is a large change at the end of a long sequence, which is a real argument against doing it inside Make rewriting easy and deletion loud: check_prose_retention.py #218 and the reason this is a separate issue.

What this issue is NOT

Not a reason to hold #218. After round 9 the false-green divergence — CommonMark says code, the gate says prose — is 0.28%, down from 12.83%, with 12 minimal forms remaining, all filed (#226) or over-charging rather than under-charging. The gate closes every failure mode found in nine rounds of adversarial review. Shipping it makes the repository better than not shipping it; this issue makes it better still.

The immediate HTML-block regression is being fixed narrowly first, because a pure addition going red is not something to ship even briefly.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions