Expand description
The CommonMark referee — one definition of “code” for every content reader in the engine.
The engine used to carry two referees for the same markdown. Section
splitting and wiki-link scanning ran on a hand-rolled line scanner
that recognised exactly one shape of code block (a column-0 backtick
fence, closed by any backtick-prefixed line); section content
validation (crate::section_format, agent-toolbox plan 08) ran on
pulldown-cmark. They disagreed in six verified ways, and the
disagreement sat on the write path — the validator judged content the
splitter had already mis-partitioned:
- indented code blocks were not masked at all;
- legally indented fences (1–3 spaces — the normal shape inside a list item) did not open a block;
- tilde fences were unhandled;
- a closing line carrying an info string — content, per CommonMark — closed the block early;
- fences inside blockquotes were not masked;
- the opening fence was stored but never compared on close, so a
-fenced block ended on the first``` ````.
section_format’s header states the thesis this module generalises:
a reader that disagrees with the renderer every agent uses sends
repair loops that cannot converge. The parser is the referee.
Both masks preserve byte offsets and line counts exactly — every
masked byte becomes an ASCII space except \n and \r, so a caller
may scan the masked copy and slice the original by the offsets it
finds. That is the whole mechanism: boundaries come from the parser,
bytes come from the original.
Heading recognition is deliberately not widened here. A section is
still a column-0 ATX ## line and nothing else — setext headings
and indented ATX create sections nowhere. This module fixes what code
blocks hide; it does not change what counts as a heading.
§Give these functions a BODY, never a whole entity file
Frontmatter is not markdown. Handing it to a CommonMark parser
invents block structure that is not there: a YAML value that reads
as a fence opener — legal at 1–3 spaces, and honoured here since
indented fences were fixed — opens a code block that runs past the
--- terminator to end of file and blanks the entire body. Every
## heading, every [[link]], and every git conflict marker in
that file becomes invisible to whatever scans the result.
Callers holding a section body are already safe — section bodies
are frontmatter-free by construction. A caller holding a raw file
or a git blob is not, and must trim it first with
crate::entity::parser::body_after_frontmatter. This bit the
engine three times during the migration that introduced these
masks: in parse_markdown, in the git-branch ripple scanner, and
in the merge-conflict guard — the last one silently defeating a
data-integrity check. Any new caller is the fourth unless it trims.
Functions§
- closing_
fence_ if_ unterminated - When
text— a section body — ends inside an unterminated fenced code block that would swallow whatever the caller writes after it, return the closing fence that terminates it.Nonewhen the text is safely self-delimiting: balanced fences, indented code (a column-0 heading line ends it), or a fence inside a container a following column-0 line closes implicitly (blockquote, list item). - mask_
code_ blocks - Mask every CommonMark code block, preserving byte offsets and line count.
- mask_
code_ blocks_ and_ spans - Mask every CommonMark code block and every inline code span, preserving byte offsets and line count.
- parser_
options - The engine’s CommonMark dialect — one
Optionsfor every reader, so the block model the masks see is the block modelcrate::section_formatchecks against.