Skip to content

Emit a heading where a <details> fold was - #29

Merged
peopleworks merged 1 commit into
mainfrom
fix/no-raw-html-in-markdown
Aug 22, 2026
Merged

Emit a heading where a <details> fold was#29
peopleworks merged 1 commit into
mainfrom
fix/no-raw-html-in-markdown

Conversation

@peopleworks

Copy link
Copy Markdown
Owner

Closes #28.

What was wrong

MarkdownDocumentationGenerator wrapped a seed method's source in a <details> fold:

<details>
<summary>Source code of PopulateStatuses</summary>
...
</details>

That collapses on GitHub. It collapses nowhere else. Markdig — and every other CommonMark parser — treats those lines as an HTML block, and a renderer that does not pass HTML through emits them as plain text. So in a Word export the C# survives correctly and two paragraphs of literal markup appear around it, and the fold's label stops being a label: "Source code of PopulateStatuses" was the title of a collapsed section and becomes a line of angle brackets.

It is not only Word. <details> is a GitHub convenience rather than Markdown, so it is literal text in most PDF converters and plain Markdown viewers too — and to a language model reading the file it is tokens spent on a fold it cannot open, in a format we generate largely for language models.

How it was found

By walking our output against the Markdig→docx AST mapping in @MBrekhof's mcpOffice, which documents HtmlBlock as "treated as plain text paragraph".

Everything else the generator emits already maps to a real Word equivalent — headings to Heading N styles, GFM pipe tables to real tables with a shaded header row, fenced blocks to shaded Consolas paragraphs, lists to Word numbering, **bold** and `code` to runs. This one call site was the entire difference between an extraction and a document somebody can hand to a client.

Which is why the fix is here and not an exporter. mcpOffice is backed by the DevExpress Office File API; anything of ours that wrote .docx would need the same, and this repository's whole claim is that reading an XAF application needs no DevExpress and no licence. Two MCP servers composing in an agent costs us nothing and keeps that claim intact.

The change

One call site. A #### heading under the seed's ###, and the wrapper dropped.

The cost, stated plainly: the fold is lost on GitHub, so a seed method with a long body makes that section longer to scroll. That is a real regression for one audience. It is the right trade because these files are read — by agents, by exports, by the Copilot — far more often than they are scrolled on github.com, but it is a trade rather than a free win, and it is recorded in the changelog as one.

The guard

PortableMarkdownTests scans every sample project's Markdown, in both languages, for a line that opens raw HTML outside a code fence — fence-aware, because a < at the start of a line inside a ```csharp block is source and must be left alone. Plus one test pinning that the seed source is introduced by a heading, in English and Spanish.

That is the durable half: it fails the day someone reaches for <details> again without knowing why it went.

348 tests, zero warnings.

🤖 Generated with Claude Code

https://claude.ai/code/session_01W45tzJFX3NoSrk7svtQeKT

A seed method's source was wrapped in <details>/<summary>. That fold only
opens in a renderer that passes HTML through. Everywhere else -- a Word or
PDF export, a plain Markdown viewer, a model reading the file -- the wrapper
is literal text, and the fold's label stops being a label and becomes a line
of markup.

Found by walking the generated Markdown against the Markdig converter in
mcpOffice, whose documented behaviour for an HTML block is to emit it as a
plain text paragraph. Every other construct the generator writes -- headings,
GFM pipe tables, fenced code, lists, bold, inline code -- maps to a real Word
equivalent, so this one call site was the whole distance between an extraction
and a document somebody can hand over.

The trade is honest: the fold is lost on GitHub, so a long seed body makes
that section longer to scroll. These files are read far more often than they
are scrolled.

Guarded by a fence-aware check that no sample project's Markdown, in either
language, opens a line with raw HTML outside a code fence. 348 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W45tzJFX3NoSrk7svtQeKT
@peopleworks
peopleworks merged commit 7683af5 into main Aug 22, 2026
6 checks passed
@peopleworks
peopleworks deleted the fix/no-raw-html-in-markdown branch August 22, 2026 22:35
peopleworks pushed a commit that referenced this pull request Aug 23, 2026
Closes the half of #28 that PR #29 left open: the recipe. The extraction
already survives the trip through mcpOffice's Markdown converter, and
this says how to make it — extract, hand a section file to
word_create_from_markdown, word_convert it to PDF — and what was verified
on the sample application: headings reach the outline, tables become
tables, fenced C# stays code.

It also answers the question the issue left for later: word_convert
reaches PDF, so the route ends in a client-ready document.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

A raw <details> block is the only thing between an extraction and a Word deliverable

1 participant