Skip to content

Inline parser: apostrophe after a code span trips Q-2-7 (Unclosed Single Quote) #221

@gordonwoodhull

Description

@gordonwoodhull

Claude kept hitting Q-2-7 when writing items in the hub-client changelog. Apostrophe seems to be a special case that works in Pandoc.

Summary

The inline grammar's smart-quote rule treats ' immediately after a closing backtick (code-span boundary) as an opening single quote, even when followed by letters as in a possessive. Pandoc treats the same construct as a possessive and emits no error. As a result, common technical-writing patterns like `setAst`'s callback trip Q-2-7 (Unclosed Single Quote).

Reproducer

printf "x \`code\`'s gate\n" | cargo run --bin pampa -- -t json -i -

Output:

Error: [Q-2-7] Unclosed Single Quote
 1 │ x `code`'s gate
   │         ┬
   │         ╰── This is the opening quote. If you need an apostrophe, escape it with a backslash.

Pandoc reads the same input as a possessive without complaint.

Scope

Pattern Result Why
`code`'s gate FAIL post-codespan ' promoted to opening
`code`'foo bar FAIL same
`code` 's gate FAIL whitespace between doesn't help
`code`\'s gate PASS escaped apostrophe
word's gate PASS letter-letter → possessive
`code`'s and `other`'s pair PASS two opens form a balanced pair
`code`'s and word's pair FAIL only one promoted-to-opening

The angle brackets in patterns like `<AssetManifestContext>`'s are a red herring — backticks alone are the trigger.

Real-world incidents

This has tripped the hub-client changelog at least twice:

  • 0c78b1a4 (2026-05-08) — diagnosis blamed <Tag> HTML-like content; the angle brackets were coincidental.
  • d7d7e063 (2026-05-10) — same pattern in plan changelog entries; rewritten in plain prose to clear the parse.

Proposed fix

In tree-sitter-markdown-inline's grammar, extend the rule for opening single quote so a ' immediately after a closing backtick — more generally, after any inline-end token — is treated as a possessive when the next character is a letter. This is the same heuristic that already handles word's. Pandoc's smart-quote algorithm is "an apostrophe between letters, or after a markup boundary that resolves to letters, is a possessive."

After regenerate + build, add a test case to the inline grammar's corpus and a passing case to resources/error-corpus showing that `code`'s no longer fires Q-2-7.

Workarounds available today

  1. Pair them deliberately in the same block (two close-backtick apostrophes form a smart-quote pair).
  2. Backslash-escape: `code`\'s.
  3. Rephrase so the apostrophe is inside a word (e.g. "the setAst callback's behavior").

Related

  • Internal: bd-1qk5 (this issue's origin), bd-kk0a (writer-side escape for unbalanced apostrophes — a parser fix here would obviate part of bd-kk0a's scope).
  • crates/pampa/snapshots/error-corpus/text/006.snap, 009.snap — current Q-2-7 examples.
  • resources/error-corpus/_autogen-table.json:18686 — parser-state mapping table.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingreaders-writersParsing issues, round-trip discrepancies, writer bugs

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions