Skip to content

fix(content): keep blocks inside u/mark/ins, and pin four reader guards (0.4.1) - #8

Merged
baraline merged 4 commits into
mainfrom
fix/reader-block-in-inline-tags
Oct 3, 2026
Merged

baraline merged 4 commits into
mainfrom
fix/reader-block-in-inline-tags

Conversation

@baraline

@baraline baraline commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Why

0.4.0's fix 11 keeps , and as raw tags, including around blocks. Markdown has no inline tag round blocks, so a table inside one read as pipe text, and a list, a heading, a quote or a rule read as Markdown source. Paragraphs were not a fixed point.

code
left a fence open that showed the rest of the memo as code.

A review also found four guards of 0.4.0's fixes that no test caught, and a few inaccurate statements in docs/content.rst.

What

  • Reader (content/conversion.py): a , or holding a block is dropped and its blocks kept, as glpi_python_client's reader at 917f030 read them. Inside a table cell or a heading, whose blocks are one line, the tag stays; around inline content nothing changes. One walk marks the tags that hold a block, linear however deep they nest. glpi_python_client's port makes the identical change.
  • Tests:
    • the correction, for every block kind, the stray fence, nested tags and the one-line controls;
    • one test each for four guards: a second "<" before a space (fix 5), a header cell (fix 6), an anchor without href (fix 7), and an item numbered 10 or more (fix 12);
    • a count of the walk's checks;
    • the display oracle now counts an
      inside an inline element as a rule.
  • docs/content.rst corrected:
    • start values;
    • any ValueError degrading to text;
    • the CVE-2025-6069 tail, which also shows an unterminated comment or a cut-short closing tag;
    • a second write-and-read cycle has two exceptions;
    • the new behaviour, and a known hole for , and round blocks.
  • Version 0.4.1 and a CHANGELOG entry. Nothing outside easyvista_python_client.content changes.

Verification

  • The new tests fail 40 of 42 on 0.4.0's converter; the two that pass are the controls.
  • Every guard mutant (the walk, the one-line exception, popping, the block set, the stop, and the four pinned guards) fails the content suite.
  • Parity with glpi_python_client's port:
    • identical ASTs once names, messages, docstrings and the import guard are set aside;
    • 135,738 differential comparisons over both packages' test bodies and a seeded fuzz corpus, 0 mismatches.
  • Gates:
    • pytest -m "not integration" with coverage: 2085 passed, 98.93%;
    • ruff check, ruff format --check, mypy strict, unasync_build.py --check, scripts/lint_hand_written_sync.py --check;
    • sphinx -E -W, built offline.

Known follow-ups (from the review; all Minor)

  • , and round blocks remain a documented hole.
  • The converter reads start with isdecimal; a browser reads " 3", "+3" or "3abc" as 3. This is documented.
  • The module docstring and content.rst still say the fixes are to be proposed to glpi_python_client; update them once its port is released.
  • An inline wrapper (<span>, <font>, and now a dropped <u>/<mark>/<ins>) round a list, followed by inline text, reads that text into the list's last item. This is markdownify's general behaviour, the same on every tree; the fix belongs in the list converter's next-sibling handling.
  • A data-glpi-block / data-ev-block attribute already present in stored HTML is trusted by the block walk. Only hand-made or sanitiser-kept HTML carries one; clear it on read.
  • No test pins that the block walk runs after nested tables are flattened (formatting-only effect on a rare shape).
  • The documented exceptions to the second-cycle fixed point are still too narrow: two adjacent lists separated by anything that reads as nothing (a comment, an empty <div>) also change on the second cycle.
  • The start-value docs omit a negative start, a full-width digit, and a start of 10 or more digits, which reads as a paragraph.

Twin PR: baraline/glpi_python_client#40

🤖 Generated with Claude Code

baraline and others added 4 commits October 2, 2026 21:31
…ocks

