Skip to content

Follow-up: deferred review findings from PR #705 #709

Description

@philcunliffe

Deferred, non-blocking findings from the triage of PR #705 (head 3c6876e29ccee577e040116da4e03c67d5c1cd9e), which replaced pandoc with in-process marked in the report renderer. Triage re-derived heading-id parity independently against a real pandoc 3.1.11 binary, one heading per document: 107/109 cases at parity, all gates green (npm test 3919 pass / 0 fail, typecheck, npm pack --dry-run, llp-ref-hygiene 11/11), component blocks byte-for-byte modulo the documented href rewrite, table alignment byte-identical, and a 500-document adversarial fuzz through renderReports with no crash. Each item below is a preference or documented-gap class divergence, not a production defect; none degrades a report in the authored vocabulary.

1. Heading ids for raw tags whose name starts with br diverge from pandoc (new at triage; the round-4 record states the opposite)

Pandoc 3.1.11's stringify maps any raw inline HTML token starting with the case-sensitive prefix <br to a space, measured via -t native:

  • ## A <brand> B mints pandoc a---b; this renderer mints a--b (both of my parity misses are this family)
  • ## A <brand>x</brand> B mints pandoc a--x-b; ours a-x-b (the close tag starts </b, so only the open tag counts)
  • ## A <bra> B and ## A <br-x> B likewise mint a---b in pandoc
  • <BR> is correctly excluded on both sides (case-sensitive prefix), and <span>/<custom>/<q> contribute nothing on both sides

The round-4 review comment and the code comment above headingId in src/core/reports/render.js both claim the regex must not be <br[^>]*> "so it does not swallow <brand>", presented as matching pandoc. Measurement shows the opposite: pandoc does swallow <brand> into a space. Candidate one-class fix: /<br[^>]*>/g (case-sensitive), which restores parity for the whole family while still excluding <BR> and closing tags; the comment needs correcting either way. Exposure: a raw unknown tag starting with br inside a heading, which the report vocabulary never produces.

2. Deferred skip from PR #705 round 4: JS \s matches three separators pandoc drops

Verified as characterised. ## A &#x2028; B (and U+2029, U+FEFF): pandoc mints a--b, this renderer a---b, because the decoded separator lands in the \s branch and mints a hyphen. The literal-authored spellings cannot be fixed in headingId at all: literal U+2028/U+2029 break upstream in marked's block parser (no heading token is emitted; the line renders as a paragraph), and literal U+FEFF collapses with adjacent spaces to a-b. A class-level fix closes only the entity half, so the skip disposition was right; recording the gap is what remains (item 4).

3. Deferred skip from PR #705 round 4: image-alt-text heading ids

Verified as characterised. Pandoc slugs Markdown-image alt text (## ![alt text](x.png) mints alt-text; ## Before ![alt text](x.png) after mints before-alt-text-after) but emits no id for a raw-HTML <img> heading, which this renderer already matches. marked emits byte-identical HTML for both spellings (measured directly), so no string-level discriminator exists in headingId; a correct fix must walk marked's heading tokens and take the image tokens' text in the heading renderer override. The authored vocabulary contains no images at all, so exposure is a heading nobody has written yet, and the degradation is a missing or shorter id, not lost content.

4. LLP 0208 does not record the heading-id known gaps

llp/0208-report-renderer-drops-pandoc.decision.md records the footnote, task-list, and syntax-highlighting consequences, but items 1 to 3 above live only in the PR #705 thread. The doc promises heading ids "so existing in-page anchors keep resolving" without naming the three narrow classes where that is not exact. LLP 0208 is Status: Active, so anything beyond an editorial addition should follow the extension conventions.

Backlink: PR #705, triage after review round 4 (the last of the maintainer-granted rounds +2).

Metadata

Metadata

Assignees

No one assigned

    Labels

    neutral:fixDelegate this issue to neutral for an autonomous fix attempt (reproduce -> fix -> PR)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions