Skip to content

Containers, quotes and fences

Divs, block quotes, code and comment fences: nesting, lazy continuation, absorption and what closes what.

Generated from resources/examples/edge-cases.md, resources/examples/core.md and resources/examples/extensions.md - edit the cases there, not here. Each case links the conformance fixture it produces.

Fenced code shorter inner fence

1 conformance fixture

A code-fence closer must use the same character and be at least as long as the opener — a shorter run inside is literal content.

carve
```
line
``
still code
```
html
<pre><code>line
``
still code
</code></pre>

Blockquote caption after a blank line

1 conformance fixture

One blank line is allowed between a block and its ^ caption; the quote becomes a <figure> with a <figcaption>.

carve
> quote text

^ Source: Someone
html
<figure>
  <blockquote><p>quote text</p></blockquote>
  <figcaption>Source: Someone</figcaption>
</figure>

Opaque spans inside a container

6 conformance fixtures

A container collects its body by scanning for its closer. A code fence, a raw block and a comment block are opaque: their contents are content, not markup, so a colon fence written inside one closes nothing. This is what lets a document about Carve show a container fence at all - under exact-length closers the code fence is the only structural way to quote one.

carve
::: note
```
:::
```
body
:::
after
html
<aside class="admonition note">
  <pre><code>:::
</code></pre>
  <p>body</p>
</aside>
<p>after</p>

The opener carrying no info string is the case that hides the bug: the opener line is closer-shaped itself, so an implementation that tests it before consuming it ends the span where it began (carve#450). A tilde fence behaves the same.

carve
::: note
~~~
:::
~~~
body
:::
after
html
<aside class="admonition note">
  <pre><code>:::
</code></pre>
  <p>body</p>
</aside>
<p>after</p>

A container opener inside the span is content too. Under exact-length closers this one is load-bearing: read as markup it would push a nesting level and put every following closer one level off.

carve
::: note
```text
::: tip
```
body
:::
after
html
<aside class="admonition note">
  <pre><code class="language-text">::: tip
</code></pre>
  <p>body</p>
</aside>
<p>after</p>

A comment block is opaque in the same way. It renders nothing at all, so what this pins is where the container ends.

carve
::: note
%%%
:::
%%%
body
:::
after
html
<aside class="admonition note">
  <p>body</p>
</aside>
<p>after</p>

Only a fence that CLOSES is opaque. An opener with no closer ahead opens no span at all, so the container's own closer stays structural and the lines after it are parsed normally. Without this one unclosed fence would swallow the rest of the document - the ::: and after below would both render inside the code block, and the admonition would close at end of input.

The %%% rule already worked this way; the code fence did not, in any of the three engines, because the spec had only ever written it down for %%%.

carve
::: note
```
x
:::
after
html
<aside class="admonition note">
  <pre><code>x
</code></pre>
</aside>
<p>after</p>

A fence with nothing to take structure away from is unaffected: alone, or as the whole content of a blockquote, an unterminated fence still opens a code block that runs to the end.

carve
> ```
html
<blockquote>
  <pre><code>
</code></pre>
</blockquote>

Blockquote lazy continuation

6 conformance fixtures

A line that follows a > line, is not blank, and does not begin its own block continues the blockquote — the > may be omitted on continuation lines (CommonMark-style). A blank line ends the quote.

carve
> quoted
continued
html
<blockquote><p>quoted
continued</p></blockquote>

A block-opener is not a lazy continuation: it ends the quote and starts that block outside it. A list marker — bullet or ordered — folds in, though: a quoted line ends in an open paragraph, and a list marker folds into an open paragraph (§10), exactly as at the top level. So > quoted then - item is one quote whose paragraph is quoted + - item, not a quote plus a sibling list. (A heading, a bounded title, is still ended by a list marker; to put a real list in a quote, >-prefix it or use the + continuation marker.)

carve
> quoted
- item
html
<blockquote><p>quoted
- item</p></blockquote>

The fold needs an open paragraph to fold into. When the last quoted line is a heading (or any block that is not an open paragraph), there is nothing to fold into, so the list marker ends the quote and starts a top-level list — exactly as # h then - item does at the top level.

carve
> # h
- item
html
<blockquote>
  <h1 id="h">h</h1>
</blockquote>
<ul>
  <li>item</li>
</ul>

The open-paragraph condition is not about list markers. Plain lazy text needs one too, and the same closed blocks leave none - so the quote ends and the line becomes a top-level paragraph.

This is the case the list-marker example above does not reach, and every engine had a defect in it: carve-php kept the quote open after a heading, and carve-js and carve-php both kept it open after the two below.

carve
> # h
b
html
<blockquote>
  <h1 id="h">h</h1>
</blockquote>
<p>b</p>

A definition term is bounded the same way. It holds inline content, not a paragraph, so there is nothing for the next line to continue.

carve
> :: t
~
html
<blockquote>
  <dl>
    <dt>t</dt>
  </dl>
</blockquote>
<p>~</p>

An invisible definition leaves nothing on the page at all, which is the clearest case of the rule: there is no paragraph because there is no output.

carve
> [f]: ~
/
html
<blockquote>

</blockquote>
<p>/</p>

Fenced code language with punctuation

1 conformance fixture

A language tag may contain punctuation (c++, c#, f#, asp.net). The info string is still a single token, so a multiword or quoted info (e.g. js title="x") is not a fence.

carve
```c++
int main() {}
```
html
<pre><code class="language-c++">int main() {}
</code></pre>

Blockquote lazy continuation stops at a fenced block

3 conformance fixtures

Lazy continuation only extends an open paragraph. A non-> line that lands inside an open fenced code block ends the quote instead of being swallowed into the code. After the quote ends, b starts a paragraph and the trailing > c interrupts it into a fresh block quote (§10 — a > marker interrupts a paragraph). In the second example the mid-paragraph ``` has no closer, so it does not interrupt (§10 closer lookahead); it is then an unclosed inline verbatim run that renders as a <code> span to the end of the block (matching djot and carve-php), and the lazy line still folds in.

carve
> ```
> a
b
> c
html
<blockquote>
  <pre><code>a
</code></pre>
</blockquote>
<p>b</p>
<blockquote><p>c</p></blockquote>
carve
> text
> ```
lazy
html
<blockquote><p>text
<code>
lazy</code></p></blockquote>

When the fence opener is immediately followed by a non-> line — with no marked content line in between — the fence is never closed (an empty code block), and the non-> line ends the quote. The trailing > still then opens a fresh block quote.

carve
> ```
code no marker
> still
html
<blockquote>
  <pre><code>
</code></pre>
</blockquote>
<p>code no marker</p>
<blockquote><p>still</p></blockquote>

Nested comment fences

1 conformance fixture

A longer comment fence may contain a shorter one as content - the block ends only at a fence of the opener's length.

carve
before

%%%%
hidden %%% inner fence stays hidden
%%%%

after
html
<p>before</p>
<p>after</p>

Indented colon-fence blocks stay literal

4 conformance fixtures

A ::: line opens a container only at column 0. Indented by a space it is not a fence opener, so the marker, the body, and the closing marker all fold into one literal paragraph. This holds for a bare div, a ::: | line block, and a named admonition alike.

An indented bare ::: div stays literal.

carve
 :::
 A box.
 :::
html
<p>:::
A box.
:::</p>

An indented ::: | line block stays literal.

carve
 ::: |
 Roses,
 Violets.
 :::
html
<p>::: |
Roses,
Violets.
:::</p>

An indented ::: note admonition stays literal.

carve
 ::: note
 Body.
 :::
html
<p>::: note
Body.
:::</p>

Control - flush left at column 0 the same ::: opens a div.

carve
:::
A box.
:::
html
<div>
  <p>A box.</p>
</div>

Below-content-column div body in a list item stays literal

1 conformance fixture

Inside a list item the block openers key on the item content column, not column 0. A ::: note sitting at the marker on the item's first line opens no container when its body and closing marker sit below the content column: they are lazy paragraph continuations, so the whole run - including the ::: note opener line - folds into the item as literal text rather than an admonition.

carve
- ::: note
 - para text
 :::
html
<ul>
  <li>::: note
- para text
:::</li>
</ul>

Comment fence with trailing text

1 conformance fixture

A %%% fence line is a delimiter plus an insignificant tail: only the leading run of % is structural, so %%% html opens a comment and %%% end closes one. No separating space is required, and %%% has no info string - a raw passthrough block is a code fence with an =FORMAT info string - so the body stays hidden and the following block still renders.

carve
before

%%% html
secret
%%% end

after
html
<p>before</p>
<p>after</p>

Unterminated comment fence

1 conformance fixture

A %%% opener with no matching closer ahead does not open a block. The line degrades to a %% line comment, so every following block still renders. This is deliberately not the unclosed-::: rule (PART 9 §12), where the opener opens and the container closes at the end of the input: a comment block is invisible either way, so failing closed costs nothing here, whereas the same choice on a container turned one mistyped closer into a tail of literal text. A tail on the opener (%%% TODO) changes nothing.

carve
before

%%%
secret

after
html
<p>before</p>
<p>secret</p>
<p>after</p>

Widened verbatim fences

1 conformance fixture

A verbatim run widens so its content can hold a shorter backtick run: the span ends at a run of EXACTLY the opening width, and any shorter run inside is content. That applies uniformly to the whole verbatim family - inline code, the inline literal, and both math forms - because each is the same backtick run with a different sigil in front.

Worth pinning because a highlighter or engine that only handles the one- and two-backtick widths closes at the first shorter run inside a wider fence and leaks the rest of the span as prose, which is exactly what happened in the highlight.js grammar (markup-carve/carve-grammars#52). No other corpus case uses a fence wider than two backticks for these constructs.

carve
A ```span with `` inside``` stays one code span.

A !```literal with `` inside``` stays prose.

Then $```a `` b``` ends the run.

$$```x `` y```
html
<p>A <code>span with `` inside</code> stays one code span.</p>
<p>A literal with `` inside stays prose.</p>
<p>Then <span class="math inline">\(a `` b\)</span> ends the run.</p>
<p><span class="math display">\[x `` y\]</span></p>

A comment is recognized at any column

1 conformance fixture

Every other construct below an item's content column folds as text (§24 C3), but a comment is invisible by nature and authors indent one freely, so it is found wherever it sits. Folding it would make %% c visible, which is the one outcome a comment may never have. The item stays open, so a following line still belongs to it.

carve
- a
 %% c
b
html
<ul>
  <li>a
    b
  </li>
</ul>

A comment fence is a comment at any column too

1 conformance fixture

§24 C3 recognizes a comment at any column, and that covers the fence form as well as the %% line: an indented %%% opener below an item's content column stays invisible, along with the body it encloses. Rendering the opener as text would put the comment on the page, which is what the rule exists to prevent.

carve
- a
 %%% n
 x
 %%%
 tail
html
<ul>
  <li>a
    tail
  </li>
</ul>

A comment under a nested item does not close it

1 conformance fixture

A comment renders nothing, so it cannot decide which item the line after it belongs to. Remove the comment and b folds into the inner item; with it there, b must still fold into the inner item. An invisible construct has no structural effect - §28's comment_line makes the indentation part of the construct rather than a column measurement.

carve
- - a
 %% c
 b
html
<ul>
  <li>
    <ul>
      <li>a
        b
      </li>
    </ul>
  </li>
</ul>

A definition inside a comment registers nothing

1 conformance fixture

A comment's body is opaque, and that covers the lines that render nothing of their own. A link reference or footnote definition written inside %%% registers no label, so a reference to it elsewhere stays literal. A definition that registered from inside a comment would be invisible in the output and active in the link table at once - a reference resolving against text the author commented out.

carve
%%%
[r]: /u
%%%
[r][]
html
<p>[r][]</p>

A comment fence at an item's content column registers nothing either

1 conformance fixture

%%% at a list item's content column is the same construct as %%% at column 0. PART 9 §24 S1 places a line by the column it REACHES and never by its first character, S2 makes a line verbatim as soon as the innermost matched container is a fenced body, and §28 makes a comment fence's body verbatim and invisible. Not one of the three is scoped to column 0, so what "A definition inside a comment registers nothing" states above holds wherever the fence sits: the label is not registered, and the reference to it stays literal.

carve
- item
  %%%
  [r]: /url
  %%%

[r][]
html
<ul>
  <li>item</li>
</ul>
<p>[r][]</p>

The corpus stated the rule and pinned only the column-0 spelling, which is the gap two engines drifted through while staying green: carve-rs and carve-php both collected the label here and resolved the reference, where carve-js and the executable spec leave it literal (carve#1309, markup-carve/carve-rs#1047, markup-carve/carve-php#1349). carve-rs has since been fixed and reproduces this document (markup-carve/carve-rs#1052); carve-php still collects the label. Nothing about the item's own rendering was ever in question - all three render the comment as nothing and the item as item. The disagreement is entirely in the link table, which is why the document has to be read past the list to see it at all.

A footnote definition inside an item's comment registers nothing

1 conformance fixture

The footnote collector is a separate pass from the link-reference one in every implementation, so it is a separate place to drift and needs its own document. The rule is the same rule, and the symptom is worse: a collected footnote definition does not merely resolve a reference, it emits an endnotes section the author commented out.

carve
- item
  %%%
  [^f]: note body
  %%%

text[^f]
html
<ul>
  <li>item</li>
</ul>
<p>text[^f]</p>

A comment fence opened on an item's marker line hides its body too

1 conformance fixture

The fence may open on the marker line itself. - %%% is a bullet whose content begins with a comment fence, the closer sits at the content column, and the item is empty of everything between them. This is the spelling a container-aware reader is most likely to miss, because the fence's own line carries the marker rather than the indentation.

carve
- %%%
  [r]: /url
  %%%

[r][]
html
<ul>
  <li></li>
</ul>
<p>[r][]</p>

A comment fence one item deeper registers nothing either

1 conformance fixture

Nothing in §24 S2 counts containers, so a second level of nesting is not a second rule. The fence sits at the inner item's content column and hides its body exactly as it does at the outer one.

carve
- a
  - b
    %%%
    [r]: /url
    %%%

[r][]
html
<ul>
  <li>a
    <ul>
      <li>b</li>
    </ul>
  </li>
</ul>
<p>[r][]</p>

A wider comment fence inside an item hides its body the same way

1 conformance fixture

Fence WIDTH decides which line closes the fence (§28's exact-length closer), not whether the body is opaque. A four-percent fence at an item's content column is as invisible to the definition collector as a three-percent one, so the two axes stay independent.

carve
- item
  %%%%
  [r]: /url
  %%%%

[r][]
html
<ul>
  <li>item</li>
</ul>
<p>[r][]</p>

An abbreviation inside a comment defines nothing

1 conformance fixture

The abbreviation collector is a third pass again, and this is the one document in the group that has to sit at column 0: PART 12 §7 recognizes an abbreviation definition only as a direct child of the DOCUMENT, so an abbreviation written inside an item's comment is already not a definition for a reason that has nothing to do with the comment, and a document written that way could not tell the two reasons apart. At column 0 both reasons are live and only the comment is doing the work.

carve
%%%
*[HTML]: HyperText Markup Language
%%%

HTML here
html
<p>HTML here</p>

Its position makes it look like the link-reference case above, and the collector it exercises makes it a different document: carve-php reads the link-reference form of this shape correctly and defines the abbreviation anyway (markup-carve/carve-php#1349). An abbreviation is the worst of the three to leak, because the use site carries no bracket to give it away - the term is rewritten in running prose that never asked for it.

A comment fence inside a colon container registers nothing

1 conformance fixture

A colon container's body is parsed as blocks, so a comment fence inside one is a comment fence and its body is opaque for the same reason it is anywhere else.

carve
::: note
Body.

%%%
[r]: /url
%%%
:::

[r][]
html
<aside class="admonition note">
  <p>Body.</p>
</aside>
<p>[r][]</p>

The quoted spelling is pinned too, under A comment fence reached through a quote registers nothing either at the end of this file. It sits there rather than here only so that adding it renumbers no existing section.

A comment fence reached through a quote registers nothing either

3 conformance fixtures

The last of the three columns a comment fence can sit at. markup-carve/carve#1309 ruled that a definition inside a comment fence is not registered wherever the fence sits, and the corpus pinned the column-0 spelling and the indented one inside a list item. The quoted spelling was left out on the grounds that all three engines registered there, which made it a disagreement rather than a coverage gap - a carve-out that expired once the three engine tickets existed (markup-carve/carve#1341, markup-carve/carve-js#1177, markup-carve/carve-php#1402, markup-carve/carve-rs#1078).

Nothing scopes the fence by container. comment_block gives its body as {character | newline}, verbatim, and §28 and §24 C3 name no container anywhere; a rule that distinguished a fence reached through a > prefix from one reached through indentation would make the same four lines register or not by their prefix. The quote is empty in all four implementations, so the fence IS consumed as a comment - and the definition inside it is then read by a later pass that was looking at lines the block parser had already swallowed.

A link reference definition:

carve
> %%%
> [r]: /url
> %%%

See [r][].
html
<blockquote>

</blockquote>
<p>See [r][].</p>

The same fence over a footnote definition. Both kinds are here because the leak sorts definitions BY KIND, which is the evidence that no rule is being followed: carve-js registers the reference above and leaves this note literal, while carve-php and carve-rs register both. A single-kind document would let carve-js pass on the half it happens to get right.

carve
> %%%
> [^f]: note
> %%%

See [^f].
html
<blockquote>

</blockquote>
<p>See [^f].</p>

The control is the same two definitions with the fence taken away. They register document-wide from inside a quote in all four implementations, so what the documents above pin is the comment, not the quote:

carve
> [r]: /url
> [^f]: note

See [r][] [^f].
html
<blockquote>

</blockquote>
<p>See <a href="/url">r</a> <a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a>.</p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>note<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

The abbreviation kind is deliberately absent, for the reason An abbreviation inside a comment defines nothing gives above: PART 12 §7 recognizes an abbreviation definition only as a direct child of the DOCUMENT, so > *[ab]: abbrev defines nothing whether a comment fence wraps it or not - all four implementations leave the use literal either way. A document written that way could not tell the two reasons apart, and it is pinned at column 0 instead, where only the comment is doing the work.

A blank after a comment still ends the item

1 conformance fixture

A comment renders nothing, so it neither closes the item nor holds it open across a blank line. The blank does what a blank always does: it ends the item, and the indented line after it is a document-level paragraph rather than item content.

carve
- - a
 %% c

 b
html
<ul>
  <li>
    <ul>
      <li>a</li>
    </ul>
  </li>
</ul>
<p>b</p>

A comment fence under a nested item does not close it either

1 conformance fixture

The fence form behaves as the %% line does: it is invisible, it leaves the item open, and the line after it folds into the inner item exactly as it would with no comment between.

carve
- - a
 %%% c
 x
 %%%
 b
html
<ul>
  <li>
    <ul>
      <li>a
        b
      </li>
    </ul>
  </li>
</ul>

A comment ends the paragraph it sits under

1 conformance fixture

Staying open is not the same as staying in the same paragraph. A comment renders nothing, but it is still a block boundary: the line after it begins the item's second paragraph. A tight list renders both readings identically, which is why the distinction needs a loose one to show at all - and why the rule went unstated while the sentence above it appeared to promise the opposite.

carve
- a
  %% x
 b

- c
html
<ul>
  <li><p>a</p>
    <p>b</p>
  </li>
  <li><p>c</p></li>
</ul>

A quote marker is > plus a space, and a lazy line keeps its own text

1 conformance fixture

>text with no space is prose, not a quote marker (§10 I1). Inside an open quoted paragraph such a line folds in as lazy continuation and keeps its >, rather than being read as a marker and stripped.

carve
> ok
>bad
html
<blockquote><p>ok
&gt;bad</p></blockquote>

A block-attribute line inside a quote ends the paragraph above it

1 conformance fixture

§10 I5 lists the block-attribute line among the invisible constructs that interrupt an open paragraph, and that holds inside a container as much as at the top level: the paragraph ends, and the attributes attach to the block that follows.

carve
> a
> {.c}
> text
html
<blockquote>
  <p>a</p>
  <p class="c">text</p>
</blockquote>

A floating attribute is scoped to the container that holds it

10 conformance fixtures

PART 9 §15 A2 says a pending {...} applies to the next block. That answers which BLOCK, not which container, and containment already bounds everything else in the language — so an attribute written inside a quote, an item or a dd does not survive that container's end (markup-carve/carve#1281).

A4 already dropped an attribute with no block left to attach to; a container's end is the second way to run out of blocks, and it drops the same way. Neither is silent: both are reported as unattached-block-attribute.

The attribute does not escape over a blank line onto a document-level paragraph — tail here is unclassed:

carve
> q
> {.k}

tail
html
<blockquote><p>q</p></blockquote>
<p>tail</p>

Without the blank line the answer is the same, and it composes with §S4: the attribute leaves no open paragraph, so the flush-left line ends the quote rather than joining it, and A4 then has nothing left to attach to.

carve
> q
> {.k}
tail
html
<blockquote><p>q</p></blockquote>
<p>tail</p>

A list item is the same container question:

carve
- a
  {.k}

tail
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>

And the attribute does not reach FORWARD out of the item to pull a block in either. The heading stays outside and stays unclassed:

carve
- a
  {.k}
# H
html
<ul>
  <li>a</li>
</ul>
<section id="H">
  <h1>H</h1>
</section>

A definition body ends the same way:

carve
:: t
:  d
   {.k}
tail
html
<dl>
  <dt>t</dt>
  <dd>d</dd>
</dl>
<p>tail</p>

An attribute block may WRAP across lines (§15 A5), and one block is one block however many lines it takes — a body ending {.k / #x} closes the same way as a body ending {.k}:

carve
:: t
:  d
   {.k
   #x}
tail
html
<dl>
  <dt>t</dt>
  <dd>d</dd>
</dl>
<p>tail</p>

Scoped, not disabled

The controls are what keep "scoped" from reading as "dropped". Inside its own container the attribute attaches exactly as it always has — in a quote:

carve
> {.k}
>
> tail
html
<blockquote><p class="k">tail</p></blockquote>

in a list item:

carve
- a
  {.k}
  # H
html
<ul>
  <li>a
    <h1 class="k" id="H">H</h1>
  </li>
</ul>

in a definition body:

carve
:: t
:  d
   {.k}
   # H
html
<dl>
  <dt>t</dt>
  <dd>
    <p>d</p>
    <h1 class="k" id="H">H</h1>
  </dd>
</dl>

and at the top level, where the document is the container and a blank line ends nothing:

carve
{.k}

tail
html
<p class="k">tail</p>

A comment fence at column 0 ends the item; a %% line does not

2 conformance fixtures

Both spellings stay invisible wherever they sit (§24 C3). They differ in what they do to the item above them: a flush-left %%% fence ends it, so the next line belongs to the document, while a flush-left %% line leaves the item open and that line folds in. An INDENTED fence stays with the item either way.

carve
- a
%%%
c
%%%
b
html
<ul>
  <li>a</li>
</ul>
<p>b</p>

The line form, same columns, different answer:

carve
- a
%% c
b
html
<ul>
  <li>a
    b
  </li>
</ul>

Two backticks are not a code fence, opening or closing

2 conformance fixtures

A fence opens on three or more. Two backticks are an inline code span, so the lines between them become its content instead of a code block.

carve
``
code
``
html
<p><code>
code
</code></p>

The closer is the same length rule seen from the other side: a two-backtick line inside an open fence is CONTENT, not the end of the block.

carve
```
code
``
still code
```
html
<pre><code>code
``
still code
</code></pre>

A single percent is not a comment

1 conformance fixture

A comment line opens on %%. One percent is ordinary text, which matters because the character is common in prose.

carve
% not a comment
html
<p>% not a comment</p>

A multi-line raw block is placed at its opening and verbatim after it

2 conformance fixtures

A raw block's content reaches the target unchanged, so a renderer that indents its output indents the block's OPENING position - the way it would any other block - and leaves every line after the first on the columns the author gave it. The corpus pinned only a single-line raw block, which is the one shape where "indent the block" and "indent every line" agree, so three engines could pass it while giving three different answers here.

carve
[^a]: note

  ```=html
  <b>x</b>
  <i>y</i>

see[^a]


```html
<p>see<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>note</p>
      <b>x</b>
<i>y</i>
      <p><a href="#fnref1" role="doc-backlink">↩</a></p>
    </li>
  </ol>
</section>

Inside a <pre> the difference is CONTENT rather than layout: two columns added to each line change what the rendered code block says.

carve
> ```=html
> <pre>
> a
>   b
> </pre>
> ```
html
<blockquote>
  <pre>
a
  b
</pre>
</blockquote>

An absorbed colon fence leaves a block quote's paragraph open

4 conformance fixtures

The item form of PART 9 §12's absorption is pinned above, under Lazy continuation. The BLOCK QUOTE form was not pinned anywhere, and it is the same clause reached through a different container, so an engine could get the quote wrong indefinitely without any document moving - which is what happened (markup-carve/carve-rs#727).

:::note has no space between the fence and the type word, so §12's opener test rejects it: it opens no block and is ordinary paragraph text. From that point the paragraph absorbs the next fence-shaped line as text too, instead of being interrupted by it. Nothing ever interrupted the quote's paragraph, so it is still open when tail arrives at column 0, and PART 1 S4 folds tail in. The quote's own prefix is missing on that line, which is exactly the partial match S4 is written for:

carve
> quote
> :::note
> body
> :::
tail
html
<blockquote><p>quote
:::note
body
:::
tail</p></blockquote>

The absorption is not width-tagged. A four-colon run under a three-colon :::note is fence-shaped too, and it is absorbed on the same terms - the paragraph is not looking for a matching closer, because no block was ever opened for it to close:

carve
> quote
> :::note
> body
> ::::
tail
html
<blockquote><p>quote
:::note
body
::::
tail</p></blockquote>

The malformed fence may be the quote's first line. There is no preceding prose for the paragraph to have been opened by, so the absorbed line opens it - and the rest follows unchanged:

carve
> :::note
> :::
tail
html
<blockquote><p>:::note
:::
tail</p></blockquote>

It holds at depth two, where the flush-left line matches neither prefix. S4 folds it into the innermost open paragraph rather than closing one quote per missing marker:

carve
> > quote
> > :::note
> > body
> > :::
tail
html
<blockquote>
  <blockquote><p>quote
:::note
body
:::
tail</p></blockquote>
</blockquote>

Give the same fence its space and the answer inverts, exactly as it does in an item: written ::: note it is a valid opener, it interrupts the quote's paragraph, and its closer completes the block - so nothing is open when tail arrives. One space decides which of the two answers the same five lines get.

A real div in a container and the flush-left line after it

3 conformance fixtures

PART 1 S4 folds a flush-left line into the innermost open paragraph, and folds nothing when there is none. A REAL ::: div - one whose opener passes PART 7's separator test, so it is a block and not absorbed paragraph text - makes that clause decide two ways depending on what the div holds when the line arrives.

An UNTERMINATED div holding a paragraph has an open paragraph in the stack, so the flush-left line folds into it. An unterminated div holding NOTHING has none, so the line ends the container instead. The two documents differ by one line of body, and that line is the whole rule (carve#909).

carve
- item
  ::: note
  body
tail
html
<ul>
  <li>item
    <aside class="admonition note">
      <p>body
tail</p>
    </aside>
  </li>
</ul>

The same shape with an empty div. Nothing in the stack holds an open paragraph when tail arrives - the item's own paragraph was closed by the div that followed it, and the div itself is empty - so S4 folds nothing and the line is a top-level paragraph.

carve
- item
  ::: note
tail
html
<ul>
  <li>item
    <aside class="admonition note">

    </aside>
  </li>
</ul>
<p>tail</p>

CONTROL, and the reason the rule is about an UNTERMINATED div. Close the div and the paragraph inside it closes with it, so the first document's answer inverts on the strength of one ::: line. This pins behavior that does not change.

carve
- item
  ::: note
  body

tail


```html
<ul>
  <li>item
    <aside class="admonition note">
      <p>body</p>
    </aside>
  </li>
</ul>
<p>tail</p>

:::

A note on the spelling, because it is what made this look like a four-way split when carve#909 was written. The shapes there are spelled :::note, with no separator. PART 7 has since narrowed the colon fence's separator to a space (carve#900, carve#905), so :::note no longer passes the opener test at all: it is ABSORBED as paragraph text, and the answer for it comes from §12's absorption rule and carve#902 rather than from S4. That row is already pinned by 86-list-lazy-continuation-9 and already declared in resources/engine-pin-drift.txt. The documents above use ::: note, which is a div.

The flush-left line after a container a quoted line opened

4 conformance fixtures

The item form of PART 1 S4's NO OPEN PARAGRAPH, NO LAZY LINE is pinned above, under A real div in a container. The BLOCK QUOTE form was not pinned anywhere (markup-carve/carve#920), and the two containers were answering the same question differently: a list item closed and put the flush-left line at top level, while a block quote kept it.

The stack after > ::: note holds a quote and an EMPTY div. S4 asks whether ANY container in it holds an OPEN paragraph, and none does - the quote's own paragraph was closed by the div opener, and the div has no content yet. So tail supplies no prefix, nothing is open for it to fold into, both containers close, and it is a top-level paragraph:

carve
> quote
> ::: note
tail
html
<blockquote>
  <p>quote</p>
  <aside class="admonition note">

  </aside>
</blockquote>
<p>tail</p>

Closing the div does not change the answer, because a CLOSED container holds no open paragraph either. Both the empty form and the form with a body land the same way, and they are the block-quote twins of the list-item documents above:

carve
> quote
> ::: note
>
> :::
tail
html
<blockquote>
  <p>quote</p>
  <aside class="admonition note">

  </aside>
</blockquote>
<p>tail</p>
carve
> quote
> ::: note
> body
> :::
tail
html
<blockquote>
  <p>quote</p>
  <aside class="admonition note">
    <p>body</p>
  </aside>
</blockquote>
<p>tail</p>

The last document is the one place §12's absorption and S4 meet, and they are decided by WHOSE line it is. :::note has no separator, so it opens nothing and is absorbed as paragraph text - and the quoted > ::: under it is absorbed on the same terms, which is what An absorbed colon fence leaves a block quote's paragraph open pins. A FLUSH-LEFT ::: is not one of the quote's lines: it supplies no > prefix and would reach that paragraph only by S4's lazy fold. The strict column-0 rule decides it instead. The quote closes and the line is re-classified at top level, where it opens a div of its own:

carve
> quote
> :::note
> body
:::
html
<blockquote><p>quote
:::note
body</p></blockquote>
<div>
</div>

A column-0 line after a container's last block, when that block left no paragraph open

29 conformance fixtures

PART 1 S4's NO OPEN PARAGRAPH, NO LAZY LINE is pinned above for an empty quote, which reads as though EMPTINESS were the property doing the work. It is not. The parameter S4 names is whether any container in the open stack holds an open paragraph, and a block that leaves none leaves none wherever it was written: - # H puts a heading in the item exactly as an indented # H would.

So a flush-left line after a heading, a table, a break, a comment, a definition or an attribute block ends the item, and each of these is the same derivation a block quote already got in every engine (markup-carve/carve#1280).

A heading is a bounded title. Nothing is open after it:

carve
- # H
tail
html
<ul>
  <li>
    <h1 id="H">H</h1>
  </li>
</ul>
<p>tail</p>

The block quote spelling of the same document, which every engine already read this way. The two containers are one rule, and this is the pair that says so:

carve
> # H
tail
html
<blockquote>
  <h1 id="H">H</h1>
</blockquote>
<p>tail</p>

A table ends at its last row:

carve
- | a | b |
tail
html
<ul>
  <li>
    <table>
      <tbody>
        <tr><td>a</td><td>b</td></tr>
      </tbody>
    </table>
  </li>
</ul>
<p>tail</p>

A thematic break holds nothing at all:

carve
- ---
tail
html
<ul>
  <li>
    <hr>
  </li>
</ul>
<p>tail</p>

A comment is invisible, and invisible is not open. The item renders empty rather than absorbing the line below it:

carve
- %% c
tail
html
<ul>
  <li></li>
</ul>
<p>tail</p>

The fence spelling of a comment answers the same way. Its closer travels with its opener, and what follows the closer is outside the item:

carve
- %%%
c
%%%
tail
html
<ul>
  <li></li>
</ul>
<p>c</p>
<p>tail</p>

A link reference definition is metadata. Ending the item disposes of the line BELOW it, never of the definition itself - §17 L6 collects that from wherever it was written, and the use below still resolves:

carve
- [r]: /u
tail

[r][]
html
<ul>
  <li></li>
</ul>
<p>tail</p>
<p><a href="/u">r</a></p>

A footnote definition, the same both ways:

carve
- [^f]: t
tail

see[^f]
html
<ul>
  <li></li>
</ul>
<p>tail</p>
<p>see<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>t<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

An attribute block opens no paragraph either, so it never reaches the line below

  • the item ends first, and the attribute is left unconsumed:
carve
- {.k}
tail
html
<ul>
  <li></li>
</ul>
<p>tail</p>

A sibling marker after the same shape still opens a sibling, which is the control for "the item ended" rather than "the item swallowed something":

carve
- # H
- next
html
<ul>
  <li>
    <h1 id="H">H</h1>
  </li>
  <li>next</li>
</ul>

The question is asked of a quote RECURSIVELY, so a quote is not automatically an open paragraph either - what decides is the block the quote itself ends on:

carve
- > # H
tail
html
<ul>
  <li>
    <blockquote>
      <h1 id="H">H</h1>
    </blockquote>
  </li>
</ul>
<p>tail</p>

The two that still fold, because a paragraph IS open

The rule has one parameter, so the controls are the documents where that parameter has the other value. A nested quote's trailing paragraph is open, and the line folds into it:

carve
- > q
tail
html
<ul>
  <li>
    <blockquote><p>q
tail</p></blockquote>
  </li>
</ul>

And plain lead text is the ordinary lazy continuation, untouched by any of this:

carve
- a
tail
html
<ul>
  <li>a
tail</li>
</ul>

The unmatched item's last block may itself be a list

The clause binds "even where the unmatched container is a LIST ITEM whose last block is a container", and a nested list is that container. So the question is asked of the nested item's own last block, recursively, exactly as it is asked of a quote's - and it is asked however deep the nesting runs.

Read as prose instead, the marker line answers "paragraph" every time, and the tell is that depth 1 comes out right while depth 2 does not (markup-carve/carve#1342). The outer item's last block here is a list whose item ends on a heading, so nothing is open and tail is a document paragraph:

carve
- - # H
tail
html
<ul>
  <li>
    <ul>
      <li>
        <h1 id="H">H</h1>
      </li>
    </ul>
  </li>
</ul>
<p>tail</p>

A comment as the nested item's only block reaches the same answer by the same route, which is how one knows the depth and not the construct is what was missing:

carve
- - %% c
tail
html
<ul>
  <li>
    <ul>
      <li></li>
    </ul>
  </li>
</ul>
<p>tail</p>

Depth 3 is the document that locates it. An implementation that unwraps one level and then stops folds tail into the MIDDLE item rather than closing all three, so this pair distinguishes "the rule recurses" from "the rule was applied once":

carve
- - - # H
tail
html
<ul>
  <li>
    <ul>
      <li>
        <ul>
          <li>
            <h1 id="H">H</h1>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
<p>tail</p>

The nested list need not be written on the marker line. A sub-list opened at the item's content column is the same last block, and leaves the same nothing open:

carve
- a
  - # H
tail
html
<ul>
  <li>a
    <ul>
      <li>
        <h1 id="H">H</h1>
      </li>
    </ul>
  </li>
</ul>
<p>tail</p>

The controls are the same three documents with a paragraph restored at the bottom of the stack. A nested item holding plain text folds, at any depth:

carve
- - a
tail
html
<ul>
  <li>
    <ul>
      <li>a
tail</li>
    </ul>
  </li>
</ul>

So does a nested item ending on a quote that CARRIES a paragraph - the recursion has to pass through both containers to reach it:

carve
- - > q
tail
html
<ul>
  <li>
    <ul>
      <li>
        <blockquote><p>q
tail</p></blockquote>
      </li>
    </ul>
  </li>
</ul>

And the content-column spelling folds too when its sub-item is prose:

carve
- a
  - b
tail
html
<ul>
  <li>a
    <ul>
      <li>b
tail</li>
    </ul>
  </li>
</ul>

An attribute line at the item's content column closes the paragraph too

§10 I5 makes a block-attribute line an interrupter, so an item whose last content line is one holds no open paragraph and the same clause ends it. The attribute was written against a container that ends before the flush-left line arrives, so it reaches nothing and is dropped - it does not travel down to the line below (markup-carve/carve#1342):

carve
- a
  {.x}
tail
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>

Separating the attribute line with a blank changes nothing. The blank does not loosen the item either, because an attribute block renders nothing and §17 L1 asks for a second PARAGRAPH:

carve
- a

  {.x}
tail
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>

The control is what the attribute does reach: a line at the content column is inside the item, the container has not ended, and the attribute attaches to the paragraph it introduces:

carve
- a
  {.x}
  more
html
<ul>
  <li>a
    <p class="x">more</p>
  </li>
</ul>

The quote spelling of the same shape is pinned under A floating attribute is scoped to the container that holds it below, and every engine already read it that way. That the two containers disagreed is what makes the item spelling a defect rather than a second reading.

A continuation-row SHAPE is prose until a table is above it

Every construct above answers S4 by its shape, and one construct cannot. §5 T6 says a table "cannot BEGIN with a continuation row", so a + ...| line reached where no table is open is not a row at all - it is ordinary paragraph text. A continuation row needs a body row pins that already at the document level, where the row that cannot attach renders as a paragraph.

A marker line is its container's FIRST block, so nothing is ever above it, and the line is prose there by construction. The item below publishes it as prose - and then, read by shape alone, told S4 it was a table row, so the item held no open paragraph and tail left it. Prose where it renders, a row where it is asked about (markup-carve/carve#1345):

carve
- + a |
tail
html
<ul>
  <li>+ a |
tail</li>
</ul>

The nested spelling reaches the same first block by the same peel the heading above uses, and answers the same way:

carve
- - + a |
tail
html
<ul>
  <li>
    <ul>
      <li>+ a |
tail</li>
    </ul>
  </li>
</ul>

At the item's CONTENT COLUMN there is a line above, so the question is real rather than settled by position - and a paragraph is not a table. The line joins that paragraph, and tail joins it too:

carve
- a
  + b |
tail
html
<ul>
  <li>a
+ b |
tail</li>
</ul>

A definition body is the third container that asks, and it asks about its last line. As that body's only line, the shape is prose for the marker line's reason:

carve
:: t
:  + a |
tail
html
<dl>
  <dt>t</dt>
  <dd>+ a |
tail</dd>
</dl>

And a line above it is not enough - what the rule wants above it is a TABLE:

carve
:: t
:  a
   + b |
tail
html
<dl>
  <dt>t</dt>
  <dd>a
+ b |
tail</dd>
</dl>

Through a QUOTE the body's last line is asked the same question one container in, and the quote holds a paragraph rather than a table - so the shape is prose there too, and the lazy line reaches all the way down:

carve
:: t
:  > a
   > + b |
tail
html
<dl>
  <dt>t</dt>
  <dd>
    <blockquote><p>a
+ b |
tail</p></blockquote>
  </dd>
</dl>

A list marker at the content column inside an open fence

2 conformance fixtures

A line that LOOKS like a list marker, sitting AT the item's content column inside an open code fence, is CODE TEXT. PART 9 §24's STEP walk decides it with no new rule, and neither of the two steps involved ever reads the line's first character.

Take - x with the stack document > list > item(content_column 2) > code fence body:

  • S1 MATCH PREFIXES consumes each container's prefix in turn. The line supplies the item's two columns, so the walk reaches the item; a fenced body demands no per-line prefix, so the walk reaches that too and stops there.
  • S2 FENCED BODY therefore fires - the innermost MATCHED container IS the fenced body - and the line is verbatim content unless it matches that fence's where-guarded closer. "No other rule applies to L." A marker is never asked about.

The plain-text sibling is already pinned and already passes: 276-a-fence-opened-on-a-list-marker-line-body-below-the-content-column-3 puts x at this exact column and gets a code block holding x. The only difference here is which character follows the indentation, and no step of the walk looks at it. A reader that answers the two differently is recognizing a marker before it has established that the line is markup at all.

carve
- ```
  - x
  ```
html
<ul>
  <li>
    <pre><code>- x
</code></pre>
  </li>
</ul>

The same rule with the fence opened after a BLANK line inside the item rather than on the marker line. It is a SEPARATE row because readers reach the two through different machinery - one continues the item from its marker line, the other collects the item's content after a blank - so a fix applied to one is invisible to the other. A single row would let half of this rule stay broken and still read as done, which is the failure carve-php#1003 had to correct and the reason the ruling on carve-php#1007 asked for both shapes at once.

The item stays TIGHT and a stays bare: PART 9 §17 L2 names fenced code among the sub-blocks a blank line attaches WITHOUT loosening, and no second paragraph ever appears here. 164-tight-list-item-keeps-trailing-text-after-a-block-bare-3 is this same opening plus a trailing paragraph, and that paragraph is what loosens it there.

carve
- a

  ```
  - x
  ```
html
<ul>
  <li>a
    <pre><code>- x
</code></pre>
  </li>
</ul>

Both rows are carried by the engine tickets rather than presented as a cross-reader agreement. No engine answers both shapes this way today, and the three do not fail on the same one, so a red engine corpus job against these two is the measurement the engine work is made against rather than a regression.

A boundary line inside an open fence does not end the container

11 conformance fixtures

PART 9 §17 L3 attaches ONE BLOCK of ANY kind, "up to the next blank line, sibling marker, or a further +". That list bounds the ATTACHED BLOCK, and a block's own extent is settled before the list is ever consulted: a fenced block runs from its opener to its matching closer, so every line between the two is INSIDE the one block L3 attached. A blank line there is not "the next blank line" any more than the closer is "a sibling marker" - it is fence content, and the boundary list never sees it.

The same holds one construct over, for a body collected by INDENTATION rather than by a marker. §24 S1 MATCH PREFIXES places a line by the column it reaches and never by its first character; §24 S2 FENCED BODY then makes the line verbatim when the innermost matched container is a verbatim body; and §28 makes a comment fence's body verbatim and invisible. None of the three asks what the line looks like.

Seven rows, deliberately not one per cell. Each reaches a DIFFERENT collector, and in every reader those collectors are separate loops that a fix to one leaves untouched - which is the failure carve-php#1003 had to correct and the reason 278-a-list-marker-at-the-content-column-inside-an-open-fence needed two rows rather than one. Each of the three fence spellings appears, because the fence kind is a real axis: a reader can survive a code fence and sever a colon fence at the same boundary.

The seventh row arrived late, and why it did is worth recording. The list + collector is the largest severing group of the whole class, and it was the one cell this category could not pin, because the executable spec severed it too: its +-attach extent helpers were spelled twice and only one of the two consulted any fence state (carve#982). A checker is not an argument - THE EXECUTABLE ARTIFACTS DECIDE NOTHING - but a row whose expectation nothing in the repo could hold is not reviewable either. With the checker corrected against L3 the cell became committable, and it is committed here.

A definition line inside an attached code fence

The worst of them, and the reason this category exists. [^z]: zz sits inside an open code fence, so §24 S2 and §28 make it verbatim text: it defines nothing, and §17 L3's boundary list does not name a definition line at ALL, so nothing here ends the attached block early. The note body holds the whole fence.

The + attach into a footnote body is already pinned by 66-footnote-with-multiple-blocks-2; this row only says what a fence inside that attached block does.

What the three readers do instead is worth stating, because it is not a near miss: each of them ends the note body at the definition line, the fence is left unterminated, and b escapes the note entirely to become the document's FIRST block - printed ahead of the paragraph that references the note. A line of verbatim code text moved a block from the end of the document to the beginning.

carve
[^f]: n
+
```
a
[^z]: zz
b
```

see[^f]
html
<p>see<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>n</p>
      <pre><code>a
[^z]: zz
b
</code></pre>
      <p><a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

A blank line inside the same fence

The boundary L3 DOES name, in the one position where it cannot apply. The blank is between the fence's opener and its closer, so it is code text; the attached block ends at the closer, as it did above.

Stated as its own row because the two are different predicates: one reader ends the block on a definition line, the other on a blank, and a fix to either is invisible to the other.

carve
[^f]: n
+
```
a

b
```

see[^f]
html
<p>see<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>n</p>
      <pre><code>a

b
</code></pre>
      <p><a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

The same blank, in a definition list's body

A third row for the same blank line because a dd is collected by a DIFFERENT loop than a footnote body in every reader, and carve-php#1003 is the precedent for one row letting the other half stay broken and still read as done. The + attach into a dd is pinned by 25-definition-lists-3.

carve
:: t
:  d
+
```
a

b
```
html
<dl>
  <dt>t</dt>
  <dd>
    <p>d</p>
    <pre><code>a

b
</code></pre>
  </dd>
</dl>

A definition line inside an attached COLON fence, in a block quote

The same boundary, a different fence kind, and a different answer - which is exactly why the fence kind is its own axis. A colon fence's body is NOT verbatim: it holds blocks, so [^z]: zz really is a definition. §17 L6 collects it and leaves NO TRACE where it was written, and the same clause has it INTERRUPT the open paragraph, so b begins a new one rather than folding back into a.

Two paragraphs, therefore, where the control (the same document without the definition line) has one. What no reading gives is a div that ENDS at the definition line, which is the answer one reader produces.

carve
> q
+
:::
a
[^z]: zz
b
:::
html
<blockquote>
  <p>q</p>
  <div>
    <p>a</p>
    <p>b</p>
  </div>
</blockquote>

A list marker at the body's column inside an item's colon fence

- m sits at the div body's own column zero, and the div body holds blocks, so the question is not §24 S2 this time but §10 I2: LIST MARKERS NEVER INTERRUPT. A marker line folds into the open paragraph as lazy continuation, and §10 I6 applies that to EVERY open paragraph, containers included. So the div holds one paragraph of three lines and ends at its closer.

This is the row that separates the fence kinds most sharply. Put the same marker inside a CODE fence at the same column and §24 S2 answers it instead, which is 278-a-list-marker-at-the-content-column-inside-an-open-fence. Two clauses, two paths, one answer: the line is content. All three readers close the div at the marker, open a real list, and leave a stray empty div behind at the end.

carve
- x
  :::
  a
  - m
  b
  :::
html
<ul>
  <li>x
    <div>
      <p>a
- m
b</p>
    </div>
  </li>
</ul>

A blank line inside an item's comment fence

§28 makes a comment fence's body verbatim AND invisible, so the blank line, the text around it and the closer are all inside the fence and none of them renders. The item is left holding nothing visible, which is <li></li> - 117-footnote-definition-inside-a-container-is-collected-2 and 16-reference-link-4 already pin that shape for an item whose only content is invisible.

The item also stays TIGHT: §17 L1 loosens on a blank-line-separated second PARAGRAPH, and there is no paragraph here at all. A reader that lets this blank line out of the fence gets the opposite of invisible - it prints the comment's body as two paragraphs.

carve
- %%%
  a

  b
  %%%
html
<ul>
  <li></li>
</ul>

The same blank, in a block attached to a LIST ITEM

The fourth collector for the one boundary, and the one that severs hardest. A list item's + attach is a separate loop again - separate from the footnote body, separate from the dd, separate from the block quote - so nothing the other three + rows pin reaches it.

What severing costs here is not a rearranged block but a broken document. End the attached block at the blank and the item keeps a alone, the closing fence is never consumed, and that stray delimiter run opens an EMPTY inline code element at document level: output that no reading of the source licenses, from an input whose only unusual feature is a blank line in a code block. L3 gives the whole fence to the item and leaves nothing at document level but z.

The item also stays TIGHT. §17 L1 loosens on a blank-line-separated second PARAGRAPH; this blank is code text and there is no second paragraph, so it is not the kind of blank L1 asks about.

carve
- x
+
```
a

b
```

z
html
<ul>
  <li>x
    <pre><code>a

b
</code></pre>
  </li>
</ul>
<p>z</p>

A blank line inside an item's INDENTED comment fence, with lead text

The sixth row above is the same fence with the same interior blank, and it passes everywhere. The difference is one word. There the fence opens ON the marker line, so the item holds nothing visible at all and there is no paragraph for looseness to wrap - the tight and the loose answer coincide, and the row cannot see this cell. Put x on the marker line and the two answers separate (carve#985).

§28 makes a comment fence's body verbatim AND invisible, so the blank line, the text around it and the closer are all fence content and none of them renders. §17 L1 loosens an item on a blank-line-separated second PARAGRAPH, and this item has no second paragraph anywhere: L1b says outright that a line rendering nothing "is not a paragraph, which is why it cannot BE the second one". The item is tight, and the document renders exactly one visible thing.

This reaches a collector none of the seven rows above touches. Those pin the extent of the ONE block a + attaches (§17 L3); this is the item collector's OWN blank-line decision, a separate reader of separate state, and a fix to the first leaves it untouched.

carve
- x
  %%%
  a

  b
  %%%
html
<ul>
  <li>x</li>
</ul>

The same item, with the blank line OUTSIDE the fence

The control the row above needs. Same item, same fence, same lead text; the blank line has moved past the closer, where it separates two paragraphs of the ITEM and §17 L1 does loosen.

Without this document the row above is satisfied by a reader that simply stops loosening whenever a comment fence appears in an item, which is not the rule and would be a second defect wearing the first one's answer. The two documents differ only in which side of the closer the blank line sits on, and they must answer differently.

carve
- x
  %%%
  a
  %%%

  b
html
<ul>
  <li><p>x</p>
    <p>b</p>
  </li>
</ul>

A blank line inside an item's indented colon fence, with lead text

The same collector, the other fence kind, and the kind is a real axis here as it is above: a colon fence's body is NOT verbatim, so this blank line is not invisible the way the comment fence's was. It genuinely separates two paragraphs

  • of the DIV.

What it does not do is give the ITEM a second paragraph. §17 L1 asks for a blank-line-separated second paragraph of the item, and the div is ONE block, so the item stays tight and keeps x unwrapped. Both answers are visible in the one output: loose inside the div, tight outside it, from a single blank line. A reader that lets that blank reach the item's looseness scan gets <p>x</p> and an otherwise identical div.

carve
- x
  :::
  a

  b
  :::
html
<ul>
  <li>x
    <div>
      <p>a</p>
      <p>b</p>
    </div>
  </li>
</ul>

The same item, with the blank line OUTSIDE the colon fence

The control for the colon spelling, and it is not redundant with the comment one: the two rows are the two branches of the same tracker, and a reader can carry one kind and miss the other, which is exactly the shape this whole category keeps finding.

Here the blank follows the closer, so the div is one block and b is a second paragraph of the item. The item is loose, and the div's own body - a alone, with no interior blank - is a single paragraph.

carve
- x
  :::
  a
  :::

  b
html
<ul>
  <li><p>x</p>
    <div>
      <p>a</p>
    </div>
    <p>b</p>
  </li>
</ul>

The first seven rows were carried by markup-carve/carve-js#884, markup-carve/carve-php#1049 and markup-carve/carve-rs#802 rather than presented as a cross-reader agreement, because no engine answered the class when they landed. All three engine tickets are closed now. The last four arrive the same way, from markup-carve/carve#985, and the pinned reference build is knowingly behind on the two that pin a defect - declared in resources/engine-pin-drift.txt rather than tolerated.

A container a lazy line folded into is still open

5 conformance fixtures

PART 1 S4's lazy branch ends "and NOTHING closes". That binds the lines AFTER the folded one as much as the folded one itself: a line that comes back to the container's content column is still that container's content, because nothing in the stack was ever closed (markup-carve/carve#980).

Every document already pinned for this rule put the flush-left line LAST - 270-a-real-div-in-a-container-and-the-flush-left-line-after-it does, and so does the block-quote category beside it. That spelling cannot tell a reader that folds and stays open from one that folds and then closes, so the rows below put a line after the fold, which is the only place the two differ.

carve
- x
  :::
  a
d
  b
  :::
html
<ul>
  <li>x
    <div>
      <p>a
d
b</p>
    </div>
  </li>
</ul>

Leaving the div unterminated does not change it. The fold and the reach are the same rule either way, and the closer only matters to a line that arrives after it:

carve
- x
  :::
  a
d
  b
html
<ul>
  <li>x
    <div>
      <p>a
d
b</p>
    </div>
  </li>
</ul>

THE CONTAINER KIND IS NOT A PARAMETER, here as in §24's clause. A block quote inside the item folds and stays open the same way, and its > prefix on the line after the fold reaches the same quote rather than a second one:

carve
- x
  > a
d
  > b
html
<ul>
  <li>x
    <blockquote><p>a
d
b</p></blockquote>
  </li>
</ul>

The same quote written on the item's MARKER line is a third row, because a marker-line container is collected through a different path:

carve
- > a
d
  > b
html
<ul>
  <li>
    <blockquote><p>a
d
b</p></blockquote>
  </li>
</ul>

CONTROL, and the sharp one. When NOTHING in the stack holds an open paragraph the line still ENDS the container, and the line after it is outside too. An empty ::: note has no paragraph, and the item's own paragraph was closed by the div opener, so both d and b are one top-level paragraph. This is the answer that must not move when the rule above is implemented: a reader that keeps the container open here has replaced one over-reach with another.

carve
- x
  ::: note
d
  b
html
<ul>
  <li>x
    <aside class="admonition note">

    </aside>
  </li>
</ul>
<p>d
b</p>

A fence keeps the blank line at the end of its content

4 conformance fixtures

A blank line inside a fence is content, and the last one is content too. That holds wherever the fence ends: at its own closer, at the end of a container, or at the end of the document.

Nothing pinned this before, and all three engines lost the blank independently - each by a different mechanism, and each only on some of the shapes below (markup-carve/carve-js#988, markup-carve/carve-php#1177, markup-carve/carve-rs#908).

carve
```
x

```
html
<pre><code>x

</code></pre>

An unterminated fence runs to the end of the document, and the blank before that end is still its content.

carve
```
x
html
<pre><code>x

</code></pre>

A container's closer ends the fence the same way its own closer would.

carve
::: note
```
x

:::
html
<aside class="admonition note">
  <pre><code>x

</code></pre>
</aside>

So does the end of a list item.

carve
- ```
  x
html
<ul>
  <li>
    <pre><code>x

</code></pre>
  </li>
</ul>

A captioned quote holds more than one block

5 conformance fixtures

A caption makes its host a figure, and PART 9 §4b says a quote is no exception: the quote goes inside a <figure> and the caption becomes its <figcaption>, which is where the HTML Standard puts a quotation's attribution.

Nothing counts the quote's blocks. A multi-paragraph epigraph is ordinary, and so are a quoted list, a nested quote, a quoted code block and a quoted heading. Each one takes its caption the same way, in the same place.

This needed pinning because the executable spec refused every shape but a single paragraph, and no corpus document held any of the others - so the refusal was unreachable, npm run core:check reported every input conformant either way, and the gap was guarded by the absence of a fixture rather than by a decision (markup-carve/carve#1181, the markup-carve/carve#755 class).

carve
> Nothing in this world is certain except death and taxes.
>
> The second of the two arrives rather more often.
^ Benjamin Franklin
html
<figure>
  <blockquote>
    <p>Nothing in this world is certain except death and taxes.</p>
    <p>The second of the two arrives rather more often.</p>
  </blockquote>
  <figcaption>Benjamin Franklin</figcaption>
</figure>

A quoted list. The caption belongs to the quote as a whole, so the list stays the quote's only child and the caption sits outside it.

carve
> - Be skeptical.
> - Be kind.
^ House rules
html
<figure>
  <blockquote>
    <ul>
      <li>Be skeptical.</li>
      <li>Be kind.</li>
    </ul>
  </blockquote>
  <figcaption>House rules</figcaption>
</figure>

A nested quote. The caption attaches to the OUTER quote - the one whose marker column the caption line sits against - so the inner quote carries no caption of its own.

carve
> > I never said that.
^ Quoted in the report
html
<figure>
  <blockquote>
    <blockquote><p>I never said that.</p></blockquote>
  </blockquote>
  <figcaption>Quoted in the report</figcaption>
</figure>

A quoted code block. The <pre> is the quote's only child and the caption still lands beside the quote, which is the case that shows the rule is about the quote rather than about a paragraph.

carve
> ~~~
> git bisect run ./check
> ~~~
^ The release runbook
html
<figure>
  <blockquote>
    <pre><code>git bisect run ./check
</code></pre>
  </blockquote>
  <figcaption>The release runbook</figcaption>
</figure>

A quoted heading. The heading keeps its id, and PART 9R leaves it out of the implicit-reference index because it sits inside a quote - the caption does not change that either way.

carve
> ## Terms
>
> Delivery is at the discretion of the vendor.
^ Appendix B
html
<figure>
  <blockquote>
    <h2 id="Terms">Terms</h2>
    <p>Delivery is at the discretion of the vendor.</p>
  </blockquote>
  <figcaption>Appendix B</figcaption>
</figure>

Composite figures

11 conformance fixtures

A bare ::: figure container is ONE figure holding ordered panels (PART 9 §4c, the figure_group production): its direct captionable children - the figure and table nodes the unchanged inner caption rules build - are the panels, and the ^ line after the closing fence is the caption of the whole group. That closer is caption placement's sixth host (PART 9 §4), and the only ::: kind that takes one. The group renders class-first, the panels nested directly in the group figure - HTML's figure content model admits flow content beside a first-or-last figcaption, so no wrapper element sits between them.

carve
{#fig-x .columns-2}
::: figure
{#fig-x-a}
![one](a.png)
^ (a) One

{#fig-x-b}
![two](b.png)
^ (b) Two
:::
^ Figure #: Group caption
html
<figure class="carve-figure-group columns-2" id="fig-x">
  <figure class="carve-figure-panel" id="fig-x-a">
    <img src="a.png" alt="one">
    <figcaption>(a) One</figcaption>
  </figure>
  <figure class="carve-figure-panel" id="fig-x-b">
    <img src="b.png" alt="two">
    <figcaption>(b) Two</figcaption>
  </figure>
  <figcaption>Figure 1: Group caption</figcaption>
</figure>

The group is one numbering unit (PART 9R R5): its caption's # draws exactly one number from the label's sequence, and that draw also registers the panel ids for cross-references - the group's number plus a letter by panel order. Panels draw nothing themselves.

carve
{#fig-first}
![lead](lead.png)
^ Figure #: First

{#fig-x}
::: figure
{#fig-x-a}
![one](a.png)
^ (a) One

{#fig-x-b}
![two](b.png)
^ (b) Two
:::
^ Figure #: Second

See </#fig-x> and </#fig-x-a>.
html
<figure id="fig-first">
  <img src="lead.png" alt="lead">
  <figcaption>Figure 1: First</figcaption>
</figure>
<figure class="carve-figure-group" id="fig-x">
  <figure class="carve-figure-panel" id="fig-x-a">
    <img src="a.png" alt="one">
    <figcaption>(a) One</figcaption>
  </figure>
  <figure class="carve-figure-panel" id="fig-x-b">
    <img src="b.png" alt="two">
    <figcaption>(b) Two</figcaption>
  </figure>
  <figcaption>Figure 2: Second</figcaption>
</figure>
<p>See <a href="#fig-x">Figure 2</a> and <a href="#fig-x-a">Figure 2a</a>.</p>

A group without a caption is a valid, unnumbered group - no trailing figcaption is emitted.

carve
::: figure
![one](a.png)
^ (a) One

![two](b.png)
^ (b) Two
:::
html
<figure class="carve-figure-group">
  <figure class="carve-figure-panel">
    <img src="a.png" alt="one">
    <figcaption>(a) One</figcaption>
  </figure>
  <figure class="carve-figure-panel">
    <img src="b.png" alt="two">
    <figcaption>(b) Two</figcaption>
  </figure>
</figure>

A one-panel group is a valid parse, not an error (carve lint reports it in strict profiles as figure-group-single-panel).

carve
::: figure
![lone](l.png)
^ The only panel
:::
^ Figure #: One panel is valid
html
<figure class="carve-figure-group">
  <figure class="carve-figure-panel">
    <img src="l.png" alt="lone">
    <figcaption>The only panel</figcaption>
  </figure>
  <figcaption>Figure 1: One panel is valid</figcaption>
</figure>

Direct children that are not captionable hosts are plain group content, preserved in place between the panels - never silently dropped, never re-attached to a panel.

carve
::: figure
Both panels were shot on the same day.

{#fig-s-a}
![one](a.png)
^ (a) One

{#fig-s-b}
![two](b.png)
^ (b) Two
:::
^ Figure #: With a note between the panels
html
<figure class="carve-figure-group">
  <p>Both panels were shot on the same day.</p>
  <figure class="carve-figure-panel" id="fig-s-a">
    <img src="a.png" alt="one">
    <figcaption>(a) One</figcaption>
  </figure>
  <figure class="carve-figure-panel" id="fig-s-b">
    <img src="b.png" alt="two">
    <figcaption>(b) Two</figcaption>
  </figure>
  <figcaption>Figure 1: With a note between the panels</figcaption>
</figure>

The group caption takes the same allowance as every host (PART 9 §4): adjacent or exactly one blank line attaches, two blank lines detach and leave the ^ line an ordinary paragraph.

carve
::: figure
![one](a.png)
^ (a) One
:::


^ Figure #: Detached
html
<figure class="carve-figure-group">
  <figure class="carve-figure-panel">
    <img src="a.png" alt="one">
    <figcaption>(a) One</figcaption>
  </figure>
</figure>
<p>^ Figure #: Detached</p>

Only the figure kind hosts a caption at its closer. A ^ line after any other container's closing fence stays what it always was: ordinary paragraph content.

carve
::: note
Body text.
:::
^ Not a caption
html
<aside class="admonition note">
  <p>Body text.</p>
</aside>
<p>^ Not a caption</p>

An opener carrying a quoted title or a [label] does not match figure_group_open - it stays a generic Tier-2 container, metadata preserved losslessly (carve lint reports figure-group-opener-metadata), and its closer hosts no caption.

carve
::: figure "A titled figure div"
![one](a.png)
^ (a) One
:::
^ Not a group caption

::: figure [g]
Body.
:::
html
<div class="figure">
  <p class="admonition-title">A titled figure div</p>
  <figure>
    <img src="a.png" alt="one">
    <figcaption>(a) One</figcaption>
  </figure>
</div>
<p>^ Not a group caption</p>
<div class="figure">
  <p class="div-label">g</p>
  <p>Body.</p>
</div>

Groups do not nest. A bare ::: figure opener inside an open group's body is a generic container (carve lint reports figure-group-nested), and only the outer group numbers.

carve
::: figure
:::: figure
![one](a.png)
^ (a) One
::::
:::
^ Figure #: Outer only
html
<figure class="carve-figure-group">
  <div class="figure">
    <figure>
      <img src="a.png" alt="one">
      <figcaption>(a) One</figcaption>
    </figure>
  </div>
  <figcaption>Figure 1: Outer only</figcaption>
</figure>

Every captionable host panels the same way: a table (captioned or not) is wrapped in the panel figure, and a captioned code listing and a captioned display-math block already render as figures and take the panel class. An UNCAPTIONED quote is plain group content - which is how a quotation carries a figure number without a caption of its own: leave the quote bare and caption the group (PART 9 §4c).

carve
{#fig-m}
::: figure
| Kind | N |
|------|---|
| a    | 1 |

```js
const x = 1
```
^ A listing panel

$$`E = mc^2`
^ An equation panel

> Measured twice.

> Brevity.
^ A quoted panel
:::
^ Figure #: Mixed panels
html
<figure class="carve-figure-group" id="fig-m">
  <figure class="carve-figure-panel">
    <table>
      <thead><tr><th scope="col">Kind</th><th scope="col">N</th></tr></thead>
      <tbody>
        <tr><td>a</td><td>1</td></tr>
      </tbody>
    </table>
  </figure>
  <figure class="carve-figure-panel">
    <pre><code class="language-js">const x = 1
</code></pre>
    <figcaption>A listing panel</figcaption>
  </figure>
  <figure class="carve-figure-panel">
    <p><span class="math display">\[E = mc^2\]</span></p>
    <figcaption>An equation panel</figcaption>
  </figure>
  <blockquote><p>Measured twice.</p></blockquote>
  <figure class="carve-figure-panel">
    <blockquote><p>Brevity.</p></blockquote>
    <figcaption>A quoted panel</figcaption>
  </figure>
  <figcaption>Figure 1: Mixed panels</figcaption>
</figure>

A captionable host takes its number where the host begins, and a figure group begins at its opening fence - so the group draws its number before anything inside it does (pre-order). The only construction that can observe the difference is a numbered caption inside non-panel group content, which draws after the group even though its caption line sits above the group's in the source.

carve
:::: figure
::: note
![x](x.png)
^ Figure #: inner
:::
::::
^ Figure #: group
html
<figure class="carve-figure-group">
  <aside class="admonition note">
    <figure>
      <img src="x.png" alt="x">
      <figcaption>Figure 2: inner</figcaption>
    </figure>
  </aside>
  <figcaption>Figure 1: group</figcaption>
</figure>

Fenced code

1 conformance fixture

If the preceding {…} block-attribute line also sets title, that line wins — the opener header only fills title when the attribute line did not.

carve
{title="from the attribute line"}
```php "from the header"
code
```
html
<pre title="from the attribute line"><code class="language-php">code
</code></pre>

Admonitions

2 conformance fixtures

The quoted opener header is the only source of the visible admonition-title paragraph. A title="…" key on the preceding attribute line is an ordinary HTML title attribute on the wrapper (a hover tooltip) — a separate channel, not a fallback spelling, and it never collides with the opener header:

carve
{title="attr title"}
::: note "opener title"
Body.
:::
html
<aside class="admonition note" title="attr title">
  <p class="admonition-title">opener title</p>
  <p>Body.</p>
</aside>

As the first token after the fence, the bare [label] may sit directly against it (:::[First]), the same allowance a code fence makes for ```[NPM].

carve
:::[First]
First panel.
:::
html
<div>
  <p class="div-label">First</p>
  <p>First panel.</p>
</div>

Comments

3 conformance fixtures

Without a space before it, %% is literal - so percentages and a%%b are safe.

carve
50%% off and a%%b stay literal.
html
<p>50%% off and a%%b stay literal.</p>

%% inside a code span is verbatim.

carve
Run `a %% b` then done. %% gone
html
<p>Run <code>a %% b</code> then done.</p>

A trailing comment ends at the line break; the next line of the paragraph stays.

carve
foo %% note
bar
html
<p>foo
bar</p>

An unclosed inline run in a line block reaches the end of the block

4 conformance fixtures

An inline run with no closer renders to the end of its BLOCK. A line block is one block, so its line breaks are a rendering instruction rather than a boundary the inline parser can see (markup-carve/carve#1282). The run therefore carries the break, and what it carries is a NEWLINE: the break is inside the run, so it is the run's content and not a <br> the container promised.

carve
::: |
a `b
c d
:::
html
<div class="line-block">
  <p>a <code>b
c d</code></p>
</div>

The control is the same two lines as an ordinary paragraph, which every reader already agreed about. One rule across both containers is what this pins, and the line block needs no exception:

carve
a `b
c d
html
<p>a <code>b
c d</code></p>

And the control that keeps the container's promise intact: a run that DOES close leaves the break outside itself, where it hardens as every other line break in a line block does. These two documents differ by one backtick and answer differently, which is why both are here.

carve
::: |
a `b`
c d
:::
html
<div class="line-block">
  <p>a <code>b</code><br>
c d</p>
</div>

The rule is about runs, not about backticks: a math run spans the break the same way, and its content holds the newline too.

carve
::: |
a $`x
c d
:::
html
<div class="line-block">
  <p>a <span class="math inline">\(x
c d\)</span></p>
</div>

A comment-only line in a line block is removed before any inline run

4 conformance fixtures

comment_line is a BLOCK - PART 1 lists it among the invisible blocks - so a comment-only body line is decided at the block layer, before the stanza reaches the inline parser. An unclosed verbatim run opened on an EARLIER line therefore cannot claim it, and a stray backtick cannot turn a comment into published text (markup-carve/carve#1333). The comment leaves an EMPTY VERSE LINE (PART 9 §23), and the run carries that line as a newline like every other break it swallows.

carve
::: |
a `b
%% secret
c
:::
html
<div class="line-block">
  <p>a <code>b

c</code></p>
</div>

The control with no run open is the shape §23 has always described and that nothing had ever pinned: the line is gone, and the stanza keeps its shape rather than losing a line.

carve
::: |
a
%% secret
c
:::
html
<div class="line-block">
  <p>a<br>
<br>
c</p>
</div>

A TRAILING comment is a different construct and answers differently. x %% secret is inline_comment (§21), not a comment line, and §21's third bullet is unconditional: inside a verbatim run there is no comment there at all, only two percent characters in content. These two documents differ only in where the %% sits on its line, which is why both are here.

carve
::: |
a `b
x %% secret
c
:::
html
<div class="line-block">
  <p>a <code>b
x %% secret
c</code></p>
</div>

The answer is §21's and not the container's, which is why there is no paragraph document beside these two: 26-comments-4 already pins a %% inside a code span as content, and the paragraph shape adds nothing a mutation of the rule can tell apart from it. One rule across both containers, as the unclosed-run documents above pin for the run itself.

An empty verse line is a LINE, not a break: it earns its <br> from the boundary above it like any other line, so a comment ending a stanza adds nothing after the break that already separates it from the line before. Two breaks on one boundary is what the section below refuses.

carve
::: |
a
%% c
:::
html
<div class="line-block">
  <p>a<br>
</p>
</div>

A line block's hard break keeps its backslash

3 conformance fixtures

A line block hardens every line boundary of its own accord, and a backslash break is NOT additive: hard_break = '\', newline consumes its own newline, so no soft break survives for §23 to convert and one boundary still produces one <br> (markup-carve/carve#1334). The backslash is not thereby redundant. PART 7 makes the whitespace run before it INTERIOR, so a \ is how a verse line keeps a LONE trailing space - and the canonical writer may not drop it, because a bare newline makes that space line-trailing, where PART 2 strips it and formatting the document destroys rendered content (PART 11 §7c).

carve
::: |
a \
b
:::
html
<div class="line-block">
  <p>a <br>
b</p>
</div>

A \ ALONE on a body line is how a stanza carries an empty verse line. The blank line is the one spelling that would end the stanza instead, so a writer that drops this backslash hands back one stanza as two.

carve
::: |
a
\
b
:::
html
<div class="line-block">
  <p>a<br>
<br>
b</p>
</div>

The control that bounds the rule: a TRAILING run of TWO OR MORE columns is already NBSP content under MEDIAL GAPS, so it survives with no backslash and the backslash carries nothing here. This is the document whose canonical form drops it.

carve
::: |
a  \
b
:::
html
<div class="line-block">
  <p>a&nbsp;&nbsp;<br>
b</p>
</div>

A line block's last body line keeps its backslash

4 conformance fixtures

PART 11 §7c lets the canonical writer spell a line block's hard_break as a BARE NEWLINE, because the container hardens every line boundary of its own accord (§23). The permission holds only where re-reading that newline yields the same tree, and at the END of a stanza it does not: §23 hardens the boundary BETWEEN two body lines, and the body's end is not one. A hard_break there is the author's own (PART 3), the newline after it belongs to the closing fence, and a writer that drops the backslash drops the break (markup-carve/carve-js#1172).

No space is involved. This is the shape the clause's first wording could not reach, because it enumerated the two cases where a bare newline is unsafe and both of them are about whitespace.

carve
::: |
a\
:::
html
<div class="line-block">
  <p>a<br>
</p>
</div>

A TRAILING run of TWO OR MORE columns is NBSP content under MEDIAL GAPS and survives a bare newline on its own, which is why it needs no backslash INSIDE a stanza - 345-a-line-block-s-hard-break-keeps-its-backslash-3 is that document. At the stanza's end the break is what is at stake rather than the spaces, so the same line answers the other way.

carve
::: |
a  \
:::
html
<div class="line-block">
  <p>a&nbsp;&nbsp;<br>
</p>
</div>

A LINE THAT ENDS IN A COMMENT IS EXEMPT, and the shape that shows why is an EMPTY comment line. The writer spells one as the marker plus a separator space, and PART 2 strips that space again on the way back in - so the LONE TRAILING SPACE case does not reach it: the space is inside the note rather than content the parser is about to lose, and stripping it leaves the same node. A backslash written to protect it lands INSIDE the note, where the block layer, which claims the whole line before the inline parser sees it, reads it back as the comment's own content. The same exemption is why a last body line ending in a comment takes no backslash either: the marker runs to the end of its own line, so there is no hard break there to spell.

carve
::: |
a
%%
b
:::
html
<div class="line-block">
  <p>a<br>
<br>
b</p>
</div>

And a boundary the author spelled \ is still a boundary, so it is still the breaks that decide which line is last. Here the last body line is the COMMENT: the backslash on a is there to hold the LONE trailing space, and the comment line below it is a line of its own. Asking the question of the soft-break conversion asks it where a \ never arrives, which kept the same note under a and dropped it under a \.

carve
::: |
a \
%% c
:::
html
<div class="line-block">
  <p>a <br>
</p>
</div>

A closed inline construct spanning a verse boundary

5 conformance fixtures

A line block hardens SOFT BREAKS, and §23's subject is the node: the only question at a boundary is whether a soft_break is there, never what encloses it. An emphasis run, a link label or a semantic span that spans a boundary encloses one - the newline is a node BESIDE the construct's text - so the break hardens exactly as it does with no construct around it (markup-carve/carve#1351).

carve
::: |
*Roses are red,
Violets are blue.*
:::
html
<div class="line-block">
  <p><strong>Roses are red,<br>
Violets are blue.</strong></p>
</div>

The control is DIFFERENT IN KIND rather than in depth, which is the whole of the rule. A verbatim run that closes on a LATER line spans the same boundary and does NOT harden it, because the newline is inside the run's own value and there is no node for the clause to convert. That completes the set above, and CLOSING is not what any of it turns on: a run that closes on the SAME line leaves the break outside itself and hardens, a run that closes on a later line and a run that never closes both hold the break in their value and do not. These two documents differ only in which construct spans the boundary and they answer differently:

carve
::: |
a `b
c` d
:::
html
<div class="line-block">
  <p>a <code>b
c</code> d</p>
</div>

No depth is a threshold either, so one stanza answers its boundaries the same way whether or not a construct is open across them. The pinned reading gave this document a bare newline and then a <br>:

carve
::: |
*Roses are red,
Violets are blue.*
And so are you.
:::
html
<div class="line-block">
  <p><strong>Roses are red,<br>
Violets are blue.</strong><br>
And so are you.</p>
</div>

A BACKSLASH BREAK IS NOT ADDITIVE holds at depth for the same reason it holds at the top: the backslash consumed the newline, so no soft break survives inside the construct either and ONE boundary still produces ONE break. An implementation that hardens by LINE BOUNDARY rather than by node writes two here:

carve
::: |
*Roses are red,\
Violets are blue.*
:::
html
<div class="line-block">
  <p><strong>Roses are red,<br>
Violets are blue.</strong></p>
</div>

A LINK LABEL AND A SEMANTIC SPAN HOLD THE SAME NODE and the rule reaches them for the same reason - every engine's tree puts a soft_break inside the link and inside the span. They were not pinned here at first, because the executable spec's brContent admitted no newline and so parsed no bracketed construct across a line boundary ANYWHERE, in a line block or in an ordinary paragraph: a fixture would have pinned that limitation rather than this rule. That is fixed (markup-carve/carve#1352), and the shapes are pinned under "A bracketed construct spanning a line boundary" below.

And LEADING WHITESPACE is still content inside the construct, so the two rules compose. An implementation that answers this by re-reading the construct's raw text loses the gap:

carve
::: |
*Roses are red,
  Violets are blue.*
:::
html
<div class="line-block">
  <p><strong>Roses are red,<br>
&nbsp;&nbsp;Violets are blue.</strong></p>
</div>

A container whose table ends on a continuation row

7 conformance fixtures

PART 1 S4 asks what a container's last BLOCK is, and a table is a table however its last row is spelled. §5 T6 gives a continuation row table_cells and joins them onto the row above, so it leaves no paragraph open and the container ends at a flush-left line (markup-carve/carve#1348).

carve
- | a |
  + b |
tail
html
<ul>
  <li>
    <table>
      <tbody>
        <tr><td>a b</td></tr>
      </tbody>
    </table>
  </li>
</ul>
<p>tail</p>

The control is the same table ending on a STANDARD row. It already answered this way everywhere, which is what made the pair above a contradiction rather than a second reading: two spellings of one table's last line, one question:

carve
- | a |
  | b |
tail
html
<ul>
  <li>
    <table>
      <tbody>
        <tr><td>a</td></tr>
        <tr><td>b</td></tr>
      </tbody>
    </table>
  </li>
</ul>
<p>tail</p>

A QUOTE answers the same way, and this is the half no implementation had right: all three engines and the executable spec kept tail inside the quote here while sending it out of the same quote ending on a standard row.

carve
> | a |
> + b |
tail
html
<blockquote>
  <table>
    <tbody>
      <tr><td>a b</td></tr>
    </tbody>
  </table>
</blockquote>
<p>tail</p>

The quote's own standard-row control, which is the document that decided it. A build that stops treating a standard row as a block inside a quote passes every other document in the corpus:

carve
> | a |
> | b |
tail
html
<blockquote>
  <table>
    <tbody>
      <tr><td>a</td></tr>
      <tr><td>b</td></tr>
    </tbody>
  </table>
</blockquote>
<p>tail</p>

And the quote answers the same WRAPPED as it does bare, because §5's clause puts the question to the quote's own body. An implementation that peels the > off one line loses the run above it and makes one document's answer depend on what is wrapped around it:

carve
:: t
:  > | a |
   > + b |
tail
html
<dl>
  <dt>t</dt>
  <dd>
    <blockquote>
      <table>
        <tbody>
          <tr><td>a b</td></tr>
        </tbody>
      </table>
    </blockquote>
  </dd>
</dl>
<p>tail</p>

The definition body without the quote is the same answer one container in:

carve
:: t
:  | a |
   + b |
tail
html
<dl>
  <dt>t</dt>
  <dd>
    <table>
      <tbody>
        <tr><td>a b</td></tr>
      </tbody>
    </table>
  </dd>
</dl>
<p>tail</p>

The other direction of the rule is unchanged and is what keeps this a parameter rather than a new constant answer. With no table above it the same line is prose, it leaves a paragraph open, and the flush-left line folds:

carve
- a
  + b |
tail
html
<ul>
  <li>a
+ b |
tail</li>
</ul>

A definition at a container's content column

6 conformance fixtures

§10 I5 makes a link or footnote definition an INTERRUPTER, so one written at a list item's content column ends the paragraph it sits under. Nothing about it closes the container: the container ends because the next line arrives at column 0 with no open paragraph left to fold into, which is PART 1 S4's own "otherwise" (markup-carve/carve#1350). And the definition BELONGS to the item at that column, so it registers.

carve
- a
  [r]: /u
tail

[r][]
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>
<p><a href="/u">r</a></p>

The footnote kind is the same construct and answers the same way:

carve
- a
  [^f]: t
tail

x[^f]
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>
<p>x<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>t<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

The control is I5's third column, and it is what makes the rule COLUMN-SCOPED rather than shape-scoped. One space to the left the same line is below the content column, where it is lazy paragraph text: it registers nothing, it leaves the paragraph open, and the flush-left line folds. These two documents differ by a single space and answer differently:

carve
- a
 [r]: /u
tail

[r][]
html
<ul>
  <li>a
[r]: /u
tail</li>
</ul>
<p>[r][]</p>

An ABBREVIATION definition is not on I5's list and is recognized at document level only, so at the same content column it is ordinary paragraph text and the flush-left line folds:

carve
- a
  *[A]: x
tail
html
<ul>
  <li>a
*[A]: x
tail</li>
</ul>

A DEFINITION BODY answers exactly as the list item does, which is what keeps S4 doing the work rather than two container-specific rules:

carve
:: t
:  a
   [r]: /u
tail

[r][]
html
<dl>
  <dt>t</dt>
  <dd>a</dd>
</dl>
<p>tail</p>
<p><a href="/u">r</a></p>

A COMMENT at a definition body's content column is on I5's list too and ends the paragraph the same way:

carve
:: t
:  a
   %% c
tail
html
<dl>
  <dt>t</dt>
  <dd>a</dd>
</dl>
<p>tail</p>

A bracketed construct spanning a line boundary

9 conformance fixtures

A [ closes at its matching ], and NOTHING in that scan is a line. The close is balanced, escape- and literal-span-aware (PART 3, link_text), and a line boundary is none of those things - link_text is inline_content, which folds across lines exactly as a paragraph does. So a link label, a semantic span, an image's alternative text, an inline note and an extension's content all admit a soft break like any other inline content.

The executable spec used to spell every one of those content runs with a ~newline guard, so it read all five as literal text and the same guard sat on the braced family beside them. Nothing pinned any of it: all three engines crossed the boundary, and the oracle alone did not (markup-carve/carve#1352).

carve
See [a
b](/u) here.
html
<p>See <a href="/u">a
b</a> here.</p>

A semantic span is the same run with a different tail:

carve
An [a
b]{.k} span.
html
<p>An <span class="k">a
b</span> span.</p>

The LABEL TEXT of a reference link crosses too. Its reference LABEL does not, and the two are pinned apart below:

carve
[a
b][r] resolves.

[r]: /u
html
<p><a href="/u">a
b</a> resolves.</p>

AN IMAGE'S ALT IS THE SAME RUN, so the two-line spelling of an image is still one image - and a paragraph whose whole content is one image is still the standalone image shape, not a wrapped one:

carve
![a
b](/i)
html
<img src="/i" alt="a
b">

and still a captionable host, for the same reason:

carve
![a
b](/i)
^ A caption.
html
<figure>
  <img src="/i" alt="a
b">
  <figcaption>A caption.</figcaption>
</figure>

An inline note's body is brContent too:

carve
A note ^[a
b] here.
html
<p>A note <a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a> here.</p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>a
b<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

An inline extension closes at its own ] and reads the same content:

carve
:span[a
b] here.
html
<p><span class="ext-span">a
b</span> here.</p>

THE BRACED FAMILY IS THE SAME RULE ONE DELIMITER OVER. An editorial span and a forced span take inline content and close on their own brace pair, so a line boundary inside one is content there as well. They are pinned here rather than in a section of their own because the defect was one guard repeated, not five decisions:

carve
An {+a
b+} insertion.
html
<p>An <ins>a
b</ins> insertion.</p>
carve
A {/a
b/} run.
html
<p>A <em>a
b</em> run.</p>

A bracketed construct's identifiers stay on one line

5 conformance fixtures

The runs that admit a boundary are the CONTENT runs. A reference label, a footnote label and a crossref target are physical-line identifiers, matching the one-line definition marker they resolve against, and they keep the guard the content runs lost. These are controls: they answer the same before and after markup-carve/carve#1352, which is what makes them worth writing down beside it.

carve
[t][r
x]

[r x]: /u
html
<p>[t][r
x]</p>
carve
x[^f
g]

[^f g]: n
html
<p>x[^f
g]</p>

AND THE TAIL IS AN IDENTIFIER TOO, which is what keeps a captionable host honest. An image's ALT spans lines; its destination and its reference label do not, so a tail carrying a boundary is not an image tail and the paragraph is ordinary prose - it neither renders as an image nor hosts the caption line below it. These are the near misses a reading that joined the paragraph and stopped there would swallow:

carve
![a][r
x]
^ cap
html
<p>![a][r
x]
^ cap</p>
carve
![a](/i
q)
^ cap
html
<p>![a](/i
q)
^ cap</p>

AND A BLOCK BOUNDARY IS STILL A WALL. Admitting a newline into the scan says nothing about how far it may run: an unclosed [ is literal text, and the inline pass never sees past the block it is reading, so the run cannot reach the next paragraph to find a closer there.

carve
x [a
y

z
html
<p>x [a
y</p>
<p>z</p>

A bracketed construct spanning a verse boundary

3 conformance fixtures

The two rules compose, and this is the coverage "A closed inline construct spanning a verse boundary" above deferred. §23's subject is the soft_break NODE, and a link label spanning a stanza boundary encloses one, so the break hardens inside the label exactly as it does inside an emphasis run.

carve
::: |
See [Roses are red,
Violets are blue.](/u)
:::
html
<div class="line-block">
  <p>See <a href="/u">Roses are red,<br>
Violets are blue.</a></p>
</div>

A semantic span holds the same node:

carve
::: |
[Roses are red,
Violets are blue.]{.verse}
:::
html
<div class="line-block">
  <p><span class="verse">Roses are red,<br>
Violets are blue.</span></p>
</div>

And so does a braced construct, which is the point of the rule being about the node rather than about a list of enclosures:

carve
::: |
{+Roses are red,
Violets are blue.+}
:::
html
<div class="line-block">
  <p><ins>Roses are red,<br>
Violets are blue.</ins></p>
</div>

A continuation row joins the row above it, whatever its cells hold

6 conformance fixtures

What a + row joins is the row above it in the SOURCE, and the only line that declines is a delimiter row, which T7 consumes. A HEADER row is a row, so a continuation joins it - onto a native |= cell as readily as onto a data cell (markup-carve/carve#1354).

carve
|=a |=b |
+ cont |
html
<table>
  <thead><tr><th scope="col">a cont</th><th scope="col">b</th></tr></thead>
</table>

An all-header row that is not the table's first is joinable for the same reason:

carve
| a |
|=b |
+ c |
html
<table>
  <tbody>
    <tr><td>a</td></tr>
    <tr><th scope="row">b c</th></tr>
  </tbody>
</table>

THE DELIMITER ROW IS WHAT DECLINES, and it declines under a NATIVE header row too - which is what tells the two readings apart, since header-ness is present here and the answer is still prose. A continuation row needs a body row above pins the GFM spelling of the same decline:

carve
|=a |
| - |
+ cont |
html
<table>
  <thead><tr><th scope="col">a</th></tr></thead>
</table>
<p>+ cont |</p>

AN ALL-EMPTY CONTINUATION ROW IS ONE TOO. T2's minimum-cell guard is the STANDARD row's - it decides what OPENS a table - and a continuation row opens nothing and produces no <tr>, so a row whose every cell is empty appends nothing, which is what T6 already provides for:

carve
| a |
+ |
html
<table>
  <tbody>
    <tr><td>a</td></tr>
  </tbody>
</table>

The two-column twin is the control that shows the guard was answering one clause twice by column count: it was absorbed all along, because only the one-column shape reaches a one-cell test.

carve
| a | b |
+ | |
html
<table>
  <tbody>
    <tr><td>a</td><td>b</td></tr>
  </tbody>
</table>

And the empty row declines under a delimiter row exactly as a filled one does, so the two halves of this rule compose rather than override:

carve
| a | b |
| - | - |
+ |
html
<table>
  <thead><tr><th scope="col">a</th><th scope="col">b</th></tr></thead>
</table>
<p>+ |</p>

A container whose table ends on a joined header row

3 conformance fixtures

Once the reader accepts these rows, the container boundary follows from T6's IT LEAVES NO PARAGRAPH OPEN with no second predicate: the item's last block is a table however its last row is spelled, so the flush-left line leaves. This is the shape markup-carve/carve#1354 reported as a container-boundary defect - the predicate said "row" while the reader published prose - and it is answered by fixing the reader rather than by teaching the predicate the reader's rejections.

carve
- |=a |
  + b |
tail
html
<ul>
  <li>
    <table>
      <thead><tr><th scope="col">a b</th></tr></thead>
    </table>
  </li>
</ul>
<p>tail</p>

The empty spelling answers the same, which is the whole point of the two halves being one rule:

carve
- | a |
  + |
tail
html
<ul>
  <li>
    <table>
      <tbody>
        <tr><td>a</td></tr>
      </tbody>
    </table>
  </li>
</ul>
<p>tail</p>

A quote is asked its own body and answers alike:

carve
> |=a |
> + b |
tail
html
<blockquote>
  <table>
    <thead><tr><th scope="col">a b</th></tr></thead>
  </table>
</blockquote>
<p>tail</p>

A quote inside a quote is asked what it ends on

12 conformance fixtures

PART 1 S4 puts the question to a quote RECURSIVELY, and "recursively" has no depth in it: an outer quote whose last block is an inner quote is answered by what the INNER quote ends on. A heading ends it, so the flush-left line ends both quotes (markup-carve/carve#1355).

carve
> > # H
tail
html
<blockquote>
  <blockquote>
    <h1 id="H">H</h1>
  </blockquote>
</blockquote>
<p>tail</p>

The ONE-LEVEL SPELLING is the control that makes this a contradiction rather than a gap. It has always answered this way, and it is the same derivation:

carve
> # H
tail
html
<blockquote>
  <h1 id="H">H</h1>
</blockquote>
<p>tail</p>

A table answers alike, which is what says the rule is about the last block and not about headings:

carve
> > | a |
> > | b |
tail
html
<blockquote>
  <blockquote>
    <table>
      <tbody>
        <tr><td>a</td></tr>
        <tr><td>b</td></tr>
      </tbody>
    </table>
  </blockquote>
</blockquote>
<p>tail</p>

So does a thematic break:

carve
> > ---
tail
html
<blockquote>
  <blockquote>
    <hr>
  </blockquote>
</blockquote>
<p>tail</p>

And an INVISIBLE block, which leaves nothing on the page for a lazy line to continue and still ends the run:

carve
> > [r]: /u
tail

[r][]
html
<blockquote>
  <blockquote>

  </blockquote>
</blockquote>
<p>tail</p>
<p><a href="/u">r</a></p>

THREE DEEP IS THE SAME RULE, since nothing in it counts levels:

carve
> > > # H
tail
html
<blockquote>
  <blockquote>
    <blockquote>
      <h1 id="H">H</h1>
    </blockquote>
  </blockquote>
</blockquote>
<p>tail</p>

An earlier paragraph in the OUTER quote does not change the answer either - the question is about the LAST block, and the last block is the inner quote:

carve
> a
> > # H
tail
html
<blockquote>
  <p>a</p>
  <blockquote>
    <h1 id="H">H</h1>
  </blockquote>
</blockquote>
<p>tail</p>

A TABLE ENDING ON A CONTINUATION ROW answers alike, and it is the shape that says the question is asked with the inner quote's OWN line history rather than of its last line alone: + b | read on its own is prose (markup-carve/carve#1345), and read under the row above it is the row that finishes the table (§5 T6).

carve
> > | a |
> > + b |
tail
html
<blockquote>
  <blockquote>
    <table>
      <tbody>
        <tr><td>a b</td></tr>
      </tbody>
    </table>
  </blockquote>
</blockquote>
<p>tail</p>

The same at three levels, which is what says the history is carried per depth rather than for one:

carve
> > > | a |
> > > + b |
tail
html
<blockquote>
  <blockquote>
    <blockquote>
      <table>
        <tbody>
          <tr><td>a b</td></tr>
        </tbody>
      </table>
    </blockquote>
  </blockquote>
</blockquote>
<p>tail</p>

THE FOLD IS UNCHANGED WHERE A PARAGRAPH IS OPEN, which is the half depth was never a parameter of. These two are controls: they answered the same before this rule and after it.

carve
> > a
tail
html
<blockquote>
  <blockquote><p>a
tail</p></blockquote>
</blockquote>
carve
> > # H
> > a
tail
html
<blockquote>
  <blockquote>
    <h1 id="H">H</h1>
    <p>a
tail</p>
  </blockquote>
</blockquote>

AND A RUN A LINE DOES NOT REACH HAS ENDED. A later quote at the same depth is a NEW quote and inherits nothing from the one before it, so its first line is read as what it is - here prose, which opens a paragraph the flush-left line folds into. This is unanimous, and it is the near miss a reading that carried the history without ending it would take:

carve
> > | a |
> # H
> > + b |
tail
html
<blockquote>
  <blockquote>
    <table>
      <tbody>
        <tr><td>a</td></tr>
      </tbody>
    </table>
  </blockquote>
  <h1 id="H">H</h1>
  <blockquote><p>+ b |
tail</p></blockquote>
</blockquote>

A block at a container's content column ends the paragraph, whatever it renders

6 conformance fixtures

The content column IS the container body's column 0 (§24 C3), so a line there is read as a BLOCK - and a block ends the paragraph above it. What the block RENDERS is not a parameter: a comment, a definition and an attribute block all render nothing and all three end the paragraph, none of them closes the container, and the container ends because the FOLLOWING line arrives at DOCUMENT column 0 with nothing to fold into (markup-carve/carve#1350, markup-carve/carve#1357).

An ATTRIBUTE BLOCK is the control that decides the argument, because it is invisible and every implementation already ends the item on it:

carve
- a
  {.k}
tail
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>

So a COMMENT answers alike. It ends the paragraph and not the item; tail ends the item because it is at column 0:

carve
- a
  %% c
tail
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>

The FENCE spelling travels with its opener (§24 C3), so it answers the same:

carve
- a
  %%% c
  %%%
tail
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>

THE RULE IS OVER THE BLOCK, NOT OVER ITS FIRST LINE. A footnote definition's indented body continuation is part of that definition - the footnote parser consumes it and permits no lazy continuation into it - so nothing of the item's is open across any of it:

carve
- a
  [^f]: t
    more
tail

x[^f]
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>
<p>x<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>t
more<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

which is the same answer the ONE-LINE spelling of that definition already gets, and that is the point - two spellings of one definition had been answering differently:

carve
- a
  [^f]: t
tail

x[^f]
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>
<p>x<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>t<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

A LINK reference definition has no body - it is one line in Carve - so an indented line under it is ordinary item text and reopens the paragraph. This is the control that says the rule is about the BLOCK'S EXTENT and not about indentation, and it is unanimous:

carve
- a
  [r]: /u
    "T"
tail

[r][]
html
<ul>
  <li>a
    “T”
tail
  </li>
</ul>
<p><a href="/u">r</a></p>

What a content-column block does not reach

2 conformance fixtures

Two controls, both unchanged and both unanimous. BELOW the content column at a NONZERO column, the following line reaches the item only through the lazy fold, and §24 C3's comment exception keeps that path open:

carve
- a
  %% c
 b
html
<ul>
  <li>a
    b
  </li>
</ul>

And a line AT the content column after the block is the item's own second paragraph, which it was before:

carve
- a
  [^f]: t
    more
  b

x[^f]
html
<ul>
  <li>a
    b
  </li>
</ul>
<p>x<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>t
more<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

A footnote definition's block runs to the end of its body

2 conformance fixtures

The rule is over the BLOCK, and a footnote definition's block is whatever the footnote parser consumes - which may be more than one block of body. A blank between the note's blocks is INTERIOR to that block, so it hands nothing back to the container: the item ends here exactly as it does on the contiguous and the one-line spellings of the same definition, and the flush-left line is a document-level paragraph (markup-carve/carve#1363).

carve
- a
  [^f]: t

    more
tail

x[^f]
html
<ul>
  <li>a</li>
</ul>
<p>tail</p>
<p>x<a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a></p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>t</p>
      <p>more<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

A LINK reference definition is the control, and it does not move. It has no body, so its block is the one line: the blank falls OUTSIDE it, the indented line below is the item's own second paragraph, and the flush-left line folds into that. Every implementation already answers this way, which is what makes it the control - the difference is the body, not the indentation and not the blank:

carve
- a
  [r]: /u

    more
tail

[r][]
html
<ul>
  <li><p>a</p>
    <p>more
tail</p>
  </li>
</ul>
<p><a href="/u">r</a></p>

A definition behind an alternating container prefix registers at the innermost content column

4 conformance fixtures

Which container's content_column a line reaches is decided by PART 9 §24 C5's dedent chain: every container strips its own prefix and hands the residue down, so the question is asked of the innermost container in the coordinates it was handed. The shape of the prefix above it - how many quotes and list items it alternates, in what order, and how deep - is not a parameter, and a definition at that column registers exactly as §10 I5 says (markup-carve/carve#1368).

carve
- > - - x
  >     [r]: /url

See [r][].
html
<ul>
  <li>
    <blockquote>
      <ul>
        <li>
          <ul>
            <li>x</li>
          </ul>
        </li>
      </ul>
    </blockquote>
  </li>
</ul>
<p>See <a href="/url">r</a>.</p>

The FOOTNOTE kind of the same shape, kept beside the link because a reader that sorts definitions by kind can pass on the half it gets right.

carve
- > - - x
  >     [^f]: note

See [^f].
html
<ul>
  <li>
    <blockquote>
      <ul>
        <li>
          <ul>
            <li>x</li>
          </ul>
        </li>
      </ul>
    </blockquote>
  </li>
</ul>
<p>See <a id="fnref1" href="#fn1" role="doc-noteref"><sup>1</sup></a>.</p>
<section role="doc-endnotes">
  <hr>
  <ol>
    <li id="fn1">
      <p>note<a href="#fnref1" role="doc-backlink"></a></p>
    </li>
  </ol>
</section>

The COLUMN control: a heading written at that same column is a block inside the innermost item. It says the line reaches the column, so a reader that declines the definition there is answering about the line's spelling rather than about its column - which §24 C3 refuses.

carve
- > - - x
  >     # h
html
<ul>
  <li>
    <blockquote>
      <ul>
        <li>
          <ul>
            <li>x
              <h1 id="h">h</h1>
            </li>
          </ul>
        </li>
      </ul>
    </blockquote>
  </li>
</ul>

The PEEL control: the same body with the outer list item removed, which is precisely what C5 says that item hands down. Every implementation registers here, so a reader that declines the first case answers one document two ways.

carve
> - - x
>     [r]: /url

See [r][].
html
<blockquote>
  <ul>
    <li>
      <ul>
        <li>x</li>
      </ul>
    </li>
  </ul>
</blockquote>
<p>See <a href="/url">r</a>.</p>

Line blocks

1 conformance fixture

Nested blocks keep ordinary soft-break behavior, and leading whitespace is not treated as alignment.

carve
:::: \
  indented
next

::: note
a
b
:::
::::
html
<div class="hardbreaks">
  <p>indented<br>
next</p>
  <aside class="admonition note">
    <p>a
b</p>
  </aside>
</div>

Inline code

1 conformance fixture

The opener is a maximal run of backticks and closes only on a run of the same length. A run with no matching closer is not literal text: it opens a verbatim span that runs to the end of the block. (A fence-looking ``` mid-paragraph is the common case.)

carve
text
```
code
html
<p>text
<code>
code</code></p>

Generic divs

3 conformance fixtures

An inline attribute block on the fence line is not a div: the opener is an ordinary paragraph (matching canonical djot).

carve
::: {.sidebar}
not a div
:::
html
<p>::: {.sidebar}
not a div
:::</p>

The type word is a grammar identifier, so it may start with an underscore.

carve
::: _box
content
:::
html
<div class="_box">
  <p>content</p>
</div>

A grammar identifier cannot start with a digit, so a digit-first token is not a valid type word: the opener is an ordinary paragraph (a class="123" would also be invalid CSS). This is a deliberate divergence from djot, which would accept it.

carve
::: 123
not a div
:::
html
<p>::: 123
not a div
:::</p>

Released under the MIT License.