Fix 11 kept these tags as raw HTML around whatever they held. Markdown
has no inline tag round blocks, so a table inside one read as pipe text,
a list, a heading, a quote or a rule as its Markdown source, paragraphs
were not a fixed point, and <u><pre>code</pre></u> left a fence open
that turned the rest of the memo into code.

A walk marks each such tag that holds a block, innermost first, stopping
at one already marked, so each is marked once however deep they nest.
convert_u drops a marked tag and keeps its blocks, as glpi_python_client
917f030 read them. Inside a table cell or a heading, whose blocks are
written on one line, the tag stays. Around inline content nothing
changes. The code is glpi_python_client's matching change, renamed.

Tests: 42 in test_fixes section 11, one per block kind and tag, the
stray fence, nested tags and the one-line controls. Against 0.4.0's
converter 40 fail; the 2 that pass are the controls. The display oracle
now counts an <hr> inside an inline element as a rule.

Docs: an [Unreleased] changelog entry, content.rst's element list and a
known hole for <b>, <em> and <s> round blocks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A review of glpi_python_client's port of this converter removed each
sub-guard of the fifteen fixes in turn and found four whose removal no
test noticed; the code is the same here. Each now has a test that fails
without it, run in disposable copies against the whole content suite:

- fix 5: before a space a second "<" keeps mdformat's single escape
  ("<< b" reads as "\<< b"); spelling only, but digests depend on it;
- fix 6: a header cell (th) is a cell, so a "|" in <kbd> or <samp>
  stays escaped and a line break in inline code splits the span;
- fix 7: an <a> without href is no link, so a table in it stays a table;
- fix 12: an ordered item numbered 10 or more indents its content by its
  bullet's width (four for "10. "), where a fixed three let a nested
  list or a second paragraph leave the item.

test_cost also counts the checks of the walk that finds blocks inside
<u>, <mark> and <ins>: the stop at a tag already marked changes no
output, only cost, so the count pins it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- start: a start that is not a decimal number counts from 1, as a
  browser counts one holding no digit; a browser reads " 3", "+3" or
  "3abc" as 3 (the HTML standard's integer rules), which the converter
  counts from 1. The display oracle reads start as the converter does,
  and now says so.
- ValueError: any ValueError raised while converting degrades the memo
  to text, not only an unreadable colspan or start. The module and
  from_transport docstrings and content.rst say so.
- CVE-2025-6069 guard: whatever follows a memo's last ">" reads as text,
  an unterminated comment and a closing tag cut short inside a link
  included, where a patched CPython drops some of it. Test 15 pins both.
- A second write-and-read cycle changes nothing more except for two
  shapes, reproduced here: adjacent lists with different bullets, and a
  fence whose info string holds a character reference. content.rst said
  it changed nothing.
- The ticket-actions skill says a <u> round a block is dropped.

Each stated behaviour was re-checked on CPython 3.13.14, and in
glpi_python_client's identical converter on 3.12.3 too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A patch release of the content reader: a <u>, <mark> or <ins> round a
block is dropped and its blocks kept, four guards of 0.4.0's fixes gain
the tests they lacked, and docs/content.rst corrects what it said about
start values, ValueError, the CVE-2025-6069 tail and a second round
trip. Nothing outside easyvista_python_client.content changes, and the
converter's writing is unchanged.

Version 0.4.1 in pyproject.toml, __version__, the public-API test and
all nine skills; the changelog section and its compare link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.92%. Comparing base (31318e6) to head (d75cda3).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@           Coverage Diff           @@
##             main       #8   +/-   ##
=======================================
  Coverage   98.92%   98.92%           
=======================================
  Files          40       40           
  Lines        2595     2614   +19     
=======================================
+ Hits         2567     2586   +19     
  Misses         28       28           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@baraline
baraline marked this pull request as ready for review October 3, 2026 07:51
@baraline
baraline merged commit 59049b6 into main Oct 3, 2026
6 checks passed
@baraline
baraline deleted the fix/reader-block-in-inline-tags branch October 3, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants