Summary
The serializer escapes a ** run that cannot pair, writing _\*\*underscore and one asterisk stay literal* for a line the parser already reads as literal text. CommonMark matches an opener and a closer only when the sum of their run lengths is not a multiple of three, unless both lengths are; here a two-character opener and a one-character closer sum to three, so nothing pairs and the run stays literal on its own. The backslashes change nothing, measured below.
This is the class #252, #256, #257, #258, #271, #289, #292, #293, #336, and #353 removed, reaching the one pairing constraint none of them covered. It is the last escape difference in corpus/commonmark/emphasis.md, though not the last difference: the file also carries the two nesting-collapse lines #213 settled, which no serializer change reaches, so fixing this does not bring the file to byte identity.
Steps to reproduce
- Open a document containing
_**underscore and one asterisk stay literal*.
- Save it without editing.
- Read the file.
Expected behavior
_**underscore and one asterisk stay literal*, unchanged. The run is held literal by the pairing rule rather than by a backslash, as ***two markers stay literal* on line 109 of the same file already is.
Actual behavior
Measured against 8bc36754 by driving the editor mount used by the plugin tests, on corpus/commonmark/emphasis.md line 121.
| Document |
Saved |
_**underscore and one asterisk stay literal* |
_\*\*underscore and one asterisk stay literal* |
The escape is redundant rather than merely cosmetic. Both spellings parse to the same document, measured with mdast-util-from-markdown 2.0.3 from the project's dependency tree:
| Source |
Document |
_**underscore and one asterisk stay literal* |
paragraph("_**underscore and one asterisk stay literal*") |
_\*\*underscore and one asterisk stay literal* |
paragraph("_**underscore and one asterisk stay literal*") |
Closure and convergence both hold today, so neither the corpus round-trip guard nor the document-preservation guard can see this. What it costs is one of the three differences keeping corpus/commonmark/emphasis.md from byte identity.
The same save relaxes the neighbouring case, which is what makes this a defect rather than a house style: ***two markers stay literal* has a three-character opener and a one-character closer, sums to four, pairs, and is written back with no escape.
Related context
Done when
Notes, logs, screenshots
Diagnosis
The serializer's safety check does not model the multiple-of-three constraint. It sees a left-flanking ** run and escapes it as though it could open strong emphasis, without asking whether any closer on the line can match it. The trailing * is the only candidate, and the sum of three rules the pair out.
Out of scope
Summary
The serializer escapes a
**run that cannot pair, writing_\*\*underscore and one asterisk stay literal*for a line the parser already reads as literal text. CommonMark matches an opener and a closer only when the sum of their run lengths is not a multiple of three, unless both lengths are; here a two-character opener and a one-character closer sum to three, so nothing pairs and the run stays literal on its own. The backslashes change nothing, measured below.This is the class #252, #256, #257, #258, #271, #289, #292, #293, #336, and #353 removed, reaching the one pairing constraint none of them covered. It is the last escape difference in
corpus/commonmark/emphasis.md, though not the last difference: the file also carries the two nesting-collapse lines #213 settled, which no serializer change reaches, so fixing this does not bring the file to byte identity.Steps to reproduce
_**underscore and one asterisk stay literal*.Expected behavior
_**underscore and one asterisk stay literal*, unchanged. The run is held literal by the pairing rule rather than by a backslash, as***two markers stay literal*on line 109 of the same file already is.Actual behavior
Measured against
8bc36754by driving the editor mount used by the plugin tests, oncorpus/commonmark/emphasis.mdline 121._**underscore and one asterisk stay literal*_\*\*underscore and one asterisk stay literal*The escape is redundant rather than merely cosmetic. Both spellings parse to the same document, measured with
mdast-util-from-markdown2.0.3 from the project's dependency tree:_**underscore and one asterisk stay literal*paragraph("_**underscore and one asterisk stay literal*")_\*\*underscore and one asterisk stay literal*paragraph("_**underscore and one asterisk stay literal*")Closure and convergence both hold today, so neither the corpus round-trip guard nor the document-preservation guard can see this. What it costs is one of the three differences keeping
corpus/commonmark/emphasis.mdfrom byte identity.The same save relaxes the neighbouring case, which is what makes this a defect rather than a house style:
***two markers stay literal*has a three-character opener and a one-character closer, sums to four, pairs, and is written back with no escape.Related context
docs/decisions.mdunderPreserve the form a file was written in, and underOffer the escape gesture only where the conversion exists, which records that nothing durable is stored for an escape and that it is derived from the text and the serializer's safety check.Done when
Notes, logs, screenshots
Diagnosis
The serializer's safety check does not model the multiple-of-three constraint. It sees a left-flanking
**run and escapes it as though it could open strong emphasis, without asking whether any closer on the line can match it. The trailing*is the only candidate, and the sum of three rules the pair out.Out of scope
*outer *inner* outer*and**outer **inner** outer**lose their inner delimiters at the parse, where a ProseMirror mark set cannot hold the same mark twice, and Emphasis wrapping a link is lost when its label nests the same mark type #213 settled that collapse as correct.