Skip to content

v3.7.0 — coverage guard

Choose a tag to compare

@syswave-dev syswave-dev released this 31 Jul 08:22
· 20 commits to main since this release

Coverage guard for page-builder one-pagers (closes #46)

Readability commits to a single best candidate container. On the one-pagers page builders emit, the article is a flat list of sibling blocks whose prose sits several levels deep — the candidate score dilutes with nesting depth, so a shallow paragraph-rich block near the top outscores the far larger content below it, and the rest is dropped. The output is well-formed markdown, so the loss is silent. Measured on one such page: 10,503 of 336,670 characters, 3.1% coverage.

The guard re-converts the container that holds the body instead — effectively an auto-written select.content, using the same conversion path a recipe takes.

Fires only when all of these hold:

  1. no recipe select.content, no forced static extractor, not the comments path
  2. cleaned body ≥ 20,000 characters
  3. coverage < 10%
  4. a single container dominates the body text
  5. the recovered candidate is ≥ 3× larger and has ≥ 5 paragraphs

Condition 4 is the discriminator: it separates one article split across siblings from many separate teasers, and it is what keeps listing pages out.

Calibration. 85 live pages — forum threads, comment-heavy blogs, wikis, long single-document pages (GPL-3.0, RFC 9110, MDN, Python docs), shops, listing homepages, landing pages. It fires on 1 of 85, and on 0 of 12 forum threads. The first false positive appears at roughly twice the shipped thresholds.

Safety. The guard can only grow a result, never shrink it. Any error degrades to previous behavior. Opt out with the new PULLMD_COVERAGE_GUARD=off. Every intervention carries source: coverage-guard and records coverage, body size, gain and the share of the body the recovered container actually holds in metadata.extractorReason, so an operator can judge afterwards whether it was warranted. A select.content recipe still wins outright.

1038 tests passing.

Full changelog: https://github.com/AeternaLabsHQ/pullmd/blob/main/CHANGELOG.md