Skip to content

Fidelity constructs: implement the semantic-verdict rows (definitions table, footnotes, link titles, task lists, math, HTML residue) #66

Description

@Mearman

Implementation half of the construct inventory (verdict table in the latest comment on #63, verified against the reader on origin/main — per-construct greps with file:line citations on that ref, not spec recollection), feeding the harmonised vocabulary in ExaDev/document-schema.js#22. The pole-case finding holds: markdown needs no new generic construct kind — every semantic verdict lands on a mechanism the schema major already defines (definitions table, anchor, link, ContentFormula, list-membership/tree fields). Everything below is gated on ExaDev/document-schema.js#24 landing the construct descriptor kinds and package tables additively.

Already carried and untouched: GFM tables with alignment (ContentTable plus per-cell ContentParagraph.alignment), strikethrough (ContentRun.strike), autolinks (ContentRun.hyperlink, with the <...> spelling re-derived on emit when text equals destination). Derivable, dropped without loss: the reference-link form itself (the destination survives on hyperlink; label spelling is a serialisation choice restorable from the definitions table), entity spelling (emit re-escapes), serialisation choices (ATX/setext, bullet glyph, delimiters, fence char, CRLF, tight/loose), and soft line breaks — with the honest caveat that soft breaks are the single largest conformance-exclusion bucket by count.

Semantic rows — reading work, by target in the harmonised vocabulary:

  • Reference link definitions ([label]: dest "title") — package-level definitions table, the same facility the styles table rides; the map is built and returned today but dies at lowering (lowerParsedMarkdown reads only parsed.document.children), and a definitions-only paragraph leaves no block behind — src/block/definitions.ts:66 (extract + consume); src/block/block.ts:782 (map returned); src/lower/lower.ts:258,275 (map ignored); fixtures src/block/block.test.ts:139-158,233
  • Footnotes ([^n] marker + definition) — done in feat: read and write GitHub footnotes, with definitions as anchor constructs #69. The mapping this row proposed turned out backwards on both halves: the DEFINITION is the anchor construct (its body rides the construct's own extent, since AnchorDescriptor.definition names a definitions-table key and a flat ContentDocument has no root table to key into), and the MARKER cannot be an anchor at all — a construct's extent is block-scoped, and a reference site sits between two runs inside a paragraph. The reference ships as a marked run (md/footnote-reference-preserved-as-text) and needs a run-level extent mechanism in document-schema.js to close properly. See the comment below for the full reading
  • Link/image titles — link node: exactly the annotated link extent a flat run field cannot express, the case the standing reconciliation on build(deps): bump document-schema.js to 2.6.1 #22 reserves the node kind for; dropped today on every path (inline links, images both run-degraded and resolved-block, and the definitions table's own titles, parsed then dead with the map) — md/link-title-dropped; src/lower/inline.ts:72-84; src/lower/lower.ts:98; src/test-support/conformance-exclusions.ts (LINK_TITLE)
  • GFM task lists — a real checked/task field on the list-membership representation, replacing today's degraded encoding (a checkbox-glyph text run prepended to the first paragraph plus a task bit encoded into the minted numId; state lost entirely when the item's first block is a table or resolved image) — src/ast/ast.ts:81; src/block/block.ts:685-700; src/lower/lower.ts:165-208 (applyTaskCheckbox, false-return case documented)
  • Code fence info string — the language word as an annotation on the code representation (a field, not a node kind); the remainder goes to residue (see the residue checklist); dropped today when non-empty, diagnosed — md/code-block-info-string-dropped; src/lower/lower.ts:117-124
  • Math ($$ blocks, \(...\) inline, Parse $$ display-math blocks and \( \) inline math #53) — ContentFormula with the canonical-plus-source pattern: LaTeX as the source spelling beside whatever canonical form the schema settles; today's preserved-as-text (MathBlock styleId, inline marker fontFamily) is the interim, not the destination — src/lower/lower.ts:143-152; src/lower/inline.ts:64-67; the MarkdownMathInlineNode comment in src/ast/ast.ts
  • Frontmatter, the unmapped half — mapped keys already reach ContentDocument.metadata; the unmapped remainder (md/front-matter-key-unmapped plus drop) and the non-flat shapes the flat reader silently skips (nested mappings, block lists, multi-line scalars) become a raw front-matter block in the package-level residue channel — src/lower/front-matter.ts:66-87 (switch + default-drop); emit inverse src/emit/front-matter.ts
  • Multi-block list item boundary — item identity on the list-membership model (the schema's list work, not a construct-vocabulary node); today ContentListMembership carries numId/level only, so "one item, several blocks" and "several items" are indistinguishable, and tables/images in an item lose membership entirely — md/list-item-multi-block-flattened, md/list-item-block-unlisted; lowerListItem in src/lower/lower.ts
  • Blockquote container / nesting depth — a container representation in the schema tree, sibling of the item-boundary gap; carried degraded today as indentLeftPt plus a Quote styleId, with depth beyond 1 approximate and the container boundary lost — md/blockquote-nested-depth; lowerBlockquote in src/lower/lower.ts; conformance-exclusions.ts (BLOCKQUOTE_STRUCTURE, ADJACENT_SAME_DEPTH)

Residue rows — quarantined source channel (per the #22 two-channel model):

  • Raw HTML blocks (all seven kinds) — per-node source: { format, ... }, restorable on re-emission; the canonical residue-channel use case from build(deps): bump document-schema.js to 2.6.1 #22, and it also fixes a live ambiguity: literal text that happens to look like a tag is indistinguishable from preserved HTML today (RAW_TEXT_TAG_AMBIGUITY exclusion). Current behaviour is preserve-as-literal-text (default), HTMLPreformatted styleId, or drop under rawHtml: 'drop' — never parsed — src/html/html.ts (recogniser, all 7 block kinds plus the inline grammar); src/lower/lower.ts:130-141; codes md/raw-html-preserved-as-text, md/raw-html-dropped; fixtures src/diagnostics/diagnostics.test.ts:110-121, src/lower/lower.test.ts:281-290
  • Raw HTML inline — per-run source channel, same treatment and same diagnostics — src/lower/inline.ts:57-62
  • Code fence info-string remainder — pandoc-style {.class #id} attributes quarantined beside the semantic language word (see the info-string row above)

Decisions needed — uncertainty to resolve before the split rows freeze:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions