Lists
Markers, looseness, the content-column model, continuation markers and block openers inside items.
Generated from resources/examples/core.md and resources/examples/edge-cases.md - edit the cases there, not here. Each case links the conformance fixture it produces.
Lists
15 conformance fixtures
A marker is a list item only when followed by a space and content. A content-less marker — bare (-) or trailing whitespace only (- ) — is not a list; it stays paragraph text. The rule ignores trailing whitespace, so - and - behave the same (an editor stripping the space can't change the meaning). Carve is stricter than CommonMark, where a bare - is an empty item.
-
not a list<p>-
not a list</p>The same holds for every marker that takes a separator space, not just bullets. A definition term needs content too, and here the trailing-whitespace half of the rule is what matters: :: and :: with two spaces after it must mean the same thing, or stripping whitespace on save would turn a paragraph into a definition list.
::<p>::</p>An ordered list nests the same way — a child indented to the parent's content column (three spaces under 1. ) is a sub-list, even though an ordered marker does not interrupt a paragraph (§10).
1. outer
1. inner<ol>
<li>outer
<ol>
<li>inner</li>
</ol>
</li>
</ol>An ordered child below the content column does not nest: an ordered marker does not interrupt a paragraph (§10), so it folds into the item as lazy text.
1. outer
1. inner<ol>
<li>outer
1. inner</li>
</ol>After a blank line the same content-column rule applies: a continuation belongs to the item only if it reaches the item's content column (three columns under 1. ), exactly as without a blank. The blank line only decides whether the item is tight or loose; it never relaxes the column a block must reach. A block opener at the content column attaches and stays tight — unlike a second paragraph, a nested block does not loosen the list.
1. one
> q<ol>
<li>one
<blockquote><p>q</p></blockquote>
</li>
</ol>Below the content column the line is outside the item body: the list ends and the block parses at document level. A two-column indent is not enough under an ordered marker whose content column is three — the same threshold the no-blank case uses.
1. one
> q<ol>
<li>one</li>
</ol>
<p>> q</p>Above the content column the residual indentation means the line is no longer a block opener — just as # h is a paragraph, not a heading, at the top level — so it folds in as a second paragraph and turns the item loose (§17 L1).
1. one
> q<ol>
<li><p>one</p>
<p>> q</p>
</li>
</ol>A list marker does not interrupt an open paragraph — like an ordered marker, a bullet needs a blank line before it. An indented bullet after a prose line folds into the paragraph (lazy continuation).
text
- item<p>text
- item</p>With no preceding paragraph, an indented bullet simply opens a list whose base column is the indentation (Rule B).
- a
- b<ul>
<li>a</li>
<li>b</li>
</ul>A blank line between items produces a loose list — each item wraps in a paragraph.
- apples
- oranges<ul>
<li><p>apples</p></li>
<li><p>oranges</p></li>
</ul>A paragraph ends at a blank line — or at a line that begins an interrupting block. A continuation line that starts with >, a valid |…| table row, a heading #, a thematic break, or a fence with a closer interrupts the paragraph and starts that block, with no blank line required (the Markdown-like rule; §10). A list marker is the exception: neither a bullet (- / * ) nor an ordered marker (1., 1), a., …) interrupts — a list needs a blank line before it (symmetric, Djot-like). So a hard-wrapped prose line that happens to begin with a bullet stays prose; the bullet lines fold into the paragraph as lazy continuation.
Die Frage ist x = 5
* 3 + 17 wahr.<p>Die Frage ist x = 5
* 3 + 17 wahr.</p>A heading under a prose line still interrupts it; a list — bullet or ordered — does not, so these fold into one paragraph.
Liste:
- eins
- zwei<p>Liste:
- eins
- zwei</p>A blank line before the marker makes it a list, even with one item.
Text hier
- nur eins<p>Text hier</p>
<ul>
<li>nur eins</li>
</ul>A blockquote needs a blank line before it like any block; its caption line then attaches and the pair renders as a figure.
Intro
> Stay hungry
^ Steve Jobs<p>Intro</p>
<figure>
<blockquote><p>Stay hungry</p></blockquote>
<figcaption>Steve Jobs</figcaption>
</figure>After a lazy continuation line, a marker at the content column resumes the same sub-list rather than starting a new one (§10).
1. outer
1. inner
lazy
2. sibling<ol>
<li>outer
<ol>
<li>inner
lazy</li>
<li>sibling</li>
</ol>
</li>
</ol>Ordered marker vs prose
1 conformance fixture
Letter and roman markers are ambiguous: a lone a. in running prose stays text (it would need a blank line before, a sibling marker, or indentation to start a list). Decimal markers always start a list.
Pick option a. it is the best one here.<p>Pick option a. it is the best one here.</p>Parenthesized ordered marker
1 conformance fixture
Carve's ordered markers use the . and ) delimiters only; a parenthesized (1) is not a list marker (it is too easily confused with a prose parenthetical), so it stays literal text.
(1) First
(2) Second<p>(1) First
(2) Second</p>List nesting and looseness
9 conformance fixtures
A more-indented marker nests a sublist inside the item.
- a
- b
- c
- d<ul>
<li>a
<ul>
<li>b</li>
<li>c</li>
</ul>
</li>
<li>d</li>
</ul>A blank line between items makes the list loose (each item wraps in <p>).
- a
- b<ul>
<li><p>a</p></li>
<li><p>b</p></li>
</ul>An item with a second paragraph is loose; the continuation is indented under the marker.
- a
more
- b<ul>
<li><p>a</p>
<p>more</p>
</li>
<li><p>b</p></li>
</ul>A flush-left line after a heading stays inside the item the heading belongs to, at any nesting depth — even when the heading opens on a deeper sub-list item's marker line. What it does not do is fold into the heading: a heading ends at the newline (§18), so the line is the item's own content, which a tight list renders unwrapped. Ownership is the rule here; the heading's id is built from the heading line alone.
- a
- b
# N
lazy<ul>
<li>a
<ul>
<li>b
<h1 id="N">N</h1>
lazy
</li>
</ul>
</li>
</ul>A blank line inside a fenced code block is verbatim content, not an interior block separator, so it does not loosen the list — a sibling item after such a fence stays tight because no blank line actually separates the two items.
- ```
a
b
```
- c<ul>
<li>
<pre><code>a
b
</code></pre>
</li>
<li>c</li>
</ul>Plain text on the line after a fenced code block closes is the item's own trailing text. With no blank line anywhere the item stays tight, so that text is not wrapped in a paragraph.
- ```
x
```
after<ul>
<li>
<pre><code>x
</code></pre>
after
</li>
</ul>A bullet's content column is where the marker actually ends, not a fixed 2. A bullet followed by extra spaces puts its content further right, and a block belongs to the item only if it reaches that column.
- item
# Wide<ul>
<li>item
<h1 id="Wide">Wide</h1>
</li>
</ul>Below that column the line is lazy paragraph text instead, so its marker survives literally — the same content-column rule as everywhere else, measured from the marker rather than assumed.
- item
# H<ul>
<li>item
# H</li>
</ul>A task item is the exception: its content column stays at 2. The checkbox is content rather than marker, and extra spaces before it do not move the column either, so neither 6 nor 8 is where the body starts.
- [ ] item
# H<ul>
<li><input type="checkbox" disabled> item
# H</li>
</ul>List lazy continuation
10 conformance fixtures
A non-indented line that follows a list item folds into the item's lead paragraph when it is plain paragraph text and has no blank line before it. A blank line, or a line that starts a block (heading, blockquote, fenced code, thematic break, table, div, a definition), ends the list instead.
- item
lazy<ul>
<li>item
lazy</li>
</ul>- a
# H<ul>
<li>a</li>
</ul>
<section id="H">
<h1>H</h1>
</section>An under-indented continuation line after a nested sublist still folds into the deepest open paragraph (CommonMark lazy continuation); its indentation does not place it at an intermediate level. A blank line before it makes it a fresh paragraph instead.
- a
- b
c<ul>
<li>a
<ul>
<li>b
c</li>
</ul>
</li>
</ul>- a
- b
- c
d<ul>
<li>a
<ul>
<li>b
<ul>
<li>c
d</li>
</ul>
</li>
</ul>
</li>
</ul>- a
- b
c<ul>
<li>a
<ul>
<li>b</li>
</ul>
</li>
</ul>
<p>c</p>Lazy continuation only ever extends an open paragraph. After a block inside an item, a dedented line therefore folds in only when that block leaves a paragraph open. A blockquote's trailing paragraph is open, so the line folds into the quote:
- item
> q
tail<ul>
<li>item
<blockquote><p>q
tail</p></blockquote>
</li>
</ul>A fenced code block leaves no open paragraph, so a dedented line ends the item and starts a top-level block instead of joining the item:
- item
```
c
```
tail<ul>
<li>item
<pre><code>c
</code></pre>
</li>
</ul>
<p>tail</p>A table is the same — no open paragraph, so the dedented line is a fresh top-level paragraph:
- item
| a | b |
tail<ul>
<li>item
<table>
<tbody>
<tr><td>a</td><td>b</td></tr>
</tbody>
</table>
</li>
</ul>
<p>tail</p>A colon fence that is not a valid opener opens no block, so it leaves the paragraph open and the dedented line folds in. :::note has no space between the fence and the type word, so §12's opener test rejects it and the line is ordinary paragraph text; from there the paragraph absorbs the following fence-shaped line as text too (§12, "the absorption is not width-tagged"). Nothing ever interrupted the item's paragraph, so it is still open when tail arrives, and PART 1 S4 folds tail into it. What decides is whether a block was opened, never the shape of the line that tried - an absorbed fence is prose:
- item
:::note
body
:::
tail<ul>
<li>item
:::note
body
:::
tail</li>
</ul>Give the same fence its space and the contrast is exact. Written ::: note, it is a valid opener: it interrupts the item's paragraph, its closer completes the block, and a closed ::: div or admonition leaves no open paragraph - so there tail does end the item and becomes a document paragraph, exactly as after the fenced code block and the table above. One space between the fence and the type word decides which of the two answers the same five lines get.
The same clause settles the neighboring shapes, which is how one knows it is the clause and not a special case, and each of them is a place an implementation could get the right answer here for the wrong reason. Indenting the lazy line to column 1 changes nothing, since it is still below the content column. The malformed fence may be the paragraph's FIRST line, written on the marker line itself (- :::note), and the item then opens with a paragraph that begins with fence-shaped text. Inside a block quote, > tail supplies the quote's prefix but not the item's indentation, which is the partial match S4 is written for. All three fold, for the one reason above; tests/colon-fence-absorbed-in-an-item.test.mjs pins them.
The same rule reaches a list item's second paragraph. The blank before spaced makes the item loose, but it does not close the paragraph that spaced opens. The following flush-left line therefore folds into that innermost paragraph; paragraph depth does not create a special boundary.
1. item
spaced
flush<ol>
<li><p>item</p>
<p>spaced
flush</p>
</li>
</ol>Compact list blocks
10 conformance fixtures
A blank line is still required to start a block inside a list item, but it no longer makes the list loose when the indented content opens a block (sub-list, block quote, fenced code, fenced div, heading, table). The item stays tight — lead text inline, the block attached — so a checklist with notes or steps with code stay compact. (A Carve deviation: canonical djot renders these loose. Only the tight/loose rendering changes, not the block structure.)
- item
> note
- next<ul>
<li>item
<blockquote><p>note</p></blockquote>
</li>
<li>next</li>
</ul>A sub-list is one of those blocks, and the rule holds when a sibling item follows it: the blank belongs to the sub-list, not to the gap between items, so the whole list stays tight.
- fruit
- apples
- vegetables<ul>
<li>fruit
<ul>
<li>apples</li>
</ul>
</li>
<li>vegetables</li>
</ul>A genuine second prose paragraph still makes the list loose (and so does a blank line between items).
- item
second para
- next<ul>
<li><p>item</p>
<p>second para</p>
</li>
<li><p>next</p></li>
</ul>An invisible construct does not loosen either, and for a plainer reason than L2: §17 L1 asks whether the item holds a blank-line-separated second paragraph, and a comment or a definition is not a paragraph - it renders nothing at all. An item wrapped in <p> because of a line that produces no output would be the blank line showing through.
- a
%% just a note<ul>
<li>a</li>
</ul>The same for a definition, which is collected and renders nothing where it stood.
- a
[r]: /u<ul>
<li>a</li>
</ul>A sibling item after it is a different question, and there the list is loose: L1's other clause asks whether an item is followed by a blank line before the next sibling marker, and it is - an invisible line in the gap does not fill it.
- a
%% just a note
- b<ul>
<li><p>a</p></li>
<li><p>b</p></li>
</ul>A paragraph inside an item carries block attributes like any other, and the attribute line sits above it exactly as it does at document level.
- a
first
{.c}
second<ul>
<li><p>a</p>
<p>first</p>
<p class="c">second</p>
</li>
</ul>The attribute still reaches its paragraph across a blank line, exactly as it does at document level: §15 A2a floats it to the next visible block, and a blank is not a block. The item is loose because that paragraph is a real second one, not because of the attribute line.
- a
{.c}
b<ul>
<li><p>a</p>
<p class="c">b</p>
</li>
</ul>On its own, though, an attribute line leaves the item tight — it renders nothing, so it is not the second paragraph §17 L1 asks for, the same reason a comment or a definition is not.
- a
{.c}<ul>
<li>a</li>
</ul>One column further in it is not an attribute line at all: §15 makes it column-strict, so it is literal paragraph text. It renders, and it loosens like any other paragraph — the one place where an attribute line and a comment part company, since a comment renders nothing at any indent.
- a
{.c}<ul>
<li><p>a</p>
<p>{.c}</p>
</li>
</ul>Marker-line nested lists
4 conformance fixtures
A sub-list opened on a parent item's marker line (- - A) is an ordinary persistent nested list, exactly as if the sub-marker sat on its own indented line. It is not a one-off lone item. This matches reference djot.js (@djot/djot) and CommonMark; carve previously inherited a narrower reading from djot-php that did not persist the nested list.
Following markers at the sub-list's indent merge into the same nested list, so - - A then - B and - C yields one list with three items.
- - A
- B
- C<ul>
<li>
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
</li>
</ul>A blank line followed by a block indented to the sub-list's content column is absorbed into the open nested item, just like any list item's lazy continuation. Here the first sub-item gains a second paragraph and the list is loose.
- - A
second
- B<ul>
<li>
<ul>
<li><p>A</p>
<p>second</p>
</li>
<li><p>B</p></li>
</ul>
</li>
</ul>One column further out the same blank belongs to the OUTER item: second sits at the outer item's content column, so that item holds two blocks - the sub-list and a paragraph - and goes loose. The lead being a marker line is not part of the looseness test.
- - A
second<ul>
<li>
<ul>
<li>A</li>
</ul>
<p>second</p>
</li>
</ul>Flush left, the blank has closed the sub-item's paragraph and the line is below every open item's content column, so the list ends and the text is a document-level paragraph. Without the blank the same line would fold into the sub-item as lazy continuation.
- - A
second<ul>
<li>
<ul>
<li>A</li>
</ul>
</li>
</ul>
<p>second</p>Fence opener with a nested-list body inside a list item
7 conformance fixtures
116-fence-opener-with-a-nested-list-body-inside-a-list-item116-fence-opener-with-a-nested-list-body-inside-a-list-item-2116-fence-opener-with-a-nested-list-body-inside-a-list-item-3116-fence-opener-with-a-nested-list-body-inside-a-list-item-4116-fence-opener-with-a-nested-list-body-inside-a-list-item-5116-fence-opener-with-a-nested-list-body-inside-a-list-item-6116-fence-opener-with-a-nested-list-body-inside-a-list-item-7
A ::: opener inside a list item opens its block even when its body is a nested list, provided the matching closer sits at the item content column (PART 9 §12). A bullet (-) or ordered marker (1.) on the next line is part of the admonition body, not a sibling list that swallows the opener as literal text. The closer must align with the opener's content column; a ::: at column zero (outside the item) does not close it.
A nested unordered list body is wrapped by the admonition:
- ::: note
- para text
:::<ul>
<li>
<aside class="admonition note">
<ul>
<li>para text</li>
</ul>
</aside>
</li>
</ul>A nested ordered list body is wrapped the same way:
- ::: note
1. para text
:::<ul>
<li>
<aside class="admonition note">
<ol>
<li>para text</li>
</ol>
</aside>
</li>
</ul>A two-item nested list is wrapped whole:
- ::: note
- one
- two
:::<ul>
<li>
<aside class="admonition note">
<ul>
<li>one</li>
<li>two</li>
</ul>
</aside>
</li>
</ul>A blank line between the opener and the nested list still opens the block:
- ::: note
- para text
:::<ul>
<li>
<aside class="admonition note">
<ul>
<li>para text</li>
</ul>
</aside>
</li>
</ul>NEGATIVE: with no closer, the opener stays literal text and the bullet starts an ordinary nested list:
- ::: note
- para text<ul>
<li>
<aside class="admonition note">
<ul>
<li>para text</li>
</ul>
</aside>
</li>
</ul>NEGATIVE: a closer at column zero is outside the item, so it does not close the opener. The opener still opens its admonition, which closes at end of input, and the stray ::: opens a second, top-level div with an empty body:
- ::: note
- para text
:::<ul>
<li>
<aside class="admonition note">
<ul>
<li>para text</li>
</ul>
</aside>
</li>
</ul>
<div>
</div>GUARD: an empty body (opener immediately followed by its closer) still opens:
- ::: note
:::<ul>
<li>
<aside class="admonition note">
</aside>
</li>
</ul>Sublist marker interrupts a continuation paragraph
2 conformance fixtures
A list marker reaching a list item's content column always starts a sublist, even when the item holds an open continuation paragraph (PART 0 S3, PART 9 §24 C3). The general rule that list markers never interrupt a paragraph applies to markers below the content column (lazy continuation) and at the top level — not to a correctly indented sublist marker.
- first
second
- nested<ul>
<li><p>first</p>
<p>second</p>
<ul>
<li>nested</li>
</ul>
</li>
</ul>Ordered markers behave identically (the symmetric list rule): an ordered marker at the content column nests.
- first
second
1. nested<ul>
<li><p>first</p>
<p>second</p>
<ol>
<li>nested</li>
</ol>
</li>
</ul>Post-blank list continuation (content-column model)
5 conformance fixtures
A block opener or sublist marker attaches to a list item only when it reaches the item's content column (§24 C3): - -> column 2, 1. -> column 3. One rule, blank line or not - the blank only decides tight vs loose. Below the content column a line lazily continues the item paragraph (no blank) or, after a blank, ends the item and parses at document level; above the content column the residual indent means it is no longer a block opener, so it folds in as lazy paragraph text. This is an intentional divergence from djot, which attaches at any indent past the marker (see #295).
Below the content column, after a blank line, the block opener ends the item and parses at the document level.
- one
> q<ul>
<li>one</li>
</ul>
<p>> q</p>At the content column, it nests into the item.
- one
> q<ul>
<li>one
<blockquote><p>q</p></blockquote>
</li>
</ul>Above the content column, the residual indent makes it lazy paragraph text inside the item, not a block opener.
- one
# h<ul>
<li><p>one</p>
<p># h</p>
</li>
</ul>With no blank line, a line below the content column lazily continues the open item paragraph.
- one
> q<ul>
<li>one
> q</li>
</ul>A block opener at column 0 is a document-level block: it interrupts and ends the list, exactly as a quote or heading there would.
- one
```
c
```<ul>
<li>one</li>
</ul>
<pre><code>c
</code></pre>Nested item looseness does not propagate to the outer item
4 conformance fixtures
A post-blank block attached to a nested (inner) item loosens only that inner item; the outer item stays tight (§17). Looseness is decided per level - a descendant's blank never counts toward an ancestor.
- a
- b
> q<ul>
<li>a
<ul>
<li>b
<blockquote><p>q</p></blockquote>
</li>
</ul>
</li>
</ul>The sibling-blank invariant: a blank between the inner items loosens the inner list but leaves the outer item tight - the same non-propagation.
- a
- b
- c<ul>
<li>a
<ul>
<li><p>b</p></li>
<li><p>c</p></li>
</ul>
</li>
</ul>The content-column threshold follows the marker, so a task item's nested block behaves the same.
- [ ] a
- b
> q<ul>
<li><input type="checkbox" disabled> a
<ul>
<li>b
<blockquote><p>q</p></blockquote>
</li>
</ul>
</li>
</ul>An item's own second paragraph after a blank still loosens it - non-propagation removes only the upward leak, not legitimate same-level looseness.
- a
b<ul>
<li><p>a</p>
<p>b</p>
</li>
</ul>Table as a block opener in a list item
2 conformance fixtures
A |-delimited table row is a block opener under the same content-column rule: it nests at the content column and folds as lazy text below it.
- one
|= H |
| x |<ul>
<li>one
<table>
<thead><tr><th scope="col">H</th></tr></thead>
<tbody>
<tr><td>x</td></tr>
</tbody>
</table>
</li>
</ul>- one
|= H |
| x |<ul>
<li>one
|= H |
| x |</li>
</ul>A paragraph opened after a block in an item is still open for a lazy line
5 conformance fixtures
361-a-paragraph-opened-after-a-block-in-an-item-is-still-open-for-a-lazy-line361-a-paragraph-opened-after-a-block-in-an-item-is-still-open-for-a-lazy-line-2361-a-paragraph-opened-after-a-block-in-an-item-is-still-open-for-a-lazy-line-3361-a-paragraph-opened-after-a-block-in-an-item-is-still-open-for-a-lazy-line-4361-a-paragraph-opened-after-a-block-in-an-item-is-still-open-for-a-lazy-line-5
PART 1 S4 asks one question of the open stack: does any container hold an OPEN paragraph. It does not ask where that paragraph sits among the container's blocks. An item whose first block is a table, a fence or a quote and whose next line is prose holds an open paragraph exactly as an item that began with prose does, so a following flush-left line folds into it and nothing closes.
The first case is the one that separates the two readings. | a | is inside the QUOTE, so at the item's own content column the block above + b | is a blockquote and not a table. PART 9 §5 T6 therefore refuses the continuation row, the line is prose, and prose keeps the paragraph open. A reader that consults the table through the container below - close enough to call the line a continuation row for the purpose of ending the paragraph, while still rendering it as text - answers one line two ways in the same parse.
- > | a |
+ b |
tail<ul>
<li>
<blockquote>
<table>
<tbody>
<tr><td>a</td></tr>
</tbody>
</table>
</blockquote>
+ b |
tail
</li>
</ul>The same rule with no continuation row involved: the item opens on a table, the next line is ordinary prose at the item's content column, and tail folds into the paragraph that prose opened.
- | a |
b
tail<ul>
<li>
<table>
<tbody>
<tr><td>a</td></tr>
</tbody>
</table>
b
tail
</li>
</ul>The block the paragraph follows is not what decides it, so a fenced block reads the same way.
- ```
c
```
b
tail<ul>
<li>
<pre><code>c
</code></pre>
b
tail
</li>
</ul>CONTROL. A blank line closes the paragraph, and S4's other half then governs: nothing in the stack holds an open paragraph, so the item ends and tail is a document sibling.
- | a |
b
tail<ul>
<li>
<table>
<tbody>
<tr><td>a</td></tr>
</tbody>
</table>
b
</li>
</ul>
<p>tail</p>CONTROL. Here the table IS above the line at the item's own column, so the second row extends it, no paragraph is opened at all, and tail is again a document sibling. A reader that folded after a table unconditionally would answer this one wrong.
- | a |
| b |
tail<ul>
<li>
<table>
<tbody>
<tr><td>a</td></tr>
<tr><td>b</td></tr>
</tbody>
</table>
</li>
</ul>
<p>tail</p>An unterminated container does not extend the item past a blank line
3 conformance fixtures
A blank line ends the open paragraph, whatever container stands above it. PART 1 S4 then has nothing to continue, so a following line BELOW the item's content column is not the item's: it stands at the enclosing document's own opener column, and the item ends there. The state of the container above the blank does not enter the question - an unterminated ::: div reaches no further past a blank than a terminated one, an opaque body, a quote, or no container at all.
The executable spec answered the unterminated spelling alone. It carried the blank as container content and left the item's paragraph open across it, so a flush-left line folded into the div as a second paragraph, while the terminated div, the code fence, the quote and the bare item all ended the item on the same input. One rule was being answered two ways by whether a closer had been written. carve-js, carve-php and carve-rs end the item in every spelling (carve#1379).
- ::: d
b
tail<ul>
<li>
<div class="d">
<p>b</p>
</div>
</li>
</ul>
<p>tail</p>CONTROL. Without the blank the paragraph b opened is still open, so the same flush-left line folds into it under S4's lazy branch and nothing closes. The blank is what decides, not the unterminated container - a reader that ended the item whenever a ::: was left open would answer this one wrong.
- ::: d
b
tail<ul>
<li>
<div class="d">
<p>b
tail</p>
</div>
</li>
</ul>CONTROL. The blank ends the paragraph, not the ITEM. Content that returns at the item's content column is still inside the div, as its second block - so a reader that closed the item on any blank line inside an open container would answer this one wrong in the other direction.
- ::: d
b
tail<ul>
<li>
<div class="d">
<p>b</p>
<p>tail</p>
</div>
</li>
</ul>A task item's checkbox is not decided by its first block
1 conformance fixture
The checkbox belongs to the ITEM. Nothing about what the item's first block turns out to be reaches it: it is written directly after the <li> opener in every spelling, and only the content moves - beside the checkbox when the first block renders inline, on its own indented line below it when it does not.
The executable spec emitted it only where that first block was a PARAGRAPH. Every other marker-line opener dropped it: a block quote, a code fence, a ::: div, a table row, a heading and a thematic break each rendered a plain <li>, so the [ ] or [x] the author wrote was gone from the output while the item itself parsed correctly. One serializer branch built the <li> opener without the checkbox, and it was the branch every non-paragraph lead takes. carve-js and carve-php write it in all of them (carve#1381).
- [ ] > q
- [x] # h
- [ ] ---<ul>
<li><input type="checkbox" disabled>
<blockquote><p>q</p></blockquote>
</li>
<li><input type="checkbox" checked disabled>
<h1 id="h">h</h1>
</li>
<li><input type="checkbox" disabled>
<hr>
</li>
</ul>Only lazy folding demotes a marker-line colon opener
2 conformance fixtures
A ::: opener written as the sole content of a list item's marker line opens a container. What takes that away is LAZY FOLDING and nothing else: an opener whose whole body arrived from lines that folded in from below the item's content column never acquired container content at all, so it stays literal text. A blank line is not one of those lines. It is the container's own content - the item collector keeps it in the item body precisely because a colon fence is open above it - so an opener a blank follows has opened an EMPTY container, not no container.
The executable spec demoted it. Its guard asked only whether the body was non-empty, and a lone blank line satisfied that, so - ::: d before a blank read as literal item text while every neighbouring spelling of the same opener was right: at end of input, with its closer at the content column, with a body line, and inside a quote instead of an item. Four correct neighbours against one wrong one, and the difference was a line the collector had already decided was content. carve-js, carve-php and carve-rs open the div (carve#1382).
- ::: d
tail<ul>
<li>
<div class="d">
</div>
</li>
</ul>
<p>tail</p>CONTROL, and the shape the guard exists for. Here the body really is lazy: tail sits below the item's content column and folds into the open paragraph the opener line left, so the opener never acquired a body of its own and the whole item is literal text. The blank that follows rides alongside that folded line and does not rescue the opener - a reader that stopped asking whether folding happened, and asked only whether the body was free of blanks, would answer this one wrong in the other direction.
- ::: d
tail
after<ul>
<li>::: d
tail</li>
</ul>
<p>after</p>A blank line before a sibling marker separates the items, whatever consumed it
3 conformance fixtures
Section 17 L1's first disjunct is a question about the LIST: is one item followed by a blank line before the next sibling marker? It reads what stands BETWEEN two items, and a blank line with nothing of the item after it stands between them whatever the item's interior was doing with it. An unterminated container above the blank does not change that, any more than it changes where the item ends.
The executable spec answered it by what the line was doing INSIDE the item. A blank inside an open fence is fence content, so it recorded no separator and the list stayed tight - for a ::: div, an admonition, a code fence, a tilde fence, a raw block and a comment fence alike, while the same document with the closer written loosens in every reader. carve-js and carve-rs loosen all six; carve-php loosens four of the six and stays tight for a code or tilde fence (markup-carve/carve-php#1445, carve#1383).
- ::: d
b
- s<ul>
<li>
<div class="d">
<p>b</p>
</div>
</li>
<li><p>s</p></li>
</ul>The same holds where the blank is genuinely the container's CONTENT and can be seen in the output. An unterminated code fence carries it as an empty payload line, and it still separates the items - what L1 asks is where the line sits relative to the marker, not which block absorbed it. Reading the payload instead would make a structural answer depend on a detail readers already spell differently: carve-php drops the same trailing blank from a raw block and keeps it in a code block.
- ```
b
- s<ul>
<li>
<pre><code>b
</code></pre>
</li>
<li><p>s</p></li>
</ul>CONTROL. The blank must precede a marker of THIS list. A different bullet character starts a different list under the section 11 axes, so nothing of the first list is followed by a blank before one of its own siblings and it stays tight - a reader that loosened on the blank alone would answer this one wrong. The first item carries the plain text that makes the answer visible: with only the fenced item, tight and loose render the same bytes and the case would assert nothing.
- a
- ```
b
* s<ul>
<li>a</li>
<li>
<pre><code>b
</code></pre>
</li>
</ul>
<ul>
<li>s</li>
</ul>The INTERIOR blank carve#326 C ruled on is untouched, and its own stated reason is what separates the two: a sibling after such a fence "stays tight because no blank line actually separates the two items". Content follows an interior blank before the marker, so nothing stands between the items, and the case above in this file stays tight in all four readers.
Colon-fence as a block opener in a list item
3 conformance fixtures
A ::: colon-fence (admonition / div) is a block opener like every other (§24 C3): it nests only when it reaches the item's content column, and folds as lazy text below or above it.
- one
::: note
b
:::<ul>
<li>one
::: note
b
:::</li>
</ul>- one
::: note
b
:::<ul>
<li>one
<aside class="admonition note">
<p>b</p>
</aside>
</li>
</ul>- one
::: note
b
:::<ul>
<li>one
::: note
b
:::</li>
</ul>Fence folds as lazy inline code above the content column
1 conformance fixture
A fenced code block indented past the content column is no longer a block opener; its lines fold as lazy paragraph text, so the backtick run becomes an inline code span (with its content's leading indentation stripped like any inline verbatim span).
- one
```
c
```<ul>
<li><p>one</p>
<p><code>
c
</code></p>
</li>
</ul>Indented ordered marker content column includes the marker indent
1 conformance fixture
The content column of a list item includes the marker's own leading indentation (PART 9 §24 C3): 1. is base column 4 plus marker width 3, so its content column is 7. A block opener dedented below that column but not to column 0 is lazy text, not a new block. A | x | table row at column 2 therefore folds into the item as lazy paragraph text instead of ending the item and escaping the row to a document-level table.
1. y
| x |<ol>
<li>y
| x |</li>
</ol>Outer item with an internal blank before an attached block is loose
1 conformance fixture
An outer list item that contains its own blank line before a block attached below its nested list is loose: the item's leading text is wrapped in a <p>. The blank line separates the item's own content from the trailing blockquote-like paragraph, so the item is not tight even though its nested child list is.
- a
- b
> q<ul>
<li><p>a</p>
<ul>
<li>b</li>
</ul>
<p>> q</p>
</li>
</ul>Tight list item keeps trailing text after a block bare
3 conformance fixtures
In a tight list item, text that follows a closed block (a fenced code block, a div, or an admonition) is part of the item's inline content and is not wrapped in a <p>, matching the item's tightness. Only a blank-separated (loose) item wraps its paragraphs.
- item
```
c
```
tail<ul>
<li>item
<pre><code>c
</code></pre>
tail
</li>
</ul>The same holds after a div body, and for an ordered item.
- item
:::note
body
:::
tail<ul>
<li>item
:::note
body
:::
tail</li>
</ul>A blank line makes the item loose, so its leading text and the trailing text are each wrapped.
- item
```
c
```
tail<ul>
<li><p>item</p>
<pre><code>c
</code></pre>
<p>tail</p>
</li>
</ul>Bare-dot ordered markers
3 conformance fixtures
An ordered marker may drop its value when the delimiter is .: a bare . counts from 1, the AsciiDoc-style shorthand for the list nobody numbers by hand.
. first
. second
. third<ol>
<li>first</li>
<li>second</li>
<li>third</li>
</ol>The bare dot is a spelling, not a dialect: it is decimal-dot, so it opens and continues one list with the explicit form. Only . may drop its value - a leading ) collides with prose parentheticals far more often than a leading . does, the same asymmetry that keeps (1) from being a marker.
1. explicit
. continues the same list
) not a marker, and never opens one<ol>
<li>explicit</li>
<li>continues the same list</li>
</ol>
<p>) not a marker, and never opens one</p>Carrying no value, it cannot set a start - 3. is how that is written - and li-attributes attach to it exactly as they do to every other marker, because the shape is marker, then attributes, then the required space.
.{#x} attributed
. plain<ol>
<li id="x">attributed</li>
<li>plain</li>
</ol>A definition attached by a + continuation marker is collected, and the item keeps no trace
1 conformance fixture
The + continuation marker (§17 L3/L4) attaches a flush-left block to the container above it like any other block - a definition is not special-cased out of that. It is collected exactly as one written at the item's own content column (above), and the item that held it renders with no trace of the line at all: no empty block, no blank line left behind (carve#665; §17 L6).
- a
+
[r]: /u
see [t][r]<ul>
<li>a</li>
</ul>
<p>see <a href="/u">t</a></p>An uppercase roman numeral is a list marker
1 conformance fixture
Roman markers are case-blind: I. opens a list with type="I" as i. does with type="i".
I. one
II. two<ol type="I">
<li>one</li>
<li>two</li>
</ol>Sibling markers that reach one column are one list
1 conformance fixture
The same column claim decides sibling markers as decides a block opener: two markers that reach one column are one list, however the indentation was written. A space advances one column and a tab advances to the next multiple of 4 (§24 C1), so four spaces and a space-plus-tab both put a marker at column 4.
This is the third shape of the rule the corpus pinned in a tab indent is the column it reaches, held back until the residual columns a straddling tab leaves behind stopped claiming source offsets they do not have (carve-js#773).
- a
- b
- c<ul>
<li>a
<ul>
<li>b</li>
<li>c</li>
</ul>
</li>
</ul>The continuation marker at an item's own column, and what follows it
3 conformance fixtures
§17's + continuation marker was pinned by the corpus in one shape only: a marker at column 0 with a BLOCK after it. Both axes it varies - where the marker sits, and what kind of thing follows - were unreached, and each hid a live divergence until someone measured it by hand (carve#812).
An INDENTED + is not consumed as a marker, so it survives as text in the item, and a definition below it is still collected:
- a
+
[r]: /u
see [t][r]<ul>
<li>a
+</li>
</ul>
<p>see <a href="/u">t</a></p>The same indented + with nothing attached stays in the item it was written in, rather than starting a block of its own:
- a
+
x<ul>
<li>a
+</li>
</ul>
<p>x</p>A PARAGRAPH attached by a column-0 + is the shape the marker most obviously serves, and the corpus pinned only non-paragraph blocks - a fenced code block and a block quote - on which the engines had always agreed. Attached paragraph text is bare, not wrapped in its own <p>:
- a
+
b
x<ul>
<li>a
b
</li>
</ul>
<p>x</p>A continuation marker after a blank line in the item
1 conformance fixture
§17 L3 conditions the marker on its COLUMN and on nothing else - not on the item being tight, and not on what the item already holds. The corpus reached it only in a tight item, so an engine could recognize it there and drop it once a blank line had appeared, which is what carve-php did (carve-php#925): the marker came out as literal text inside the paragraph it was meant to end, and the block it should have attached folded in with it.
- a
b
+
c
x<ul>
<li><p>a</p>
<p>b</p>
<p>c</p>
</li>
</ul>
<p>x</p>A continuation marker attaches one block, and the boundary is that block's extent
9 conformance fixtures
327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent-2327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent-3327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent-4327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent-5327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent-6327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent-7327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent-8327-a-continuation-marker-attaches-one-block-and-the-boundary-is-that-block-s-extent-9
§17 L3 says it in capitals: a + attaches "the FOLLOWING flush-left block to that container — ONE block of ANY kind". The trailing "up to the next blank line, sibling marker, or a further +" is the extent of that one block, not a count — an attached list, quote or fenced block is many lines long and still one block (markup-carve/carve#1290).
So a marker takes the paragraph and leaves the quote below it outside the item:
- a
+
para
> q<ul>
<li>a
para
</li>
</ul>
<blockquote><p>q</p></blockquote>A second attached block takes a second marker. This spelling already produces identical output in all three engines, so one block costs a marker line and no expressiveness:
- a
+
para
+
> q<ul>
<li>a
para
<blockquote><p>q</p></blockquote>
</li>
</ul>The one block may be many lines. A wrapped paragraph is not cut at its first line, and the quote below it is still outside:
- a
+
p1
p2
> q<ul>
<li>a
p1
p2
</li>
</ul>
<blockquote><p>q</p></blockquote>An attached LIST is one block too, however many items it holds — the extent clause is what carries them in:
- a
+
> x
> y
- next<ul>
<li>a
<blockquote><p>x
y</p></blockquote>
</li>
<li>next</li>
</ul>A sibling marker ends the attachment rather than being swallowed into it, which is the measured case that settles the reading on its own — three flat items, in every engine:
- a
+
- x
- y<ul>
<li>a</li>
<li>x</li>
<li>y</li>
</ul>The first-block form counts the same way. - + opens an item whose body is the one block that follows, and a second block needs its own marker:
- +
para
> q<ul>
<li>para</li>
</ul>
<blockquote><p>q</p></blockquote>- +
para
+
> q<ul>
<li>para
<blockquote><p>q</p></blockquote>
</li>
</ul>The block-quote form counts the same way. > quoted / + / para / # H attaches the paragraph and leaves the heading outside the quote:
> quoted
+
para
# H<blockquote>
<p>quoted</p>
<p>para</p>
</blockquote>
<section id="H">
<h1>H</h1>
</section>And a second marker brings it in, exactly as in the list form:
> quoted
+
para
+
# H<blockquote>
<p>quoted</p>
<p>para</p>
<h1 id="H">H</h1>
</blockquote>A continuation marker after a blank line in a loose item
1 conformance fixture
The marker sits at the item's marker column and attaches the flush-left block below it, whether or not a blank line comes first. The blank does not loosen the item on its own - this item is loose because of the blank between a and b, not because of the one before the marker.
- a
b
+
c
x<ul>
<li><p>a</p>
<p>b</p>
<p>c</p>
</li>
</ul>
<p>x</p>A fence opened on a list marker line, body below the content column
7 conformance fixtures
276-a-fence-opened-on-a-list-marker-line-body-below-the-content-column276-a-fence-opened-on-a-list-marker-line-body-below-the-content-column-2276-a-fence-opened-on-a-list-marker-line-body-below-the-content-column-3276-a-fence-opened-on-a-list-marker-line-body-below-the-content-column-4276-a-fence-opened-on-a-list-marker-line-body-below-the-content-column-5276-a-fence-opened-on-a-list-marker-line-body-below-the-content-column-6276-a-fence-opened-on-a-list-marker-line-body-below-the-content-column-7
A code fence opened on a list MARKER line, with its body below the item's content column, got four different answers from four readers - the executable spec swallowed the closer into the code text, carve-js did the same with an extra space, carve-php read the column-0 line as body and let the column-0 fence close it, and only carve-rs closed the item (markup-carve/carve#646). No corpus case put a fence body below the content column, so nothing could tell.
PART 9 §24's STEP algorithm already decides it, without a new rule. Take x at column 0 with the stack document > list > item(content_column 2) > code fence body:
- S1 MATCH PREFIXES walks the stack and stops at the first container whose prefix the line does not supply.
xsupplies no indentation, so the walk stops at the ITEM and the fenced body is never reached. - S2 FENCED BODY therefore does not fire: it applies only when the innermost MATCHED container is a fenced body, and here that is the item.
- S4 PARTIAL MATCH governs. Its lazy-continuation branch continues an OPEN PARAGRAPH, and a fenced body is not one - the NO OPEN PARAGRAPH, NO LAZY LINE clause the spec already spells out for
. >. What remains is S4's otherwise: close the unmatched containers and re-classify the residue in the surviving context.
So the item holds an EMPTY code block and x re-parses at document level:
- ```
x
```<ul>
<li>
<pre><code>
</code></pre>
</li>
</ul>
<p>x
<code></code></p>The trailing delimiter becoming EMPTY INLINE CODE is pinned deliberately rather than inherited. It is not part of the rule - it is what a backtick run means once the line is ordinary paragraph text - but it is the kind of output nobody would write down on purpose, so it is stated.
One column in is the same answer, and it is a separate row because the two broken readings differed here: one kept the leading space in the code text and one stripped it. Below the content column is below the content column.
- ```
x
```<ul>
<li>
<pre><code>
</code></pre>
</li>
</ul>
<p>x
<code></code></p>CONTROL. AT the content column the fence body is the item's, the closer closes it, and nothing leaves the item. All four readers always agreed here, which is the shape every existing corpus case uses:
- ```
x
```<ul>
<li>
<pre><code>x
</code></pre>
</li>
</ul>The BLOCK QUOTE analogue is the same derivation with the same answer, and all three engines already agree on it - unenforced until now, which is why the list case could drift away from it:
> ```
x
```<blockquote>
<pre><code>
</code></pre>
</blockquote>
<p>x
<code></code></p>A tilde fence takes the same route, and the residue shows the empty inline code above was a property of the BACKTICK run rather than of this rule: ~~~ in paragraph text is just text.
- ~~~
x
~~~<ul>
<li>
<pre><code>
</code></pre>
</li>
</ul>
<p>x
~~~</p>The guard is on the OPEN FENCE, not on the item's paragraph state. Once the body has collected a line at the content column, a reader tracking "is a paragraph open" sees one again and folds - so this row and the first one need different mechanisms to pass, and only the fence-shaped rule passes both:
- ```
x
y
```<ul>
<li>
<pre><code>x
</code></pre>
</li>
</ul>
<p>y
<code></code></p>The same clause reaches one shape further: a fence opened on a CONTINUATION line rather than on the marker line. S1 stops at the item either way, so the item closes at the below-column line and its closer never joins the body. What the truncated item then holds is §10 I4's business, not this clause's: a opened a paragraph, the fence that follows has no closer left inside the item, and I4 says such a fence does not interrupt - so the delimiter run is paragraph text.
This row is pinned because the executable spec's answer moves here too, and an unpinned move is the drift this corpus exists to prevent. No engine was measured on it - the ticket measured the marker-line spelling - so it is carried by the engine tickets rather than presented as a cross-reader agreement.
- a
```
b
y
```<ul>
<li>a
<code>
b</code></li>
</ul>
<p>y
<code></code></p>A below-column marker after a comment, where no paragraph is open
5 conformance fixtures
277-a-below-column-marker-after-a-comment-where-no-paragraph-is-open277-a-below-column-marker-after-a-comment-where-no-paragraph-is-open-2277-a-below-column-marker-after-a-comment-where-no-paragraph-is-open-3277-a-below-column-marker-after-a-comment-where-no-paragraph-is-open-4277-a-below-column-marker-after-a-comment-where-no-paragraph-is-open-5
§24 C3's below-column branch says a dedented line "folds in as lazy item text". That names an OPERATION, and lazy continuation continues an OPEN PARAGRAPH (§10 I2). A comment ends the paragraph and does NOT end the item - C3's comment exception says both in the same breath - so after one there is nothing to fold into, and the branch has no answer for a case it does not notice it is in (markup-carve/carve#682).
The line is then classified in the context that survives. The item is still open, so a MARKER sits at the item body's own column 0, where C4 Rule B opens a list. carve-js, carve-rs and carve-php all answer this way; the executable spec was the lone dissenter, because it read the comment fence's BODY as prose and believed a paragraph was open.
- a
%%%
x
%%%
- s<ul>
<li>a
<ul>
<li>s</li>
</ul>
</li>
</ul>An ordered marker is the same row, and a separate case because the two marker shapes are recognized by different productions:
- a
%%%
x
%%%
1. o<ul>
<li>a
<ol>
<li>o</li>
</ol>
</li>
</ul>A NON-marker line after the same comment fence is the other half of the clause: it stays in the item too, beginning the item's SECOND paragraph rather than continuing the first. # h is not a heading below the content column, so it is that paragraph's text - and all four readers already agreed here, which is why only the marker shapes ever diverged:
- a
%%%
x
%%%
# h<ul>
<li>a
# h
</li>
</ul>CONTROL, and the one that shows this is the mechanism rather than a coincidence about comments: with the paragraph still OPEN the fold is available and the marker is lazy item text, as C3 says. Deleting the comment fence from the first document inverts its answer.
- a
b
- s<ul>
<li>a
b
- s</li>
</ul>CONTROL. A BLOCK QUOTE leaves its own paragraph open, so the fold is available there too and the marker folds into the quote - the same rule reaching a third answer purely on whether a paragraph is open:
- a
> q
- s<ul>
<li>a
<blockquote><p>q
- s</p></blockquote>
</li>
</ul>A column-zero definition ends an open list item
4 conformance fixtures
Column zero is the surrounding document's opener column. A link or footnote definition there interrupts and closes the item, registers as document metadata, and leaves the following block at document level. Only a nonzero column below the item content column reaches no definition opener and folds as literal text. At the content column the definition belongs to the item, as category 228 pins. A comment remains the explicit exception: its invisibility is accepted independently of column and does not itself close the item.
1. x
[t](u)
_u_
[r]: /u
[t][r]
\#<ol>
<li>x
<a href="u">t</a>
<u>u</u></li>
</ol>
<p><a href="/u">t</a>
#</p>- a
[^f]: note
after[^f]<ul>
<li>a</li>
</ul>
<p>after<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>1. x
[r]: /u<ol>
<li>x
[r]: /u</li>
</ol>1. x
[r]: /u
[t][r]<ol>
<li>x
<a href="/u">t</a>
</li>
</ol>Adjacent sibling lists survive the round trip
3 conformance fixtures
Two lists the parser reads as siblings must still read as two after fmt. Nothing separates them but indentation once their markers match, so the writer keeps one space more on each list than the one before it (PART 11 §1; markup-carve/carve#1088).
1. a
1. b<ol>
<li>a</li>
</ol>
<ol>
<li>b</li>
</ol>A third list steps again rather than repeating the first offset, which would put it back in the second list's column.
1. a
1. b
1. c<ol>
<li>a</li>
</ol>
<ol>
<li>b</li>
</ol>
<ol>
<li>c</li>
</ol>Where the marker already separates them nothing is owed, and the control is that this pair renders the same way with no indentation at all.
- a
* b<ul>
<li>a</li>
</ul>
<ul>
<li>b</li>
</ul>A multi-letter ordered marker opens no list
2 conformance fixtures
PART 2 spells the marker as ordered_marker = (digit+ | letter | roman_numeral), ('.' | ')'). abc is not a run of digits, not the single letter the production admits, and not a roman numeral, so abc. item matches nothing and the line is an ordinary paragraph.
ABC) is the same reading in the other case and with the other delimiter. Note that a SINGLE letter still is a marker - it is the second letter that ends the match - and that a roman run of any length still is one, so iv. item is a list.
The executable spec refused both instead, and no corpus document began a line with a multi-letter word and a dot (markup-carve/carve#1188).
abc. item<p>abc. item</p>ABC) item<p>ABC) item</p>A block attached after an invisible line leaves the item tight
5 conformance fixtures
323-a-block-attached-after-an-invisible-line-leaves-the-item-tight323-a-block-attached-after-an-invisible-line-leaves-the-item-tight-2323-a-block-attached-after-an-invisible-line-leaves-the-item-tight-3323-a-block-attached-after-an-invisible-line-leaves-the-item-tight-4323-a-block-attached-after-an-invisible-line-leaves-the-item-tight-5
PART 9 §17 L1 loosens a list when "some item holds a blank-line-separated second paragraph", and its first clause covers an item followed by a blank line before the next sibling marker. §17 L2 is the other half: a sub-block attached after a blank ATTACHES, and the item stays tight.
An invisible line - a comment, a definition, an attribute block - renders nothing, so it decides neither. 186-an-invisible-line-does-not-cancel-a-blank-line-separation pins that it does not close the separation a blank opened, and 188-a-floating-attribute-stops-at-the-item-boundary pins the case where nothing visible follows it at all and the item really did end at the blank.
What neither of those can say is what happens when a block ATTACHES after the invisible line and the list has a SECOND item. The attachment consumes the separation exactly as it does when no invisible line is there - - a / blank / - b / - c is tight (87-compact-list-blocks-2), and inserting a line that produces no output cannot make the item loose. A reader that remembers the blank and never forgets it loosens here, which is what the executable spec did (carve#1265); every corpus document of this shape had one item, so nothing said so.
An attribute block:
- a
{.x}
- b
- c<ul>
<li>a
<ul class="x">
<li>b</li>
</ul>
</li>
<li>c</li>
</ul>A comment, which is the same rule with a different invisible line - the class of the gap-filler is not the question:
- a
%% note
- b
- c<ul>
<li>a
<ul>
<li>b</li>
</ul>
</li>
<li>c</li>
</ul>A reference definition:
- a
[r]: /u
- b
- c<ul>
<li>a
<ul>
<li>b</li>
</ul>
</li>
<li>c</li>
</ul>Nor is the attached block only a nested list. A quote is a §17 L2 sub-block in the same position:
- a
{.x}
> q
- c<ul>
<li>a
<blockquote class="x"><p>q</p></blockquote>
</li>
<li>c</li>
</ul>And so is a code fence:
- a
{.x}code
- c<ul>
<li>a
<pre class="x"><code>code
</code></pre>
</li>
<li>c</li>
</ul>A PARAGRAPH after the invisible line is the boundary and still loosens, because that is §17 L1's own second paragraph rather than an attachment - 186-an-invisible-line-does-not-cancel-a-blank-line-separation already pins it, one item and two.