Skip to content

Latest commit

 

History

History
1534 lines (1236 loc) · 104 KB

File metadata and controls

1534 lines (1236 loc) · 104 KB
Template FunctionResource
ResourceType Function
Name MarkdownToNotebook
Description Convert a literate-markdown document into a Wolfram notebook using a template
ContributedBy Nikolay Murzin, Claude (Anthropic)
Keywords
markdown
literate programming
function repository
notebook
documentation
templates
Categories
Notebook Documents & Presentation
SeeAlso
ResourceFunction
ResourceObject
CreateNotebook
DefineResourceFunction
Links
[Wolfram/AccessibleColors - an example paclet authored entirely in markdown](https://resources.wolframcloud.com/PacletRepository/resources/Wolfram/AccessibleColors/)
[YAML front matter - the frontmatter convention](https://jekyllrb.com/docs/front-matter/)
[Quarto cell options - the #| option syntax](https://quarto.org/docs/computations/execution-options.html)
[CommonMark - the base markdown spec](https://commonmark.org/)
EntrySymbol MarkdownToNotebook

This document is the source of truth for the resource function it describes. The frontmatter above is the Function Repository metadata; the Definition section below inlines the implementation from a local .wl file; and the example cells are evaluated (with caching) to build the resource's documentation. Running the function on this very file reproduces its own definition notebook, so it publishes itself.

Definition

The implementation is a single plain Wolfram Language (.wl) file, inlined here at conversion time via the file option - a general mechanism: any code cell with #| file: path is replaced by the contents of that local file or URL, resolved relative to this document. The deployed resource therefore carries the implementation inline:

#| file: MarkdownToNotebook.wl

Details & Options

  • The source is a local file path, an http(s) URL, or a raw markdown string.
  • The layout is the document's own Template frontmatter key - FunctionResource, FunctionResourceReview, Symbol, Guide, TechNote, Paclet, Example, NotebookTemplate, or Default - so the source declares its own layout. The full documentation page-type roster is also covered: Format, ServiceConnection, Device, Interpreter, Entity, Character, Message, Program, Workflow, and WorkflowGuide pages each map ## sections to their type's section styles (ImportExportSection, ServiceSubsection, DeviceSubsection, InterpreterSection, EntitySection, ProgramSection, workflow steps with their circled counters, ...), stamp the matching Categorization entity type and ref/format/-style URI kind, and ship in the paclet directory $docTemplateDirectories maps for them (ReferencePages/Formats, .../Services, ..., Workflows, WorkflowGuides).
  • FunctionResource fills the official FunctionResourceDefinition.nb template (keeping its docked Deploy/Submit toolbar); Symbol and Guide fill the DocumentationTools authoring templates; the reference subtypes synthesize their authoring pages natively on the shipped Reference.nb stylesheet; Default maps headings and code to standard notebook styles.
  • In a FunctionResource notebook a code span is what the definition notebook toolbar's Template Input button makes of the same text - each lowercase identifier a template argument in italics, a documented symbol a link, the resource's own name plain, no whitespace tokens - and a *variable* in prose is that same italic formula, all set in the toolbar's Source Sans Pro: the formatting the Function Repository reviewers ask for. A span of markdown or YAML syntax, such as #| eval: false, keeps its literal form, and a double-backtick span is literal code.
  • FunctionResourceReview is the FunctionResource notebook as the Function Repository reviewers send it back: a SubmissionReview: frontmatter mapping (SubmissionID, OriginalName, ...) carries the submission under review, which the toolbar's Submit Update reads to update that submission. NotebookToMarkdown writes this template from a reviewed notebook, so the reviewers' edits come back as markdown.
  • A blockquote whose first line opens with [!REVIEW] or [!COMMENT] is a definition notebook comment - a reviewer's ReviewerComment or the author's AuthorComment reply - with the rest of that line naming the commenter and the time, as in > [!COMMENT] Name, 2026-10-10 12:00 UTC. A reviewer comment read from a notebook keeps its whole cell in a #| comment: directive before the quote, so the signed comment returns unchanged, while an author's reply is plain text, edited in the markdown and rebuilt from it; the cells around a comment keep the CellIDs they have without it.
  • NotebookTemplate produces a Wolfram template notebook - what CreateNotebook["Template"] opens and GenerateDocument fills - with the template tagging and the authoring toolbar. Its code cells are never evaluated at conversion time. A slot is written as ordinary code, TemplateSlot["name"] or TemplateSlot["name", default] (an integer name is positional), inline in prose or inside a code cell, and TemplateExpression[expr] is evaluated when the document is generated; both become the framework's slot boxes. A Slots: frontmatter mapping - indented name: default lines of Wolfram Language - declares a default once for every occurrence of that slot (an inline default still wins), and with every slot defaulted the toolbar's Generate fills the template as converted. The cell option #| behavior: ExcludeCell (or the same <!-- #| ... --> directive before a paragraph or heading) drops that cell - on a heading, its whole group - from the generated document.
  • The frontmatter is a YAML-style key: value header fenced by --- lines at the very top of the document - the front matter convention static-site generators use - carrying the resource metadata. Its keys mirror the chosen template's slots (Name, Description, Keywords, Categories, ContributedBy, SeeAlso, Links, and so on), so the author fills metadata, never cell styles.
  • The optional second argument selects the result: omitted (or "Notebook") returns the Notebook, "Association" returns the parsed structure, a .nb file name writes the notebook, and a .md file name writes a markdown twin - the same document with every evaluated output rasterized to an image beside it.
  • The function takes six options:
Option Default
"Evaluate" True evaluate the example cells and keep their output; False leaves them as input only, which a self-referential document passes to convert its own source without re-running its own examples
"PreserveSource" False with True, stamps the original markdown source into the produced notebook's TaggingRules (under the "MarkdownToNotebook" key, as <|"Source" -> ..., "Template" -> ...|>) so the .nb is self-contained: rendered view + the source it came from in one file, useful for tooling that wants the source side-loaded. The default is False so the notebook is a strictly-rendered artifact and any post-conversion edit to the cells shows up faithfully when NotebookToMarkdown walks it back to markdown - the right semantics for diffing the edited .nb against the .md it was built from. NotebookToMarkdown does NOT read this stash by design
"LightDark" Automatic the appearance the evaluated outputs (and the markdown twin's rasterized images) are rendered in: "Light" or "Dark". Automatic keeps the ambient $lightDark setting (default light)
"EvaluateSeparator" Automatic where the per-document evaluation context is reset while the example cells run in sequence - see the section below. The host session's `Global`` context is never touched
"MathFont" None the font family LaTeX math is typeset in. None (like "" and Automatic) keeps the front end's native math font, which is deterministic across machines; a family name such as "Latin Modern Math" forces the Computer-Modern look
"UseCache" True reuse cached example outputs from the persistent store described below. False re-evaluates every example cell in the document, ignoring what is stored
  • A Flag frontmatter key flags the whole document and a code cell's #| flag: option flags that cell, with one of the documentation build's flags - Future, Excised, Obsolete, Temporary, Preview, or Internal - the front end's Futurize / Excise toolbar buttons, written as the build's banner cell.
  • LaTeX math is typeset by the Wolfram/Parser paclet. If it is not already installed, the first call that needs it installs it from the Paclet Repository, which requires network access; install it yourself beforehand to avoid that. When it cannot be reached the function issues MarkdownToNotebook::noparser once per session and falls back to ImportString[..., "TeX"], which handles plain math but mis-decodes non-ASCII characters.
  • Evaluated example outputs are cached as a PersistentSymbol per cell at the "Local" PersistenceLocation, keyed by a cumulative hash of the preceding cells, so re-runs reuse them across sessions.
  • Manage that cache the standard way: PersistentObjects["MarkdownToNotebook/ExampleOutput/*", "Local"] lists it, DeleteObject clears it, and $PersistencePath / PersistenceLocation relocate it.
  • An input cell shows its code as typed. To show a sub-expression typeset instead - a Quantity as its unit form, an integral in TraditionalForm - ask for it, in either of two ways. A Typeset: frontmatter mapping lists pattern: form lines (_Quantity: StandardForm), or holds one rule or a rule list as a scalar, and the outermost sub-expression of each input that a pattern matches is typeset. A comment naming a box form right before a sub-expression marks just that one: f[(*TraditionalForm*)Integrate[x^2, x], 2]. The comment is inert when the code runs as text, so the markdown stays runnable, and the typeset form is of the expression as written, never its value, so evaluating the notebook's input cell runs exactly the markdown's code. Typesetting is formatting: it applies whether or not the examples are evaluated.
  • The source lives on GitHub, which renders the markdown directly: github.com/WolframInstitute/MarkdownToNotebook.
  • Running the function on this document - Get the .wl, then MarkdownToNotebook["MarkdownToNotebook.md", "MarkdownToNotebook.nb"] - reproduces this very definition notebook; that is the loop build.wls runs.

Individual code cells carry their own options as #| comment lines at the top of the cell - the Quarto cell-option convention - one key: value per line:

Option Effect
eval evaluate the cell and keep its output (the default); eval: false shows the code without running it
file replace the cell body with the contents of a local file or URL
screenshot rasterize a produced notebook to an inline image
tear render the output as a torn-paper screenshot; a number sets the visible height in points
flag mark the cell with a build flag - Future, Excised, Obsolete, Temporary, Preview, or Internal
input input: false drops the Input cell and keeps only the captured output - the Demonstration snapshot convention, where the snapshot is the rendered Manipulate panel at a fixed parameter state
excluded excluded: true appends the "Excluded" cell style; the resource scraper strips the cell from the published resource but it stays in the source .nb (the cell-tools Mark as Excluded button)
hidden hidden: true adds the "HiddenMaterial" modifier style and sets CellOpen -> False; the cell is closed on the published web page but open in the downloadable example notebook (the cell-tools Mark as Hidden button)
typeset show matching sub-expressions of the input typeset - typeset: _Quantity -> StandardForm, a list of such rules, or {p1, p2} -> form for alternatives; tried before the document's Typeset: rules, and typeset: None turns those off for the cell

Usage

MarkdownToNotebook[source] converts a literate-markdown source into a Wolfram notebook and returns the Notebook expression.

MarkdownToNotebook[source, "Association"] returns the parsed structure as an Association instead of the notebook.

MarkdownToNotebook[source, "file.nb"] writes the notebook to the .nb file and returns the file.

MarkdownToNotebook[source, "file.md"] writes a markdown twin of the document, with each evaluated output rasterized to an image beside it, and returns the file.

Basic Examples

Convert a markdown string into a notebook. The result is the explicit Notebook expression:

MarkdownToNotebook["# Title\n\nA paragraph.\n\n## Section\n\nMore text."]

A whole notebook has no faithful inline form, so to show the produced notebook rendered in the documentation, the cell whose output is the notebook carries the #| screenshot: true option - which rasterizes the notebook to an image - and pairs it with #| tear: N to crop the image to the top N points with a torn-paper edge. Here both options sit inside the markdown source on a cell whose output is a literal Notebook expression, so the syntax is visible alongside the rendered effect:

#| screenshot: true
MarkdownToNotebook["## Headline\n\n```wl\n#| screenshot: true\n#| tear: 100\nNotebook[{Cell[\"Hi\", \"Title\"], Cell[\"A paragraph.\", \"Text\"]}]\n```"]

Prose formatting, inline code, and lists all carry through:

#| screenshot: true
MarkdownToNotebook["# Notes\n\nA *key* idea, with inline `code`:\n\n- first\n- second\n- third"]

Scope

The source is a file path, an http(s) URL, or a raw string, and the layout comes from the Template frontmatter key. The subsections below cover the markdown the converter understands and the results it returns.

Frontmatter

A --- - delimited block at the very top of the document is the frontmatter: key: value lines (a YAML-ish header) that carry the resource metadata - the Name, Description, Template, Keywords, and so on. Everything below it is content. Read the parsed metadata back with "Association":

MarkdownToNotebook["---\nName: Demo\nTemplate: Default\nKeywords: [alpha, beta]\n---\n# Demo\n\ntext", "Association"]["Metadata"]

Headings and prose

# becomes a Title, ## a Section, ### a Subsection; blank-line-separated paragraphs become Text:

#| screenshot: true
MarkdownToNotebook["# Title\n\n## Section\n\n### Subsection\n\nA paragraph of text."]

Inline formatting

Inline `code` is formatted code; *italic* (or _italic_) is emphasis, **bold** (or __bold__) is bold, and ~~struck~~ is strikethrough; a double-backtick literal is a verbatim span and a $x$ span is inline TeX math. A backslash escapes the next punctuation, and underscore emphasis is matched only at word boundaries so a snake_case name in prose is left untouched:

#| screenshot: true
MarkdownToNotebook["Inline `Range[3]`, *italic*, **bold**, ~~struck~~, ``verbatim``, and the math $\\sqrt{a^2 + b^2}$."]

Display math

A $$ … $$ block (on its own line, or fenced across lines) becomes a centered DisplayFormula cell - the standard style for a displayed equation:

#| screenshot: true
MarkdownToNotebook["The Pythagorean identity:\n\n$$ a^2 + b^2 = c^2 $$"]

Links

Three link forms are supported:

  • [label](url) makes a prose hyperlink.
  • [Symbol]() infers a documentation reference (a backticked label with no target).
  • [`Symbol`](url) makes a code-styled explicit link.

For example:

#| screenshot: true
MarkdownToNotebook["See [Range]() and the [Wolfram site](https://www.wolfram.com)."]

Lists and tables

-, *, or + lines become bullet items, 1./2. lines a numbered list, and - [ ]/- [x] lines a task list (a ballot-box glyph); a GitHub-style pipe table becomes a grid:

#| screenshot: true
MarkdownToNotebook["1. first\n2. second\n\n- [x] done\n- [ ] todo\n\n| x | y |\n|---|---|\n| 1 | 2 |"]

Blockquotes

Consecutive > lines become a quote, set off by a left rule and indent:

#| screenshot: true
MarkdownToNotebook["> A quoted remark,\n> carried across two lines."]

Evaluated code cells

A fenced wl cell is evaluated and its output kept (then cached); a cell may carry options as #| key: value comment lines at the top - #| eval: false shows the code without running it, #| boxes: true reads the body as a literal box expression (RowBox, GridBox, TemplateBox, TooltipBox, ...) and splices it into a Cell[BoxData[…], "Input"] unchanged - no parse to RowBoxes, no evaluation; #| screenshot: true rasterizes a produced Notebook to an inline image, #| tear: h adds the torn-paper screenshot edge, #| flag: … marks the cell with a build flag, #| file: path replaces the body with the contents of a local file or URL. Two cells - one evaluated, one held - put the option syntax visibly in the markdown source:

#| screenshot: true
MarkdownToNotebook["## Evaluated\n\n```wl\nRange[5]^2\n```\n\n## Held\n\n```wl\n#| eval: false\nRange[5]^2\n```"]

Box-literal cells

#| boxes: true reads the body as a literal box expression - RowBox, StyleBox, GridBox, TemplateBox, TagBox, TooltipBox, ... - and splices it into a Cell[BoxData[…], "Input"] unchanged. No front-end reparse to RowBoxes, no evaluation; the rendered cell shows whatever the boxes say. Pair a regular cell (whose body goes through the reparser) with a boxes cell to see the difference in the same screenshot:

#| screenshot: true
MarkdownToNotebook["## Reparsed\n\n```wl\nx + y\n```\n\n## Box literal\n\n```wl\n#| boxes: true\nRowBox[{\"x\", StyleBox[\" + \", FontColor -> RGBColor[0.8, 0.043, 0.008]], \"y\"}]\n```"]

Inlining a file

A code cell whose first line is #| file: path is replaced by the contents of that local file or URL, resolved relative to the source - the mechanism the Definition section above uses to pull in MarkdownToNotebook.wl. Here a snippet written to disk is inlined and evaluated:

#| screenshot: true
Export[FileNameJoin[{$TemporaryDirectory, "snippet.wl"}], "Range[5]^2", "Text"]; NotebookPut[MarkdownToNotebook[Export[FileNameJoin[{$TemporaryDirectory, "inc.md"}], "## Inlined\n\n```wl\n#| file: snippet.wl\n```", "Text"]]]

Inlining an image

A markdown image ![alt](path) inlines an image - a local file or URL, resolved relative to the source. The image's title is a raw cell-style override: here "ExampleImage" styles the function's headline image (markdown in, a notebook out) as a documentation figure:

MarkdownToNotebook: markdown in, a notebook out

The title defaults to Output; the special title "papertear" keeps Output and adds the front end's Convert To > Paper Tear cell effect for a torn-screenshot look (the same effect a code cell's #| tear: option gives its output, used under Applications below).

Returning a notebook, an association, or a file

Omitted (or "Notebook") returns the Notebook; "Association" returns the parsed structure for inspection; any other string writes the notebook to that file and returns it. The whole association exposes the notebook, the metadata, the section list, and the chosen template:

MarkdownToNotebook["---\nName: Demo\nKeywords: [alpha, beta]\n---\n# Demo", "Association"]

Writing a markdown twin

Targeting a markdown file writes a GitHub-renderable twin of the document - the same prose and code, but with each evaluated output rasterized to a PNG beside it (under an images/ folder next to the target). MarkdownToNotebook-out.md in this repository is exactly that twin, produced this way. Here a small literate doc is converted to a twin and the resulting markdown read back, showing the output image spliced in after its code cell:

Module[{dir = CreateDirectory[]}, MarkdownToNotebook["## Squares\n\n```wl\nRange[5]^2\n```", FileNameJoin[{dir, "twin.md"}]]; Import[FileNameJoin[{dir, "twin.md"}], "Text"]]

Flagging a document or cell

The documentation build's flags - the front end's Futurize / Excise toolbar buttons - mark a page or cell as Future, Excised, Obsolete, Temporary, Preview, or Internal. A Flag frontmatter key flags the whole document; a code cell's #| flag: option flags that one cell. Each becomes the build's banner cell at the top of the page. Here the same #| flag: option syntax used by the converter is visible inside the markdown source, applied to one cell of a tiny demo:

MarkdownToNotebook["## Demo\n\n```wl\n#| flag: future\nRange[5]^2\n```", "Association"]["Notebook"]

A paclet Symbol page with Flag: Future added to its frontmatter renders with the giant pink "FUTURE" banner the front end shows for unreleased pages:

#| screenshot: true
#| tear: 200
MarkdownToNotebook[StringReplace[
    Import["https://raw.githubusercontent.com/sw1sh/AccessibleColors/main/docs/Symbols/WCAGContrastRatio.md", "Text"],
    "---\nTemplate: Symbol" -> "---\nFlag: Future\nTemplate: Symbol"
]]

Options

Evaluate

By default every wl example cell is evaluated and its output kept. With the default, the converted notebook carries the evaluated output:

#| screenshot: true
MarkdownToNotebook["## Squares\n\n```wl\nRange[5]^2\n```"]

"Evaluate" -> False builds the notebook from the same source but leaves the example cells unevaluated - the input stays, the output is dropped. A self-referential document (one whose example converts its own source) passes it so converting itself does not re-run its own examples without end:

#| screenshot: true
MarkdownToNotebook["## Squares\n\n```wl\nRange[5]^2\n```", "Evaluate" -> False]

EvaluateSeparator

Controls when the per-document evaluation context is reset while example cells are run in sequence. A reset clears every symbol the document has defined in its private MTNB$… context and ClearSystemCache[]s, and the cumulative-hash chain that the example cache is keyed by also restarts - so cache validity is local to one section instead of the whole notebook. The host session's `Global`` context is never touched.

  • "EvaluateSeparator" -> Automatic (default) - reset at every --- thematic break and at every heading (at any level), so each (sub)section starts with a clean context. Two cells under the same heading share state; the next heading or --- wipes it.
  • "EvaluateSeparator" -> None - never reset; the whole notebook shares one context and one cumulative-hash chain. This is the historical M2N behaviour and is useful when one section depends on a symbol defined further up.
  • "EvaluateSeparator" -> All - reset before every executable cell. Each cell runs in a fresh context and its cache key depends only on its own code (so two cells with identical text always cache-hit, but neither can see definitions from prior cells).
#| screenshot: true
MarkdownToNotebook["## A\n\n```wl\nx = 1\n```\n\n```wl\nx + 10\n```\n\n## B\n\n```wl\nValueQ[x]\n```", "EvaluateSeparator" -> Automatic]

Applications

MarkdownToNotebook fills every Wolfram Repository definition notebook from plain markdown, so authors never edit notebook cell styles by hand. The samples below live under examples/ in the repository; examples/build.wls builds each one and DeployResource-style CloudDeploy[ResourceObject[nb], …, Permissions -> "Public"]s it under a stable public URL, so every link below resolves to the live deployed notebook.

Function Resource

The ReverseAddSequence document is a complete Function Repository submission - usage signature, examples, options, and the function body itself - kept in one markdown file. Converting it fills the official FunctionResource notebook with its docked Deploy/Submit toolbar, and the build step deploys it publicly to the cloud. The #| screenshot: true cell option rasterizes the produced notebook and #| tear: 200 gives it a torn-paper screenshot look, keeping the top 200 points of output visible above the tear:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/FunctionResource/ReverseAddSequence.md"]

Paclet

The published Wolfram/AccessibleColors paclet - PacletInfo.wl, the guide page, every symbol reference page, and the Paclet Repository submission notebook - is built this way end to end. Here its guide page is converted straight from the markdown on GitHub:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/sw1sh/AccessibleColors/main/docs/Guides/AccessibleColors.md"]

The WolframParser paclet - a fast, composable parser library that pairs a GrammarRules DSL compiled via FunctionCompile with a Parsec-style combinator core - is a larger Paclet example: guide, twelve symbol pages, six tutorials, the LaTeX-math parser, and the resource-submission notebook all driven from the same docs/ markdown tree; the built guide is deployed here:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/sw1sh/WolframParser/main/docs/Guides/WolframParser.md"]

The PAdic paclet - p-adic valuations, the non-archimedean norm, digit expansions in $\mathbb{Q}_p$, and Hensel lift - is a math-heavy Paclet example whose guide and symbol pages use inline $…$ LaTeX throughout; the built guide is deployed here:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/sw1sh/PAdic/main/docs/Guides/PAdic.md"]

Example

The Example template fills the Example Repository definition notebook. The PrimeSpiralPoints sample ships a "Points" content element and a short gallery of derived plots; deployed here:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/Example/PrimeSpiralPoints.md"]

The Discrete-Time Quantum Walk sample is a longer Example doc: it derives the Hadamard-coin walk, plots the two-horned interference distribution against the classical Gaussian, and bundles the simulator as a "Step" content function; deployed here:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/Example/QuantumWalk.md"]

Data

The Data template fills the Data Repository definition notebook. The Seventeen Wallpaper Groups sample bundles the classification table, the point-group and lattice columns, and a worked Euler-characteristic check; deployed here:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/Data/WallpaperGroups.md"]

Prompt

The Prompt template fills the Prompt Repository definition notebook for one of three resource types - Persona, Function, or Modifier. The AdaLovelace sample is a Persona prompt whose ## Prompt section is the system message and whose ## Chat Examples and ## Basic Examples invoke the persona through LLMSynthesize and ChatEvaluate; deployed here:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/Prompt/AdaLovelace.md"]

Demonstration

The Demonstration template fills the Demonstrations Project authoring notebook, complete with its docked HELP / SAVE / UPDATE THUMBNAIL AND SNAPSHOTS / TEST IMAGE SIZE / UPLOAD toolbar. The Bloch Sphere with a Quantum Gate Sequence sample uses one ## Caption paragraph, the ## Initialization definitions (the gate matrices and the Bloch projection), a single ## Manipulate cell, and three ## Snapshots panels - the structure the Demonstrations review requires. A snapshot is the same Manipulate rendered at a specific control state, not a different graphic, so the idiomatic pattern factors the Manipulate into a named helper demo[p1_:…, p2_:…, …] in ## Initialization and each ## Snapshots cell is a call like demo[v1, v2, …] with #| input: false so only the rendered panel appears (no code, no In[]/Out[] label):

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/Demonstration/BlochSphereGates.md"]

Overview

The Overview template fills the doc-tools overview page - the paclet's high-level table of contents that links into its Guide, Symbol, and Tutorial pages. Heading depth picks the cell style (# → TOCDocumentTitle, ## → TOCChapter, ### → TOCSection, #### → TOCSubsection, ##### → TOCSubsubsection); a bulleted list under a heading becomes TOC leaves one level deeper; each entry's markdown link ([Label](paclet:Pub/Pkg/<kind>/Name)) is rendered as a clickable ButtonBox. The worked sample is the AccessibleColors Overview:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/sw1sh/AccessibleColors/refs/heads/main/docs/Tutorials/Overview.md"]

Computational Essay

The ComputationalEssay template fills the Wolfram Computational Essay genre - an intellectual story told through narrative prose interleaved with short, captioned Wolfram Language inputs. The produced notebook uses the Default.nb stylesheet (no resource scraper, no docked submit toolbar) and is deployable to the Notebook Archive, Wolfram Community, or a public CloudObject. The How Random Is Pi? sample probes the digits of pi for the kind of patterns a normal number ought not have - a chi-square test, a 2D random walk on the digits - in five short segments; deployed here:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/ComputationalEssay/PiIsMostlyRandom.md"]

Book

The Chapter template fills the Wolfram Book Tools chapter notebook - the structure used by long-form course / book material with TOC navigation, exercises, vocabulary, Q&A, and back matter. The IntroToQuantumComputing example is a worked two-chapter book modelled on the first two lessons of the Wolfram Quantum Framework course, augmented with the book-style back matter the original notebooks did not have. Each chapter compiles independently; the build script also stamps ExpressionUUIDs on heading cells (so the TOC buttons have stable jump targets), generates Contents.nb in the same shape WolframBookTools WBTMakeContentsFromDialog writes, and (--publish) deploys the whole book to the cloud - chapter 1 here, chapter 2 here, and the TOC. A chapter in miniature, carrying the same back-matter sections:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["---\nTemplate: Chapter\nName: Superposition\n---\n\n# Superposition\n\nA qubit holds a combination of both basis states.\n\n```wl\nNormalize[{1, 1}]\n```\n\n## Vocabulary\n\n- **qubit** - a two-level quantum system\n\n## Exercises\n\n1. Normalize the state {1, I}.\n\n## Summary\n\nA qubit state is a unit vector in a two-dimensional space."]

Beyond Symbol / Guide / TechNote pages, the full documentation page-type roster converts too: Format, ServiceConnection, Device, Interpreter, Entity, Character, Message, Program, Workflow, and WorkflowGuide pages, each mapping its ## sections to the type's own cell styles and shipping in the type's paclet directory (ReferencePages/Formats, …/Services, …, Workflows). The DocPageExamples example is a minimal REAL paclet carrying one page of each: its kernel registers a MAZE import/export format, a fully local ServiceConnect["Lorem"] service, a simulated DeviceOpen["RandomSignal"] device, and a WallpaperGroup entity store, defines the MazeParse::ragged message, and ships a mazegen wolframscript CLI - so every page's example cells evaluate genuinely at build time:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/Paclet/DocPageExamples/docs/MAZE.md", "Evaluate" -> False]

Notebook Template

The NotebookTemplate template produces the notebook CreateNotebook["Template"] opens: GenerateDocument fills its slots and evaluates the result, so nothing is evaluated at conversion time. The Wolfram Model Report sample is a report template in the style of the Wolfram Physics Project's registry builds: TemplateSlot["Rule"], TemplateSlot["InitialCondition"], TemplateSlot["EvolutionSteps"] and TemplateSlot["ShownSteps"] all take their defaults from the frontmatter's Slots: mapping, so Generate produces a full report of the classic {{x, y}, {x, z}} -> {{x, z}, {x, w}, {y, w}, {z, w}} model without any input, a TemplateExpression stamps the generation date into the byline, and an authoring note marked #| behavior: ExcludeCell never reaches a generated report:

#| screenshot: true
#| tear: 200
MarkdownToNotebook["https://raw.githubusercontent.com/WolframInstitute/MarkdownToNotebook/refs/heads/main/examples/NotebookTemplate/WolframModelReport.md"]

Properties and Relations

The Wolfram Language already reads markdown into a plain notebook - Import["doc.md", "Notebook"], or ImportString[markdown, {"Markdown", "Notebook"}] for a string. MarkdownToNotebook builds on that idea and adds the resource layer: the layout chosen from frontmatter, the metadata slots, cell options, and evaluated and cached example cells. The built-in import of the same snippet gives just the bare cells (it does parse inline TeX math, the same $x$ convention used here):

ImportString["# Title\n\nText with inline math $\\sin x$.", {"Markdown", "Notebook"}]

FunctionResource then fills the same template CreateNotebook["FunctionResource"] opens (publishable with ResourceSubmit), and Symbol/Guide fill the DocumentationTools templates DocumentationBuild turns into reference pages.

Possible Issues

A string that is neither a URL nor an existing file is treated as raw markdown, so a mistyped path silently parses as content rather than erroring:

MarkdownToNotebook["nonexistent.md", "Association"]["Sections"]

Neat Examples

A whole Function Repository submission fits in one string: frontmatter picks the template and carries the metadata, ## Definition is the implementation, and ## Usage and ## Basic Examples fill the documentation slots - so the document is the resource, and converting it yields the publishable notebook:

#| screenshot: true
#| tear: 220
MarkdownToNotebook["---\nTemplate: FunctionResource\nName: Greet\nDescription: Greet someone by name\n---\n\n## Definition\n\n```wl\nGreet[name_String] := \"Hello, \" <> name\n```\n\n## Usage\n\nGreet[*name*] returns a greeting for *name*.\n\n## Basic Examples\n\n```wl\nGreet[\"world\"]\n```"]

Because this very document is itself such a literate source - its ## Definition inlines MarkdownToNotebook.wl and its frontmatter is the resource metadata - running the function on it reproduces this definition notebook, so the function publishes itself.

Tests

Each wl cell in this section is an explicit VerificationTest[code, expected, TestID -> …] expression that becomes one Input cell in the resource's VerificationTests slot (the docked Run Tests button evaluates them). These are the regressions the converter has hit; tests.wls in the repo runs the same cells out-of-band by parsing this section, so the in-notebook button and the CI script run the same assertions from a single source.

Basic conversion returns a Notebook expression:

VerificationTest[
    Head @ MarkdownToNotebook["# Hi\n\nA paragraph."],
    Notebook,
    TestID -> "basic conversion returns a Notebook"
]

A <code>[Symbol]()</code> reference in a Usage signature carries a paclet link on the head (regression: the link silently disappeared when the <code> rule was rewritten to wrap the whole span in one InlineFormula instead of recursing on the inside). Since issue #20 the head wraps in the typed PackageLink / RefLink TemplateBox (not a bare ButtonBox) so the doc center and CloudPublish resolve it:

VerificationTest[
    ! FreeQ[
        MarkdownToNotebook["---\nTemplate: Symbol\nName: Range\nContext: System`\nPaclet: System\nURI: System/ref/Range\n---\n\n## Usage\n\n<code>[Range]()[$n$]</code> gives a list."],
        TemplateBox[{Cell[TextData["Range"]], _String, ___}, "PackageLink" | "RefLink", ___]
    ],
    True,
    TestID -> "<code>[Symbol]()…</code> in Usage carries a paclet link on the head"
]

Math in a usage signature is read argument by argument: a braced list $\{a_1, b\}$ becomes the literal braces and commas around template arguments, as {$a_1$, $b$} would, and math with an operator ($n \geq 1$) is typeset, so no $ is left in the usage line:

VerificationTest[
    With[{u = FirstCase[
        FirstCase[
            MarkdownToNotebook["---\nTemplate: Symbol\nName: Foo\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/ref/Foo\n---\n\n## Usage\n\n<code>[Foo]()[$\\{a_1, b\\}$, $n \\geq 1$]</code> does.\n", "Evaluate" -> False],
            Cell[t_, "Usage", ___] :> t, None, Infinity],
        Cell[BoxData[b_], "InlineFormula", ___] :> b, None, Infinity]},
        {Cases[u, s_String /; StringContainsQ[s, "$"], {0, Infinity}],
         ! FreeQ[u, RowBox[{"{", RowBox[{SubscriptBox[StyleBox["a", "TI"], StyleBox["1", "TR"]], ",", " ", StyleBox["b", "TI"]}], "}"}]],
         ! FreeQ[u, RowBox[{StyleBox["n", "TI"], "\[GreaterEqual]", "1"}]]}],
    {{}, True, True},
    TestID -> "a braced list or operator math in a usage signature leaves no $ in the usage line"
]

A bullet list with indented continuation lines folds each continuation into the preceding item, so a three-bullet list with two-line continuations is three items, not six (regression: the list parser used to break at the continuation, producing alternating one-item lists and stray paragraphs):

VerificationTest[
    Length @ Cases[
        MarkdownToNotebook["## Demo\n\n- First bullet\n  that wraps.\n- Second bullet\n  also wraps.\n- Third bullet."],
        Cell[_, "Notes" | "Item" | "Bullet", ___],
        Infinity
    ],
    3,
    TestID -> "multi-line bullets fold into single items (3, not 6)"
]

A backslash-escaped punctuation character inside <code>...</code> is a markdown source escape and unescapes before the cell is built - so <code>\*</code> lands in the notebook as a literal *, not as \* (regression: the <code> wrapper let markdown formatting through but skipped the backslash-unescape step, leaving the literal backslash in the cell content):

VerificationTest[
    FreeQ[
        MarkdownToNotebook["A <code>\\*</code> reference."],
        "\\*"
    ],
    True,
    TestID -> "`<code>\\*</code>` unescapes the markdown `\\*` to a literal `*` in the cell"
]

The unescape preserves Wolfram named-character escapes (\[CircleTimes], \[Theta], ...) - they share the leading \[ with the markdown \[ punctuation escape, so the Wolfram-name pattern is matched first and rebuilt verbatim (regression: the punctuation rule ate the leading \, leaving a stray [CircleTimes] that the inferred-link parser then auto-linked into a ButtonBox):

VerificationTest[
    ! FreeQ[
        MarkdownToNotebook["A <code>a \\[CircleTimes] b</code> reference."],
        "\[CircleTimes]"
    ],
    True,
    TestID -> "`<code>\\[Name]</code>` preserves the Wolfram named-character escape"
]

The #| excluded: true cell option appends the "Excluded" style after the cell's base style; the scraper strips any Cell[..., "Excluded", ...] from the published resource but the cell stays in the authoring .nb:

VerificationTest[
    MatchQ[
        FirstCase[
            MarkdownToNotebook["## Demo\n\n```wl\n#| excluded: true\nRange[3]\n```", "Evaluate" -> False],
            Cell[_, "Input", ___],
            Missing[],
            Infinity
        ],
        Cell[_, "Input", "Excluded", ___]
    ],
    True,
    TestID -> "#\\| excluded: true appends \"Excluded\" after the base \"Input\" style"
]

A heading carries the same inline markup prose does - backticks become an InlineFormula cell, bold / italic / math / links render the same way they would in a paragraph (regression: heading text was stored as a plain string and emitted as Cell["A foo heading", "Section"] with the backticks rendered literally):

VerificationTest[
    MatchQ[
        FirstCase[
            MarkdownToNotebook["## A `foo` heading\n\nText.", "Evaluate" -> False],
            Cell[_, "Section", ___],
            Missing[],
            Infinity
        ],
        Cell[TextData[{"A ", Cell[BoxData["foo"], "InlineFormula", ___], " heading"}], "Section", ___]
    ],
    True,
    TestID -> "headings parse inline markup (backticks -> InlineFormula)"
]

Bold / italic / strike runs containing other inline markup ("$x$", "$n$", "code", "$y$") recursively re-enter inlineTextData and distribute the formatting onto each resulting element via wrapStyle; an InlineFormula cell inside a bold span gets the FontWeight -> "Bold" option on the cell itself (regression: the bold rule used to capture the inner string verbatim and emit StyleBox["$x$", "Bold"], so math / code inside bold rendered as literal $x$):

VerificationTest[
    (* the inline-math cell carries FontWeight -> Bold (alongside the
       FontSize the math style adds); matched loosely so option order /
       the math-font wrapper don't matter *)
    ! FreeQ[
        MarkdownToNotebook["Some **$1$** prose.", "Evaluate" -> False],
        Cell[BoxData["1" | StyleBox["1", ___]], "InlineFormula", o___] /; ! FreeQ[{o}, FontWeight -> "Bold"]
    ],
    True,
    TestID -> "bold containing math wraps the InlineFormula with FontWeight -> Bold"
]

A real-world document (thousands of lines) parses without hitting the default $RecursionLimit of 1024 - the line-by-line blockLoop and its splitters are tail-recursive but Wolfram does not optimize tail calls, so parseBlocks now lifts the limit to scale with the input (regression: a ~1500-line tutorial like SymmetrySubcontextTutorial.md aborted with TerminatedEvaluation[RecursionLimit]):

VerificationTest[
    Head @ MarkdownToNotebook[
        StringJoin[Table["## H" <> ToString[i] <> "\n\nP" <> ToString[i] <> "\n\n", {i, 1500}]],
        "Evaluate" -> False
    ],
    Notebook,
    TestID -> "parseBlocks scales $RecursionLimit with input - a 1500-block doc parses"
]

The "PreserveSource" option defaults to False so a notebook the converter writes does not carry the source in its TaggingRules - any later edit to the cells is the new truth, visible in the walker's diff:

VerificationTest[
    FreeQ[MarkdownToNotebook["# Hi"], "MarkdownToNotebook" -> _],
    True,
    TestID -> "\"PreserveSource\" defaults to False - no stash in TaggingRules"
]

With "PreserveSource" -> True, the source is stamped under the "MarkdownToNotebook" tagging key byte-exact:

VerificationTest[
    With[{src = "## Demo\n\nA paragraph.\n"},
        First[
            Cases[
                MarkdownToNotebook[src, "PreserveSource" -> True],
                ("MarkdownToNotebook" -> v_) :> v,
                Infinity
            ],
            <||>
        ]["Source"] === src
    ],
    True,
    TestID -> "\"PreserveSource\" -> True stamps the source under \"MarkdownToNotebook\""
]

The #| hidden: true cell option adds the "HiddenMaterial" modifier style and CellOpen -> False so the cell renders closed on the published web page (and open in the downloadable example notebook):

VerificationTest[
    MatchQ[
        FirstCase[
            MarkdownToNotebook["## Demo\n\n```wl\n#| hidden: true\nRange[3]\n```", "Evaluate" -> False],
            Cell[_, "Input", ___],
            Missing[],
            Infinity
        ],
        Cell[_, "Input", "HiddenMaterial", ___, CellOpen -> False, ___]
    ],
    True,
    TestID -> "#\\| hidden: true adds \"HiddenMaterial\" + CellOpen -> False"
]

The Overview template maps the markdown heading hierarchy to TOC* cells (# → TOCDocumentTitle, ## → TOCChapter, ### → TOCSection, ...) and turns bulleted list items under a heading into TOC leaves one level deeper:

VerificationTest[
    Sort @ DeleteDuplicates @ Cases[
        MarkdownToNotebook["---\nTemplate: Overview\nName: T\n---\n\n## Chapter\n\n- [Foo](paclet:X/Y/ref/Foo)\n- [Bar](paclet:X/Y/ref/Bar)\n\n### Section\n"],
        Cell[_, s_String /; StringStartsQ[s, "TOC"], ___] :> s,
        Infinity
    ],
    {"TOCChapter", "TOCDocumentTitle", "TOCSection"},
    TestID -> "`Template: Overview` emits TOCDocumentTitle/TOCChapter/TOCSection cells"
]

Inline math with a bare sign as a script argument ($\sigma_-$) attaches the sign as a subscript - the same SubscriptBox the braced \sigma_{-} form produces - instead of leaking a loose _ - (Wolfram/Parser issue #26):

VerificationTest[
    ! FreeQ[
        MarkdownToNotebook["A $\\sigma_-$ operator.", "Evaluate" -> False],
        SubscriptBox[_, "-"]
    ],
    True,
    TestID -> "inline math: bare-sign subscript $\\sigma_-$ attaches as SubscriptBox"
]

A ket with a power ($|0\rangle^{\otimes 10}$) maps to the system Ket template (full-height, stretchy delimiters) with the power lifted onto it, instead of leaking a literal ^ or short detached bars (Wolfram/Parser issues #26 + #28):

VerificationTest[
    ! FreeQ[
        MarkdownToNotebook["A $|0\\rangle^{\\otimes 10}$ ket.", "Evaluate" -> False],
        SuperscriptBox[TemplateBox[_, "Ket", ___], _]
    ],
    True,
    TestID -> "inline math: ket power |0>^{...} becomes a Ket-template superscript"
]

A sized delimiter ($\big(x\big)$) scales with the surrounding text via FontSize -> r Inherited, never the absolute Magnification (which renders smaller than the body text under any viewer zoom; Wolfram/Parser issue #27):

VerificationTest[
    With[{nb = MarkdownToNotebook["A $\\big(x\\big)$ group.", "Evaluate" -> False]},
        FreeQ[nb, Magnification -> _] && ! FreeQ[nb, StyleBox["(", FontSize -> _]]
    ],
    True,
    TestID -> "inline math: \\big( sizes with FontSize -> Inherited, not Magnification"
]

The last-resort ImportString[..., "TeX"] path (used only when the Wolfram/Parser paclet is unreachable) strips the spacing / sizing tokens that import would otherwise leak as literal text - \!, the empty \left./\right., and the \big/\Big sized-delimiter prefixes - while leaving big operators like \bigcup intact (issue #25):

VerificationTest[
    {texImportStrip["a\\!b"], texImportStrip["\\big(x\\big)"], texImportStrip["\\bigcup A"]},
    {"ab", "(x)", "\\bigcup A"},
    TestID -> "texImportStrip drops \\!/\\big but keeps \\bigcup"
]

On the same fallback the built-in importer maps \hbar to an empty box - the reduced Planck constant simply vanishes - so it is swapped for \hslash, which imports to the identical \[HBar] (U+210F) glyph the primary parser emits and that the inverse maps back to \hbar; every other Greek/physics symbol imports fine, so only \hbar needs the swap (issue #61):

VerificationTest[
    {texImportStrip["E = \\hbar \\omega"],
     ! FreeQ[texBoxesViaImport["\\hbar"], s_String /; StringContainsQ[s, "\[HBar]"]]},
    {"E = \\hslash \\omega", True},
    TestID -> "\\hbar imports as its glyph instead of a blank box on the ImportString fallback (issue #61)"
]

On the primary path \cdots needs a pre-substitution of its own. Alone it parses correctly, but inside a juxtaposition run (a\cdots b, or \mathrm{Tr}[\,\cdots\,]) the parser's product rule matches the bare \cdot prefix and the leftover s becomes an italic identifier - a centered dot and a loose "s" where \[CenterEllipsis] belongs. Feeding the parser the glyph instead (longest command first, so the shorter \cdot rule cannot claim it) renders it correctly in every position, and the inverse maps \[CenterEllipsis] back to \cdots (sibling of the \cdot fix, issue #68):

VerificationTest[
    {FreeQ[texBoxes["a\\cdots b"], "\[CenterDot]"],
     ! FreeQ[texBoxes["\\mathrm{Tr}[\\,\\cdots\\,]"], "\[CenterEllipsis]"],
     ! FreeQ[texBoxes["a\\cdot b"], "\[CenterDot]"]},
    {True, True, True},
    TestID -> "\\cdots stays a centered ellipsis in a juxtaposition run (issue #68)"
]

A single-backtick inline code span that reads as a filesystem path, URL, dotted filename (`~/.prime/config.json`), or hyphen-joined identifier (`claude-opus-4-7`) is kept verbatim instead of reparsed as Wolfram code - otherwise the front end tokenizes its / . ~ - as operators (ReplaceAll, Dot, Subtract, ...) and it renders with stray operator spacing (config . json, claude - opus - 4 - 7). Genuine WL inline code (`Range[5]`, `x_1`) still reparses to boxes:

VerificationTest[
    {inputBoxes["~/.prime/config.json"], inputBoxes["config.json"], inputBoxes["claude-opus-4-7"], Head @ inputBoxes["Range[5]"]},
    {"~/.prime/config.json", "config.json", "claude-opus-4-7", RowBox},
    TestID -> "inline code that reads as a path / id stays verbatim, real WL still boxes"
]

A ## Usage statement whose head is an inferred link ([Head]()[args]) or an italic instance variable (*m*[...]) parses into a signature+description pair, so multiple statements render as separate usage lines instead of collapsing into one run-on cell (a Symbol page with an auto-linked head used to fall back to a single squished cell):

VerificationTest[
    {usageStatement["[Manifold]()[*{x1}*] represents a manifold."][[1, 1]],
     usageStatement["*m*[\"prop\"] extracts a property."][[1, 1]]},
    {"Manifold[{x1}]", "m[\"prop\"]"},
    TestID -> "usage head: inferred-link [Head]()[args] and italic *m*[...] parse into pairs"
]

The "Double Usage Line" style is named for the new line it puts after the code: the signature and its description sit on separate lines, joined by a \[LineSeparator] (soft line break) - exactly what the palette's DoubleUsageLinesInsert writes. A plain space would squish the description onto the signature's line:

VerificationTest[
    MemberQ[usageLineItems[{"Foo[x]", "does a thing"}], "\[LineSeparator]"],
    True,
    TestID -> "Double Usage Line: signature and description separated by \\[LineSeparator]"
]

A Guide's ### subsection under ## Functions becomes a GuideFunctionsSubsection that heads its own CellGroupData group (heading + its function cells). A flat subsection cell among sibling function cells renders in the desktop FE but is silently dropped by DocumentationBuild, so the built guide loses every subsection divider:

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Guide\nName: G\nContext: Pub`Pkg`\nPaclet: Pub/Pkg\nURI: Pub/Pkg/guide/G\n---\n\n## Functions\n\n### Group A\n- `Foo` does foo\n\n### Group B\n- `Bar` does bar\n"]},
        {Length @ Cases[nb, Cell[_, "GuideFunctionsSubsection", ___], Infinity],
         Length @ Cases[nb, Cell[CellGroupData[{Cell[_, "GuideFunctionsSubsection", ___], ___}, _], ___], Infinity]}
    ],
    {2, 2},
    TestID -> "guide ### subsections each head their own CellGroupData group"
]

A hub guide builds the documentation hierarchy (the collapsible sidebar tree) by pointing at sub-guides. DocumentationBuild reads parent→child edges only from ButtonBox[…, BaseStyle -> "Link", ButtonData -> "paclet:…/guide/…"] links sitting in GuideFunctionsSubsection / GuideTOCLink cells - NOT from TemplateBox "RefLinkPlain" links or links in GuideText/GuideMoreAbout. Two authoring channels emit the scanned form: a whole-heading guide link ### [Sub](paclet:…/guide/Sub) (becomes a GuideFunctionsSubsection link) and a ## Guides index list (each item a GuideTOCLink):

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Guide\nName: Hub\nContext: Pub`Pkg`\nPaclet: Pub/Pkg\nURI: Pub/Pkg/guide/Hub\n---\n\n## Functions\n\n### [Algebra](paclet:Pub/Pkg/guide/Algebra)\n- `Foo` does foo\n\n## Guides\n\n- [NumberTheory](paclet:Pub/Pkg/guide/NumberTheory) primes\n"]},
        {Cases[nb, Cell[BoxData[ButtonBox[_, ___, ButtonData -> u_, ___]], "GuideFunctionsSubsection", ___] :> u, Infinity],
         Cases[nb, Cell[c_, "GuideTOCLink", ___] :> First[Cases[c, (ButtonData -> u_) :> u, Infinity], None], Infinity]}
    ],
    {{"paclet:Pub/Pkg/guide/Algebra"}, {"paclet:Pub/Pkg/guide/NumberTheory"}},
    TestID -> "guide hierarchy: ### [Sub](…/guide/Sub) heading and ## Guides index emit nav ButtonBox links"
]

Inside ## Functions, a --- separator becomes the palette's Delimiter - the thin Cell["\t", "GuideDelimiter"] rule that visually separates groups of related listings. Whether a listed symbol links to its paclet ref page or the system ref page (paclet:ref/Sym) is inferred entirely from context - no markup: a name that resolves to a System`` built-in (and the paclet does not redefine) links to the system page with an italic label; a paclet symbol links to the paclet's own page. A bare ``` TensorContract``` (a WL built-in) infers topaclet:ref/TensorContract, while Foo` (not a built-in) stays on the paclet:

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Guide\nName: G\nContext: Pub`Pkg`\nPaclet: Pub/Pkg\nURI: Pub/Pkg/guide/G\n---\n\n## Functions\n\n- `Foo` does foo\n\n---\n\n- `TensorContract`, `TensorReduce` two built-ins\n"]},
        {Length @ Cases[nb, Cell["\t", "GuideDelimiter", ___], Infinity],
         Sort @ Cases[nb, u_String /; StringStartsQ[u, "paclet:ref/"], Infinity],
         Length @ Cases[nb, u_String /; StringStartsQ[u, "paclet:Pub/Pkg/ref/Foo"], Infinity],
         Length @ Cases[nb, TemplateBox[{Cell[TextData[StyleBox["TensorContract", ___, FontSlant -> "Italic", ___]], ___], "paclet:ref/TensorContract", ___}, ___], Infinity]}
    ],
    {1, {"paclet:ref/TensorContract", "paclet:ref/TensorReduce"}, 1, 1},
    TestID -> "guide listing: built-in vs paclet ref inferred from context, no markup"
]

A guide listing joins its symbol chips with a scalar ", " separator. The list form Riffle[units, {", "}] interposes its separator cyclically and appends a trailing copy after a lone element, so a single-symbol item - or the last symbol of an enumeration - would carry a stray ", " ahead of its \[LongDash] description; NotebookToMarkdown echoes it and the next build re-appends, drifting an extra comma into the rendered text on every save-back. A one-symbol item must therefore carry no separator, and two symbols on one line exactly one between them:

VerificationTest[
    {Count[FirstCase[MarkdownToNotebook["---\nTemplate: Guide\nName: G\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/guide/G\n---\n\n## Functions\n\n- `Foo` does foo\n"], Cell[TextData[td_], "GuideText", ___] :> td, {}, Infinity], ", "],
     Count[FirstCase[MarkdownToNotebook["---\nTemplate: Guide\nName: G\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/guide/G\n---\n\n## Functions\n\n- `Aa`, `Bb` do stuff\n"], Cell[TextData[td_], "GuideText", ___] :> td, {}, Infinity], ", "]},
    {0, 1},
    TestID -> "guide listing: scalar comma separator leaves no trailing comma after chips"
]

The frontmatter parser folds a flow list, key: ["a", "b", ...], that wraps across several physical lines back into one logical line before reading it - a long Links: or Authors: list routinely wraps. Brackets inside "..." are literal (a markdown link label is full of them), so only unquoted [ ] count toward the fold. Without it a wrapped list parses as a truncated scalar plus one garbage key: value per continuation line (every URL carries a :), and the External Links section then shows only the first entry:

VerificationTest[
    Lookup[
        First @ extractFrontmatter["---\nName: R\nLinks: [\"[a](https://x/1)\",\n\"[b](https://y/2)\",\n\"[c](https://z/3)\"]\nType: Paclet\n---\n\nbody\n"],
        "Links"],
    {"[a](https://x/1)", "[b](https://y/2)", "[c](https://z/3)"},
    TestID -> "frontmatter: a flow list wrapped across physical lines parses fully"
]

A Paclet page's main description prose fills from ## Basic Description when there is no ## Usage, and its example surface carries only the sections actually written - not the eight empty Basic Examples..Neat Examples placeholder subsections the generic Function template scaffolds:

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Paclet\nName: P\nPaclet: Pub/P\n---\n\n## Basic Description\n\nhello world desc\n"]},
        {! FreeQ[nb, s_String /; StringContainsQ[s, "hello world desc"]],
         Cases[nb, Cell[t_String, "Subsection", ___] /; MemberQ[{"Basic Examples", "Scope", "Neat Examples"}, t] :> t, Infinity]}],
    {True, {}},
    TestID -> "Paclet: LongDescription fills from ## Basic Description; empty example subsections dropped"
]

A TechNote source builds with the modern Tutorial entity type (DocumentationBuild gives it the same TechNote page styling), and a Guide's RelatedTutorials: frontmatter fills the Tech Notes section's GuideTutorial placeholders - one link per entry:

VerificationTest[
    {FirstCase[MarkdownToNotebook["---\nTemplate: TechNote\nName: T\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/tutorial/T\n---\n\n## Overview\n\ntext\n"], Cell[et_String, "Categorization", o___] /; (CellLabel /. Flatten[{o}]) === "Entity Type" :> et, "none", Infinity],
     Length @ Cases[MarkdownToNotebook["---\nTemplate: Guide\nName: G\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/guide/G\nRelatedTutorials: [Foo, Bar]\n---\n\n## Functions\n\n- `X` does x\n"], Cell[_, "GuideTutorial", ___], Infinity]},
    {"Tutorial", 2},
    TestID -> "TechNote -> Tutorial entity type; Guide RelatedTutorials -> GuideTutorial cells"
]

A Symbol page's Notes (Details) slot is filled from the Details section whether it is headed ## Details & Options (the doc-tools title) or just ## Details; sections are keyed by heading text, so a lone ## Details must be matched explicitly or its bullets are silently dropped from the built page:

VerificationTest[
    {Length @ Cases[MarkdownToNotebook["---\nTemplate: Symbol\nName: Foo\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/ref/Foo\n---\n\n## Details\n\n- first note\n- second note\n"], Cell[_, "Notes", ___], Infinity],
     Length @ Cases[MarkdownToNotebook["---\nTemplate: Symbol\nName: Foo\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/ref/Foo\n---\n\n## Details & Options\n\n- only note\n"], Cell[_, "Notes", ___], Infinity]},
    {2, 1},
    TestID -> "Symbol Details section fills Notes whether titled '## Details' or '## Details & Options'"
]

A #| annotation: directive reconstructs a real "Annotate" annotation on its cell: the cell regains the "TextAnnotation" CellTag, a CellFrameLabels note (its date prefix kept verbatim) whose Edit/Delete chrome matches the shape DocumentationToolsAnnotationRemovelooks for, aCellID(the Edit button'sGenerateAnnotationDialogaborts without one), and a non-emptyLastAnnotator` name - so a round-tripped annotation stays a removable, editable annotation rather than an orphan note:

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTitle: T\n---\n\n<!-- #| annotation: 26.06.22: review me -->\nbody text\n"]},
        {! FreeQ[nb, CellTags -> ({___, "TextAnnotation", ___} | "TextAnnotation")],
         ! FreeQ[nb, Cell[TextData[{"26.06.22: review me", ___}], "TextAnnotation", ___]],
         ! FreeQ[FirstCase[nb, Cell[_, ___, CellFrameLabels -> {{_, _}, {_, Cell[_, "TextAnnotation", ___]}}, ___], Null, Infinity], CellID -> _Integer],
         ! FreeQ[nb, StyleBox[RowBox[{_, Except["", _String]}], "TextAnnotator"]]}
    ],
    {True, True, True, True},
    TestID -> "#| annotation: rebuilds the TextAnnotation tag, note, CellID, and LastAnnotator name"
]

A <!-- #| annotation: ... --> written across several hard-wrapped lines keeps its whole value - the wrapped lines are joined into one directive rather than only the first line surviving - and a standalone annotation placed just before a --- delimiter lands on the following cell instead of the (metadata-less) delimiter:

VerificationTest[
    With[{note = FirstCase[
        MarkdownToNotebook["---\nTitle: T\n---\n\n<!-- #| annotation: line one\nwrapped two\nwrapped three -->\n\n---\n\nbody text\n"],
        (CellFrameLabels -> {{_, _}, {_, Cell[TextData[{n_String, ___}], "TextAnnotation", ___]}}) :> n, "", Infinity]},
        {StringContainsQ[note, "wrapped three"], StringContainsQ[note, "line one wrapped two wrapped three"]}
    ],
    {True, True},
    TestID -> "#| annotation: multi-line value joined and attached past a --- delimiter"
]

A #| annotation: directive on a section heading (e.g. before ## Details on a structured doc page) annotates the section's first cell - a structured heading has no cell of its own, so the note lands once on the first content cell rather than being dropped or repeated on every item:

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Symbol\nName: Foo\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/ref/Foo\n---\n\n## Usage\n\n`Foo[x]` does.\n\n<!-- #| annotation: 26.06: review section -->\n## Details\n\n- Detail one.\n- Detail two.\n\n## Basic Examples\n\n```wl\nFoo[1]\n```\n", "Evaluate" -> False]},
        Cases[nb, Cell[_, "Notes", ___, CellFrameLabels -> {{_, _}, {_, Cell[TextData[{note_String, ___}], "TextAnnotation", ___]}}, ___] :> note, Infinity]],
    {"26.06: review section"},
    TestID -> "#| annotation: on a section heading (## Details) annotates the section's first cell"
]

A page whose examples span more than its primary Context: lists the extra contexts in a ContextPath: frontmatter list; the page's ExampleInitialization cell then Needs[] every one (the primary context first), so a reader who runs the examples loads them all - not just the primary context:

VerificationTest[
    With[{ei = FirstCase[
        MarkdownToNotebook["---\nTemplate: Symbol\nName: Foo\nContext: A`Pkg`\nContextPath: [B`Extra`, C`More`]\nPaclet: A/Pkg\nURI: A/Pkg/ref/Foo\n---\n\n## Usage\n\n`Foo[x]` does.\n\n## Basic Examples\n\n```wl\nFoo[1]\n```\n", "Evaluate" -> False],
        Cell[BoxData[b_], "ExampleInitialization", ___] :> b, $Failed, Infinity]},
        {! FreeQ[ei, "\"A`Pkg`\""], ! FreeQ[ei, "\"B`Extra`\""], ! FreeQ[ei, "\"C`More`\""]}
    ],
    {True, True, True},
    TestID -> "ContextPath: each context Needs[]'d in the ExampleInitialization cell"
]

A Blank immediately followed by a named-character head (_\[FormalS], delivered by a fence as the literal ten-character escape) rebuilds as a single Blank leaf with that head - the front-end reparser otherwise splits it into Times[Blank[], \[FormalS]], which matches nothing (issue #39):

VerificationTest[
    MatchQ[\[FormalS][1], ReleaseHold @ ToExpression[inputBoxes["_\\[FormalS]"], StandardForm, Hold]],
    True,
    TestID -> "_\\[Name] rebuilds as Blank with a named-character head (issue #39)"
]

A \!\(...\) linear-syntax box (a typeset subscript inside a string label) is reactivated: the four inert ASCII tokens \! \( \* \) map back to the active PUA codes, so the cell shows a rendered subscript instead of the literal escaped ASCII (issue #35):

VerificationTest[
    With[{b = inputBoxes["\"x \\!\\(\\*SubscriptBox[\\(CO\\), \\(2\\)]\\)\""]},
        {! FreeQ[b, _String?(StringContainsQ[#, FromCharacterCode[63425]] &)],
           FreeQ[b, _String?(StringContainsQ[#, "\\!\\("] &)]}],
    {True, True},
    TestID -> "\\!\\(...\\) linear syntax reactivated to PUA markers (issue #35)"
]

Example messages are captured at the box level (an InternalHandlerBlock["Message"], not a $Messagestext file), so a message is rebuilt from its template + args with each arg boxified: a styledRawBoxesargument - asResourceFunction's ResourceFunctionMessageputs in its name slot - becomes a realStyleBoxin the message boxes instead of dumping a literalRawBoxes[StyleBox[…]]` string:

VerificationTest[
    messageBoxData["RFM::user", "`1`: `2`", {RawBoxes[StyleBox[RowBox[{"Foo", "::", "bar"}], "MessageName"]], "oops"}],
    RowBox[{StyleBox["RFM::user", "MessageName"], ": ", StyleBox[RowBox[{"Foo", "::", "bar"}], "MessageName"], ": ", "oops"}],
    TestID -> "styled RawBoxes message arg becomes a StyleBox, not literal text (ResourceFunctionMessage)"
]

The markdown twin reads a captured message as the front end shows it. A ResourceFunctionMessage message arrives as a Row, which boxes to a TemplateBox[..., "RowDefault"]: its parts are joined and its string literals lose their quotes, instead of the raw boxes leaking into the blockquote:

VerificationTest[
    messageMd[messageBoxData["ResourceFunction::usermessage", "`1`",
        {Row[{RawBoxes[StyleBox[RowBox[{"Memoize", "::", "flat"}], "MessageName"]], ": ",
            Row[{"Memoize does not support ", joined, ", which has the attribute Flat."}]}]}]],
    "> ResourceFunction::usermessage: Memoize::flat: Memoize does not support joined, which has the attribute Flat.",
    TestID -> "a ResourceFunctionMessage message reads as text in the markdown twin"
]

A Row with a separator reads with its separator between the parts:

VerificationTest[
    messageMd[messageBoxData["f::m", "got `1`", {Row[{1, "b"}, ", "]}]],
    "> f::m: got 1, b",
    TestID -> "a Row with a separator reads as text in the markdown twin"
]

An echo reads in the markdown twin as the front end shows it, after the » marker of an Echo cell, and a machine number shows without the precision mark its boxes carry:

VerificationTest[
    printTextForm /@ captureCellRun["Echo[2.5, \"computing\"]"]["prints"],
    {"\[RightGuillemet] computing 2.5"},
    TestID -> "an echo reads as the front end shows it in the markdown twin"
]

An example-output cache entry whose boxes embed a raw format-wrapper expression (a TraditionalForm[...] inside an Interpretation / Manipulate / DynamicModule output) round-trips through the persistent cache: it is stored as WXF bytes, so Put cannot render it as un-reparseable 2D text and force the whole document to permanently cache-miss:

VerificationTest[
    Module[{entry, name, got},
        entry = <|"outs" -> {ToBoxes[Interpretation[TraditionalForm[Cos[x/2]], TraditionalForm[Cos[x/2]]]]},
            "msgs" -> {}, "prints" -> {}, "cells" -> {}|>;
        name = exampleCacheName["CacheReproTest", 1, 987654321];
        exampleCacheSet[name, entry];
        got = exampleCacheGet[name];
        DeleteObject[PersistentObjects[name, "Local"]];
        got === entry],
    True,
    TestID -> "cache survives an embedded TraditionalForm wrapper (WXF round-trip, issue #60)"
]

A #| tags: (or #| annotation:) directive before a fenced code cell lands on the Input cell even after the cell is evaluated - the Input/Output pair is wrapped in a CellGroupData, so the directive is applied to the group's first (Input) cell, not dropped (issue #42):

VerificationTest[
    ! FreeQ[
        MarkdownToNotebook["<!-- #| tags: mytag -->\n```wl\n1 + 1\n```\n"],
        Cell[_, "Input", ___, CellTags -> {___, "mytag", ___}, ___]
    ],
    True,
    TestID -> "#| tags on a fenced code cell survives evaluation, lands on the Input cell (issue #42)"
]

A bare big operator (an indefinite \int, or a limit-less \sum) comes back from the parser blown up to FontSize -> 1.7 Inherited, towering over the inline line; it is dampened to a restrained inline scale, while a sized delimiter (\Big() keeps its size (issue #47):

VerificationTest[
    Cases[
        MarkdownToNotebook["$\\int \\mathcal{L}\\,dx$", "Evaluate" -> False],
        StyleBox[s_String, ___, FontSize -> (r_ ? NumericQ) Inherited, ___] /; bigOpGlyphQ[s] :> r,
        Infinity],
    {1.15},
    TestID -> "bare big operator dampened to inline scale, not the parser's 1.7x (issue #47)"
]

A bare |x| modulus is promoted to a modulus delimiter (not left as raw bracketing-bar glyphs), and so is \lVert v\rVert; a conditional P(a|b) (an ASCII bar) is untouched (issue #46):

VerificationTest[
    With[{bars = GridBoxDividers -> {"Columns" -> {True, True}, ___}},
        {! FreeQ[MarkdownToNotebook["$|\\alpha|^2$", "Evaluate" -> False], bars],
         Count[MarkdownToNotebook["$\\lVert v\\rVert$", "Evaluate" -> False], bars, Infinity],
         FreeQ[MarkdownToNotebook["$P(a|b)$", "Evaluate" -> False], bars]}],
    {True, 2, True},
    TestID -> "bare |x| / ||v|| promoted to the modulus / norm delimiter, conditional bar untouched (issue #46)"
]

The extensible Abs / Norm template bars seam (a mid-height "bump") once the argument passes one text line, so every modulus is drawn as a GridBox column rule - a divider spans exactly the content height and is not a glyph, so it can neither be built up nor seam. The case that keeps regressing is the parenthesised argument |\psi(x)|^2, which is not a braket, so a braket-only guard misses it (issues #48, #67):

VerificationTest[
    Map[
        Function[tex,
            With[{b = MarkdownToNotebook["$" <> tex <> "$", "Evaluate" -> False]},
                {! FreeQ[b, GridBoxDividers -> {"Columns" -> {True, True}, ___}],
                 FreeQ[b, TemplateBox[_, "Abs" | "Norm"]]}]],
        {"|\\psi(x)|^2", "|x|", "\\lVert v\\rVert", "|\\langle\\phi|\\psi\\rangle|^2"}],
    {{True, True}, {True, True}, {True, True}, {True, True}},
    TestID -> "modulus / norm drawn as a seamless GridBox column rule, incl. a parenthesised argument (issue #48/#67)"
]

A norm whose bars never became the bracketing pair - \|…\| has no matchfix production and a bare-bar ket poisons the \lVert…\rVert matchfix, so both spellings emit a bare \[DoubleVerticalBar] (U+2225, a relational glyph that cannot stretch) - is still promoted around a tall argument, so $\||\psi\rangle\|$ draws a full-height rule instead of two one-line ticks. Bare U+2225 is also how \parallel is spelled, so the promotion is guarded: a genuine relation a \parallel b (an operand on each outer side, scalar argument) keeps its plain glyph (issue #64):

VerificationTest[
    With[{bars = GridBoxDividers -> {"Columns" -> {True, True}, ___}},
        {Count[MarkdownToNotebook["$\\||\\psi\\rangle\\| = 1$", "Evaluate" -> False], bars, Infinity],
         FreeQ[MarkdownToNotebook["$a \\parallel b$", "Evaluate" -> False], bars],
         FreeQ[MarkdownToNotebook["$\\|x\\|$", "Evaluate" -> False], bars]}],
    {2, True, True},
    TestID -> "tall bare-double-bar norm drawn full-height, \\parallel relation and scalar left alone (issue #64)"
]

A script on a \|…\| norm hangs on the closing bar glyph itself - \| is a bare atom, so the parser has no matchfix span to carry the script - and a pair whose closer is a SuperscriptBox / SubscriptBox is not a bare pair. Such a pair is promoted too, with the script lifted onto the promoted norm, so $\||\psi\rangle\|^2$ draws the full-height rule squared; a scripted operand beside a genuine \parallel relation keeps its plain glyph (issue #74):

VerificationTest[
    With[{bars = GridBoxDividers -> {"Columns" -> {True, True}, ___}},
        {Count[MarkdownToNotebook["$\\||\\psi\\rangle\\|^2$", "Evaluate" -> False], bars, Infinity],
         ! FreeQ[MarkdownToNotebook["$\\||\\psi\\rangle\\|^2$", "Evaluate" -> False], SuperscriptBox[_GridBox, "2"]],
         ! FreeQ[MarkdownToNotebook["$\\||\\psi\\rangle\\|_2$", "Evaluate" -> False], SubscriptBox[_GridBox, "2"]],
         FreeQ[MarkdownToNotebook["$a \\parallel b^2$", "Evaluate" -> False], bars]}],
    {2, True, True, True},
    TestID -> "norm-squared \\|..\\|^2 / \\|..\\|_2 keeps the full-height rule with the script lifted onto it (issue #74)"
]

A ket / bra written with explicit sizing delimiters (\left|..\right\rangle, \left\langle..\right|) is a mismatched pair - an extensible bracketing bar against an angle bracket - that no matched-bar rule catches; it folds to the same Ket / Bra template as the bare |..\rangle form, whose bar is a clean non-extensible glyph. An outer product \left|e\right\rangle\left\langle g\right| splits its bar pair across the two factors and folds to a Ket then a Bra, not a modulus (issue #85):

VerificationTest[
    {! FreeQ[MarkdownToNotebook["$\\left|e\\right\\rangle$", "Evaluate" -> False], TemplateBox[_, "Ket"]],
     ! FreeQ[MarkdownToNotebook["$\\left\\langle e\\right|$", "Evaluate" -> False], TemplateBox[_, "Bra"]],
     FreeQ[MarkdownToNotebook["$\\left|\\hat\\sigma_z = \\pm 1\\right\\rangle$", "Evaluate" -> False],
         "\[LeftBracketingBar]" | "\[RightBracketingBar]"],
     Cases[MarkdownToNotebook["$\\left|e\\right\\rangle\\left\\langle g\\right|$", "Evaluate" -> False],
         TemplateBox[_, t : "Ket" | "Bra"] :> t, Infinity]},
    {True, True, True, {"Ket", "Bra"}},
    TestID -> "explicit \\left|..\\right\\rangle / \\left\\langle..\\right| folds to Ket / Bra; outer product is not a modulus (issue #85)"
]

Dirac notation whose content is wrapped in braces (\langle{\phi}|{\psi}\rangle) keeps that content: the parser's standalone-fence commands re-emit a following {group} instead of dropping it, so a braced bra/ket/braket folds into its template just like the unbraced form (issue #49, WolframParser fix):

VerificationTest[
    {! FreeQ[MarkdownToNotebook["$\\langle{\\phi}|{\\psi}\\rangle$", "Evaluate" -> False], TemplateBox[_, "BraKet"]],
     ! FreeQ[MarkdownToNotebook["$\\langle{X}|$", "Evaluate" -> False], TemplateBox[_, "Bra"]]},
    {True, True},
    TestID -> "braced Dirac content keeps its content and folds into Bra/BraKet (issue #49)"
]

A symbol page keeps the standard Examples-Initialization section - the ExamplesInitializationSection group with an ExampleInitialization cell that Needs[] the documented context - exactly as the authoring template ships it and every built ref page has it (e.g. Wolfram/LeanLink). DocumentationBuild folds it into the Examples section at build time:

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Symbol\nName: Foo\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/ref/Foo\n---\n\n## Usage\n\n`Foo[x]` does.\n\n## Basic Examples\n\n```wl\nFoo[1]\n```\n", "Evaluate" -> False]},
        {! FreeQ[nb, Cell[___, "ExamplesInitializationSection", ___]],
         ! FreeQ[nb, Cell[BoxData[b_ /; ! FreeQ[b, "\"P`Q`\""]], "ExampleInitialization", ___]]}],
    {True, True},
    TestID -> "Symbol page keeps the standard Examples-Initialization section with a Needs cell"
]

A symbol reference in a resource notebook (Template: Paclet / FunctionResource / ...) is the plain reference-Link ButtonBox the Function/Paclet Repository templates use - BaseStyle -> "Link" with the paclet:ref/... target kept (the cloud resolves it on deploy) - not the doc-center RefLink / PackageLink TemplateBox a built doc page uses, which the resource stylesheet has no definition for:

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Paclet\nName: Foo\nPaclet: Pub/Foo\nDescription: x\n---\n\n## Details\n\n- Uses [ColorConvert]() here.\n", "Evaluate" -> False]},
        {Length @ Cases[nb, TemplateBox[_, "RefLink" | "PackageLink", ___], Infinity],
         ! FreeQ[nb, ButtonBox["ColorConvert", ___, ButtonData -> "paclet:ref/ColorConvert", ___]]}],
    {0, True},
    TestID -> "resource-template autolink is a plain paclet Link ButtonBox (FunctionResource form), not a doc-center RefLink"
]

A doc page (Symbol / Guide / TechNote) still emits the typed paclet: RefLink - it is built by DocumentationBuild and rendered in the doc center, where both the template and the paclet: scheme resolve (issue #20):

VerificationTest[
    ! FreeQ[
        MarkdownToNotebook["---\nTemplate: Symbol\nName: Bar\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/ref/Bar\n---\n\n## Usage\n\n`Bar[x]` x.\n\n## Details\n\n- Uses [ColorConvert]() here.\n", "Evaluate" -> False],
        TemplateBox[_, "RefLink", ___]
    ],
    True,
    TestID -> "doc-page autolink still uses the typed paclet RefLink (issue #20)"
]

A ## Interactive Examples section on a Symbol page fills the template's "Interactive Examples" ExampleSection - it is a standard extended-examples slot the Symbol template ships, so the authored content lands under that scaffold heading (issue #82, the same missing-key class as #4 / #12):

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Symbol\nName: Foo\nContext: P`Q`\nPaclet: P/Q\nURI: P/Q/ref/Foo\n---\n\n## Usage\n\n`Foo[x]` does.\n\n## Interactive Examples\n\nTry it:\n\n```wl\n#| eval: false\nManipulate[Foo[n], {n, 0, 1}]\n```\n", "Evaluate" -> False]},
        ! FreeQ[
            FirstCase[nb,
                Cell[CellGroupData[{sec_ /; ! FreeQ[sec, "Interactive Examples"], rest___}, Open], ___] :> {rest},
                {}, Infinity],
            "Manipulate"]],
    True,
    TestID -> "Interactive Examples fills the Symbol template's ExampleSection (issue #82)"
]

A ## Background & Context section on a Symbol page becomes FunctionEssay cells under a TOP-LEVEL "Function Essay" FunctionEssaySection group - the one shape DocumentationBuild extracts for the built page's Background section; essay cells nested inside the ObjectName group parse cleanly but never reach the built page (issue #86):

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: Symbol\nName: Foo\nContext: Global`\nPaclet: Test/Pack\nURI: Test/Pack/ref/Foo\n---\n\n## Usage\n\n`Foo[x]` does a thing.\n\n## Background & Context\n\nFirst paragraph.\n\nSecond paragraph.", "Evaluate" -> False]},
        {
            Length @ Cases[nb, Cell[_, "FunctionEssay", ___], Infinity],
            MemberQ[First[nb], Cell[CellGroupData[{Cell[_, "FunctionEssaySection", ___], ___}, ___], ___]]
        }
    ],
    {2, True},
    TestID -> "Background & Context becomes a top-level FunctionEssaySection group (issue #86)"
]

A ### heading inside ## Details / ## Details & Options groups the notes that follow it, the way long WFR Details sections and ref-page notes are grouped. It becomes a Subsubsection cell in a resource definition notebook (the level under the section's Subsection header, which the WFR scraper passes through) and a NotesSubsection cell on a Symbol page (the ref-page grouping style DocumentationBuild renders; issue #77):

VerificationTest[
    {
        FirstCase[
            MarkdownToNotebook["---\nTemplate: FunctionResource\nName: TinyFn\nDescription: d\n---\n\n## Definition\n\n```wl\nTinyFn[x_] := x\n```\n\n## Details\n\n- A note.\n\n### Grouped notes\n\n- Another note.\n", "Evaluate" -> False],
            Cell[c_ /; ! FreeQ[c, "Grouped notes"], style_String, ___] :> style, Missing["dropped"], Infinity],
        FirstCase[
            MarkdownToNotebook["---\nTemplate: Symbol\nName: TinyFn\nContext: Tiny`\n---\n\n## Usage\n\n`TinyFn[x]` gives x.\n\n## Details\n\n- A note.\n\n### Grouped notes\n\n- Another note.\n", "Evaluate" -> False],
            Cell[c_ /; ! FreeQ[c, "Grouped notes"], style_String, ___] :> style, Missing["dropped"], Infinity]
    },
    {"Subsubsection", "NotesSubsection"},
    TestID -> "nested Details heading groups notes: Subsubsection (resource) / NotesSubsection (Symbol page) (issue #77)"
]

A Template: Chapter document without a ChapterNumber: key (unnumbered front / back matter such as a Preface) gets a plain title-only Section heading - no CounterBox, no SectionBar separator, no CounterAssignments - while a numbered chapter keeps the canonical <counter> | <title> banner:

VerificationTest[
    With[{
        plain = MarkdownToNotebook["---\nTemplate: Chapter\nName: Preface\n---\n\n# Preface\n\nText.\n", "Evaluate" -> False],
        numbered = MarkdownToNotebook["---\nTemplate: Chapter\nName: Real\nChapterNumber: 3\n---\n\n# Real\n\nText.\n", "Evaluate" -> False]
    },
        {FirstCase[plain, Cell[t_, "Section", ___] :> t, Missing[], Infinity],
         FreeQ[plain, CounterBox] && FreeQ[plain, CounterAssignments],
         MatchQ[FirstCase[numbered, Cell[t_, "Section", ___] :> t, Missing[], Infinity],
             TextData[{CounterBox["Section"], StyleBox[" | ", "SectionBar"], __}]]}
    ],
    {"Preface", True, True},
    TestID -> "Chapter template: missing ChapterNumber gives a plain Section heading, a number keeps the CounterBox form"
]

Inside a Template: Chapter build the #| cell directives (#| style:, #| tags:, #| annotation:) land on the produced book cells the same way they do in a Default build - on free-form intro prose and inside a reserved back-matter section alike:

VerificationTest[
    With[{nb = MarkdownToNotebook[
        "---\nTemplate: Chapter\nName: Tiny\n---\n\n# Tiny\n\n#| style: SmallText\nCopyright line.\n\n## Summary\n\n#| tags: keep\n- First point.\n",
        "Evaluate" -> False]},
        {! FreeQ[nb, Cell[_, "SmallText", ___]],
         Cases[nb, (CellTags -> t_) :> t, Infinity]}],
    {True, {{"keep"}}},
    TestID -> "Chapter template: #| style / #| tags directives land on book cells, free-form and reserved-section alike"
]

A NotebookTemplate document is a template notebook: the framework's tagging, slot boxes for TemplateSlot in code and in prose, an expression box for TemplateExpression, the cell-behavior label for #| behavior:, and no evaluation:

VerificationTest[
    With[{nb = MarkdownToNotebook[
        "---\nTemplate: NotebookTemplate\nSlots:\n  z: 7\n---\n\n<!-- #| behavior: ExcludeCell -->\nNote.\n\nx is `TemplateSlot[\"x\"]`.\n\n```wl\nTemplateSlot[\"x\"] + TemplateSlot[\"y\", 1] + TemplateSlot[\"z\"]\n```\n\n```wl\nTemplateExpression[2 x]\n```"]},
        {MemberQ[Cases[nb, (TaggingRules -> r_) :> r, {1}], KeyValuePattern["NotebookTemplate" -> True]],
         Cases[nb, TemplateBox[{n_, d_, m_, f_}, "NotebookTemplateSlot"] :> {n, d, m, f}, Infinity],
         Count[nb, TemplateBox[_, "NotebookTemplateExpression"], Infinity],
         Cases[nb, (CellFrameLabels -> {{Cell[BoxData[TemplateBox[{k_}, "NotebookTemplateCellBehavior"]]], _}, _}) :> k, Infinity],
         Count[nb, Cell[_, "Output", ___], Infinity]}],
    {True,
     {{"\"x\"", "", "Named", TextData}, {"\"x\"", "", "Named", BoxData}, {"\"y\"", "1", "Named", BoxData}, {"\"z\"", "7", "Named", BoxData}},
     1, {"ExcludeCell"}, 0},
    TestID -> "NotebookTemplate: template tagging, slot / expression boxes, a Slots: frontmatter default, cell behavior, no evaluation"
]

A reference page stamps CellContext -> CellGroup so its independent examples cannot leak bindings into one another, while a narrative Tech Note or Tutorial keeps the ambient context - it threads state across sections, and a private per-group context would make a reader's re-evaluation disagree with the output the page displays (issue #97):

VerificationTest[
    Map[
        Cases[MarkdownToNotebook[
            "---\nTemplate: " <> # <> "\nName: N\nContext: Global`\nPaclet: X/Y\nURI: X/Y/ref/N\n---\n\n## Usage\n\nN[x] does x.\n",
            "Evaluate" -> False][[2 ;;]],
            HoldPattern[CellContext -> v_] :> v, Infinity, Heads -> True] &,
        {"Symbol", "TechNote"}],
    {{CellGroup}, {}},
    TestID -> "CellContext: CellGroup on a reference page, ambient on a narrative Tech Note (issue #97)"
]

A ## Functions item made only of code spans joined by ▪ is an inline listing: one InlineGuideFunctionListing row of the same chips a 1-Line Function uses, separated by the template's InlineSeparator cell, while an ordinary item keeps the 1-Line Function form (issue #91):

VerificationTest[
    With[{nb = MarkdownToNotebook[
        "---\nTemplate: Guide\nName: G\nTitle: G\nPaclet: X/Y\nContext: X`\nURI: X/Y/guide/G\n---\n\n## Functions\n\n- `Plot` - plot\n- `PlotStyle` \[FilledVerySmallSquare] `PlotLabel` \[FilledVerySmallSquare] `AxesLabel`\n",
        "Evaluate" -> False]},
        With[{lst = Cases[nb, c : Cell[_, "InlineGuideFunctionListing", ___] :> c, Infinity]},
            {Length[lst], Count[lst, Cell[_, "InlineGuideFunction", ___], Infinity],
             Count[lst, StyleBox[_, "InlineSeparator"], Infinity],
             Count[nb, Cell[TextData[{___, " \[LongDash] ", ___}], "GuideText", ___], Infinity]}]],
    {1, 3, 2, 1},
    TestID -> "Guide: a code-span row joined by \[FilledVerySmallSquare] builds an InlineGuideFunctionListing (issue #91)"
]

Each ## Abstract paragraph is its own GuideAbstract cell rather than one run-together block, and a placeholder expanded into several cells gives each its own CellID - three RelatedTutorials fill three GuideTutorial cells with no ID shared (issues #100, #98):

VerificationTest[
    With[{nb = MarkdownToNotebook[
        "---\nTemplate: Guide\nName: G\nTitle: G\nPaclet: X/Y\nContext: X`\nURI: X/Y/guide/G\nKeywords: [a, b, c]\nRelatedTutorials: [One, Two, Three]\n---\n\n## Abstract\n\nFirst.\n\nSecond.\n\n## Functions\n\n- `Plot` - plot\n",
        "Evaluate" -> False]},
        {Cases[nb, Cell[t_, "GuideAbstract", ___] :> t, Infinity],
         Count[nb, Cell[_, "GuideTutorial", ___], Infinity],
         Select[Tally[Cases[nb, (CellID -> id_) :> id, Infinity]], Last[#] > 1 &]}],
    {{"First.", "Second."}, 3, {}},
    TestID -> "Guide: abstract paragraphs stay separate cells; expanded placeholders get distinct CellIDs (issues #100, #98)"
]

A table with an empty header row - how an option table without a header is written in markdown - builds no blank first row (issue #92):

VerificationTest[
    Length @ FirstCase[
        MarkdownToNotebook["## T\n\n|   |   |\n|---|---|\n| a | 1 |\n| b | 2 |\n", "Evaluate" -> False],
        GridBox[rows_, ___] :> rows, {}, Infinity],
    2,
    TestID -> "an empty markdown header row is not built as a blank first row (issue #92)"
]

A reference subtype's example sections follow the Symbol page's shape - the primary group holds only the examples before the first section heading, and each later section is its own ExampleSection group under a "More Examples" group - instead of nesting inside Basic Examples as ExampleSubsection cells (issue #99):

VerificationTest[
    With[{nb = MarkdownToNotebook[
        "---\nTemplate: ServiceConnection\nName: S\nPaclet: X/Y\nContext: X`\nURI: X/Y/ref/service/S\n---\n\nA service.\n\n## Examples\n\n### Basic Examples\n\n```wl\n1 + 1\n```\n\n### Scope\n\n```wl\n2 + 2\n```\n\n### Authentication\n\n```wl\n3 + 3\n```\n",
        "Evaluate" -> False]},
        {Count[FirstCase[nb, g : Cell[CellGroupData[{Cell[_, "PrimaryExamplesSection", ___], ___}, _], ___] :> g, {}, Infinity],
            Cell[_, "ExampleSubsection", ___], Infinity],
         Cases[nb, Cell[BoxData[InterpretationBox[Cell[t_String, "ExampleSection"], _]], "ExampleSection", ___] :> t, Infinity],
         Count[nb, Cell[_, "ExtendedExamplesSection", ___], Infinity]}],
    {0, {"Scope", "Authentication"}, 1},
    TestID -> "subtype page: extra example sections are ExampleSection groups under More Examples (issue #99)"
]

A comment naming a box form marks the sub-expression after it to show typeset: inside an argument list that is the sequence's first element, the display is the form's boxes and the interpretation is the code as written, so the input still evaluates exactly as typed; an ordinary comment is not a marker (issue #90):

VerificationTest[
    With[{nb = MarkdownToNotebook[
        "## A\n\n```wl\nf[(*TraditionalForm*)Integrate[x^2, x], 2]\n```\n\n```wl\n(* integrate it *)Integrate[x^2, x]\n```",
        "Evaluate" -> False]},
        {Cases[nb, InterpretationBox[FormBox[_, form_], e_, ___] :> {form, HoldComplete[e]}, Infinity],
         ToExpression[First @ Cases[nb, Cell[BoxData[b_], "Input", ___] :> b, Infinity], StandardForm, HoldComplete]}],
    {{{TraditionalForm, HoldComplete[Integrate[x^2, x]]}}, HoldComplete[f[Integrate[x^2, x], 2]]},
    TestID -> "typeset: an inline form marker typesets its operand and keeps the input's meaning (issue #90)"
]

Typesetting by rule is opt-in: a Typeset: frontmatter pattern typesets every matching sub-expression, a cell's #| typeset: None turns that off, and a cell rule adds to the document's; it applies with "Evaluate" -> False too (issue #90):

VerificationTest[
    With[{forms = Function[md, Cases[MarkdownToNotebook[md, "Evaluate" -> False],
            InterpretationBox[FormBox[_, f_], ___] :> f, Infinity]],
          q = "```wl\n{Quantity[1, \"Meters\"], Integrate[x^2, x]}\n```"},
        {forms["## A\n\n" <> q],
         forms["---\nTypeset:\n  _Quantity: StandardForm\n---\n\n## A\n\n" <> q],
         forms["---\nTypeset:\n  _Quantity: StandardForm\n---\n\n## A\n\n" <> StringReplace[q, "```wl\n" -> "```wl\n#| typeset: None\n"]],
         forms["---\nTypeset:\n  _Quantity: StandardForm\n---\n\n## A\n\n" <> StringReplace[q, "```wl\n" -> "```wl\n#| typeset: _Integrate -> TraditionalForm\n"]]}],
    {{}, {StandardForm}, {}, {StandardForm, TraditionalForm}},
    TestID -> "typeset: frontmatter rules are opt-in, None disables, cell rules merge, Evaluate -> False still typesets (issue #90)"
]

A sub-expression with no typeset form until it is evaluated - a DateObject built from a date list - is evaluated for its display, while the interpretation stays the code as written (issue #90):

VerificationTest[
    Cases[MarkdownToNotebook["## A\n\n```wl\n(*StandardForm*)DateObject[{2026, 9, 30}]\n```", "Evaluate" -> False],
        InterpretationBox[FormBox[TemplateBox[_, t_String, ___], _], e_, ___] :> {t, HoldComplete[e]}, Infinity],
    {{"DateObject", HoldComplete[DateObject[{2026, 9, 30}]]}},
    TestID -> "typeset: a DateObject shows its date and holds its code (issue #90)"
]

An approximate number in a typeset display reads as typed: its box carries a precision mark (1.4 + backtick) that an output cell formats away but an input cell would show verbatim, so the typeset display drops it (issue #90):

VerificationTest[
    Cases[MarkdownToNotebook["## A\n\n```wl\n{(*StandardForm*)Quantity[1.4, \"Meters\"], (*StandardForm*)Quantity[3, \"Meters\"]}\n```", "Evaluate" -> False],
        TemplateBox[{m_, __}, "Quantity", ___] :> m, Infinity],
    {"1.4", "3"},
    TestID -> "typeset: an approximate magnitude shows without its precision mark (issue #90)"
]

Example outputs are cached as WXF, which keeps every symbol's context, so a front-end symbol in cached boxes reads back into System` rather than as a Global` copy; an entry in the older Compress form reads as a miss and is recomputed (issue #101):

VerificationTest[
    Module[{name = "MarkdownToNotebook/ExampleOutput/test-" <> CreateUUID[], entry = <|"boxes" -> RowBox[{"1", "+", "1"}], "msgs" -> {}|>, r},
        exampleCacheSet[name, entry];
        r = {Head[PersistentSymbol[name, $cacheLocation]], exampleCacheGet[name] === entry};
        PersistentSymbol[name, $cacheLocation] = Compress[entry];
        r = Append[r, MissingQ[exampleCacheGet[name]]];
        DeleteObject[PersistentObject[name, $cacheLocation]];
        r],
    {ByteArray, True, True},
    TestID -> "example cache: entries are WXF, and a pre-WXF Compress entry reads as a miss (issue #101)"
]

A Related Guides entry links under the guide's title: a system guide the installed documentation knows (EquationSolving) links to its own page, a paclet guide's name is split into words, and an explicit [Title](Name) keeps its title (issue #102):

VerificationTest[
    Cases[MarkdownToNotebook["---\nTemplate: Symbol\nName: F\nContext: X`\nPaclet: X/Y\nURI: X/Y/ref/F\nRelatedGuides: [EquationSolving, MyPacletGuide, \"[Custom Title](OtherGuide)\"]\n---\n\n# F\n\n## Usage\n\nF[x] does x.\n",
            "Evaluate" -> False],
        ButtonBox[l_, ___, ButtonData -> d_String, ___] /; StringContainsQ[d, "guide/"] :> {l, d}, Infinity],
    {{"Equation Solving", If[StringQ[Quiet @ Documentation`ResolveLink["paclet:guide/EquationSolving"]],
        "paclet:guide/EquationSolving", "paclet:X/Y/guide/EquationSolving"]},
     {"My Paclet Guide", "paclet:X/Y/guide/MyPacletGuide"},
     {"Custom Title", "paclet:X/Y/guide/OtherGuide"}},
    TestID -> "RelatedGuides: a system guide links to its own page; every guide shows its title (issue #102)"
]

In a chapter, inline math takes the book stylesheet's own InlineMath style, which sizes it for the book, while a code span stays an InlineFormula (issue #108):

VerificationTest[
    Cases[MarkdownToNotebook["---\nTemplate: Chapter\nName: \"Repro\"\nChapterNumber: 3\n---\n\n# Repro\n\nInline math $x^2$ and `code`.\n", "Evaluate" -> False],
        Cell[BoxData[_], st : ("InlineFormula" | "InlineMath"), o___] :> {st, o}, Infinity],
    {{"InlineMath"}, {"InlineFormula", FontSize -> 0.9 Inherited}},
    TestID -> "Chapter: inline math takes the InlineMath style, a code span stays InlineFormula (issue #108)"
]

A display formula inside a solved example or a proof sizes a bare big operator like any display formula (issue #109):

VerificationTest[
    Cases[MarkdownToNotebook["---\nTemplate: Chapter\nName: \"Repro\"\nChapterNumber: 3\n---\n\n# Repro\n\n$$\\int f$$\n\n::: solved-example\nFind it.\n\n$$\\int f$$\n:::\n\n::: proof\nSince\n\n$$\\int f$$\n:::\n",
            "Evaluate" -> False],
        Cell[BoxData[PaneBox[b_, ___]], st_String, ___] :>
            {st, Cases[b, StyleBox["\[Integral]", ___, FontSize -> f_, ___] :> f, {0, Infinity}]}, Infinity],
    {{"DisplayFormula", {1.4 Inherited}}, {"SolvedExampleDisplayFormula", {1.4 Inherited}}, {"ProofTheoremDisplayFormula", {1.4 Inherited}}},
    TestID -> "Chapter: solved-example and proof display formulas size big operators like any display formula (issue #109)"
]

In a Function resource a code span is what the definition notebook toolbar's Template Input button makes of the same text - no whitespace tokens, each lowercase identifier a TI template argument, a documented symbol a link - and a *variable* in prose is that same TI InlineFormula; every inline formula, a link included, is set in the toolbar's Source Sans Pro (the formatting the Function Repository reviewers ask for):

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: FunctionResource\nName: TinyFn\nDescription: d\n---\n\n## Definition\n\n```wl\nTinyFn[x_] := x\n```\n\n## Details\n\n- `TinyFn[f, crit]` and `; // TinyFn` use *f* like [Set]().\n", "Evaluate" -> False]},
        {
            ! FreeQ[nb, Cell[BoxData[RowBox[{"TinyFn", "[", RowBox[{StyleBox["f", "TI"], ",", StyleBox["crit", "TI"]}], "]"}]], "InlineFormula", FontFamily -> "Source Sans Pro"]],
            ! FreeQ[nb, Cell[BoxData[RowBox[{";", "//", "TinyFn"}]], "InlineFormula", FontFamily -> "Source Sans Pro"]],
            ! FreeQ[nb, Cell[BoxData[StyleBox["f", "TI"]], "InlineFormula", FontFamily -> "Source Sans Pro"]],
            ! FreeQ[nb, Cell[BoxData[ButtonBox["Set", ___]], "InlineFormula", FontFamily -> "Source Sans Pro", ___]]
        }],
    {True, True, True, True},
    TestID -> "a Function resource's code span is the toolbar's Template Input, a *variable* a TI InlineFormula, in Source Sans Pro"
]

A span of markdown or YAML syntax in a Function resource is not Wolfram Language code, so it keeps the literal boxes any template gives it rather than Template Input's italics, and a path stays a literal InlineCode token; a postfix application written tight is code even though it holds a /:

VerificationTest[
    With[{nb = MarkdownToNotebook["---\nTemplate: FunctionResource\nName: TinyFn\nDescription: d\n---\n\n## Definition\n\n```wl\nTinyFn[x_] := x\n```\n\n## Details\n\n- Write `#| eval: false` or `key: value`, and `;//TinyFn` or `docs/x.md`.\n", "Evaluate" -> False]},
        {Cases[nb, Cell[BoxData[b_], "InlineFormula", ___] /; ! FreeQ[b, "#" | "key"] :> MemberQ[Flatten[b /. RowBox -> List], " "], Infinity],
         ! FreeQ[nb, Cell[BoxData[RowBox[{";", "//", "TinyFn"}]], "InlineFormula", ___]],
         ! FreeQ[nb, Cell["docs/x.md", "InlineCode", ___]]}],
    {{True, True}, True, True},
    TestID -> "markdown or YAML syntax in a Function resource's code span stays literal, a tight postfix is code"
]

A [!REVIEW] quote after a #| comment: directive places the cell the directive carries exactly as it was - a reviewer's signature, label, CellID and wording included - where the quote stands, and the cells around it keep the CellIDs they have without it:

VerificationTest[
    Module[{cell, md, with, without, idOf},
        cell = Cell[TextData[{"Use ", Cell[BoxData[StyleBox["f", "TI"]], "InlineFormula", FontFamily -> "Source Sans Pro"], " here."}], "ReviewerComment",
            Editable -> False, Deletable -> False, TaggingRules -> {"Signature" -> "c2lnbmVk"},
            CellFrameLabels -> {{None, Cell[BoxData[TemplateBox[{StyleBox[TemplateBox[{"\"WFR Team\""}, "ReviewerCommentLabelTemplate"],
                ShowStringCharacters -> False, StripOnInput -> False], 4.0005*^9}, "CommentCellLabelTemplate"]], Background -> None]}, {None, None}},
            CellTags -> {"CommentCell", "ReviewerComment"}, CellID -> 1234567];
        md[c_] := "---\nTemplate: FunctionResource\nName: TinyFn\nDescription: d\n---\n\n## Definition\n\n```wl\nTinyFn[x_] := x\n```\n\n## Details\n\n- A note.\n\n" <> c <> "- Another note.\n";
        with = MarkdownToNotebook[md["<!-- #| comment: " <> BaseEncode[BinarySerialize[cell]] <> " -->\n> [!REVIEW] WFR Team, 2026-10-09 19:30 UTC\n> Use f here.\n\n"], "Evaluate" -> False];
        without = MarkdownToNotebook[md[""], "Evaluate" -> False];
        idOf[nb_] := FirstCase[nb, Cell[c_ /; ! FreeQ[c, "Another note."], "Notes", ___, CellID -> id_, ___] :> id, None, Infinity];
        {Count[with, cell, Infinity],
         MatchQ[Cases[with, {___, Cell[a_ /; ! FreeQ[a, "A note."], "Notes", ___], cell, Cell[b_ /; ! FreeQ[b, "Another note."], "Notes", ___], ___}, Infinity], {_}],
         idOf[with] === idOf[without]}
    ],
    {1, True, True},
    TestID -> "a [!REVIEW] quote places its directive's cell verbatim and shifts no CellID"
]

A [!COMMENT] quote without a directive is the author's reply, an AuthorComment cell with the label and UTC time the toolbar's Reply button gives one; a [!REVIEW] quote is never made up from text, so without its directive it stays a plain quote (and MarkdownToNotebook::revcomment says so):

VerificationTest[
    Module[{md, author, review},
        md[q_] := "---\nTemplate: FunctionResource\nName: TinyFn\nDescription: d\n---\n\n## Definition\n\n```wl\nTinyFn[x_] := x\n```\n\n## Details\n\n- A note.\n\n" <> q <> "\n";
        author = FirstCase[MarkdownToNotebook[md["> [!COMMENT] Ada Lovelace, 2026-10-10 12:00 UTC\n> Reworded the note."], "Evaluate" -> False],
            Cell[t_, "AuthorComment", o___] :> {t, Lookup[{o}, CellTags], Cases[{o}, TemplateBox[{l_, w_}, "CommentCellLabelTemplate"] :> {l, w}, Infinity]}, None, Infinity];
        review = MarkdownToNotebook[md["> [!REVIEW] WFR Team, 2026-10-09 19:30 UTC\n> Made up."], "Evaluate" -> False];
        {author, Cases[review, Cell[_, "ReviewerComment", ___], Infinity],
         Cases[review, Cell[TextData[{"Made up."}], "Text", ___, FontSlant -> "Italic", ___] :> "quote", Infinity]}
    ],
    {{TextData[{"Reworded the note."}], {"AuthorComment", "CommentCell"},
      {{StyleBox["\"Ada Lovelace\"", ShowStringCharacters -> False, StripOnInput -> False],
        N @ AbsoluteTime[DateObject[{2026, 10, 10, 12, 0, 0}, TimeZone -> 0], TimeZone -> 0]}}},
     {}, {"quote"}},
    {MarkdownToNotebook::revcomment},
    TestID -> "a [!COMMENT] quote builds an AuthorComment; a [!REVIEW] quote needs its directive"
]

The markdown twin keeps a comment as its source writes it - each quote line, the header first, and a reviewer comment's directive - so a document rebuilt from its twin has the same comments:

VerificationTest[
    Module[{cell, md, twin = FileNameJoin[{$TemporaryDirectory, "mtn-comment-twin.md"}], nb1, nb2, comments},
        cell = Cell["Is this clear?", "ReviewerComment", CellTags -> {"CommentCell", "ReviewerComment"}, CellID -> 2468];
        md = "---\nTemplate: FunctionResource\nName: TinyFn\nDescription: d\n---\n\n## Definition\n\n```wl\nTinyFn[x_] := x\n```\n\n## Details\n\n- A note.\n\n<!-- #| comment: " <> BaseEncode[BinarySerialize[cell]] <> " -->\n> [!REVIEW] WFR Team, 2026-10-09 19:30 UTC\n> Is this clear?\n\n> [!COMMENT] Ada Lovelace, 2026-10-10 12:00 UTC\n> Yes.\n";
        nb1 = MarkdownToNotebook[md, "Evaluate" -> False];
        MarkdownToNotebook[md, twin, "Evaluate" -> False];
        nb2 = MarkdownToNotebook[twin, "Evaluate" -> False];
        DeleteFile[twin];
        comments[nb_] := Cases[nb, Cell[_, "ReviewerComment" | "AuthorComment", ___], Infinity];
        {Length[comments[nb1]], comments[nb2] === comments[nb1]}
    ],
    {2, True},
    TestID -> "a comment survives the markdown twin"
]

Template: FunctionResourceReview builds the Function notebook a reviewed submission came back as: its SubmissionReview: mapping becomes the SubmissionReviewData the toolbar's Submit Update reads to update that submission:

VerificationTest[
    Lookup[
        Association @ Normal @ FirstCase[
            MarkdownToNotebook["---\nTemplate: FunctionResourceReview\nName: TinyFn\nDescription: d\nSubmissionReview:\n  SubmissionID: 42\n  OriginalName: TinyFn\n---\n\n## Definition\n\n```wl\nTinyFn[x_] := x\n```\n", "Evaluate" -> False],
            Notebook[_, ___, TaggingRules -> t_, ___] :> t, {}, {0}],
        "SubmissionReviewData"],
    {"Review" -> True, "SubmissionID" -> "42", "OriginalName" -> "TinyFn"},
    TestID -> "FunctionResourceReview writes the SubmissionReview mapping as SubmissionReviewData"
]