docs/editor-behavior/editor-protocol-matrix.md
This is the exhaustive scenario matrix for editor behavior.
It is intentionally different from the other docs in this directory:
If someone asks, "Do we cover every key, boundary, selection shape, and container interaction?", this is the file that should answer that.
For current in-scope families, the rows are filled. Future releases may still add deferred families or entirely new scenario classes.
Use this file to:
Do not use this file as:
| File | Job |
|---|---|
| markdown-standards.md | methodology and authority model |
| markdown-editing-spec.md | normative family-level law |
| markdown-parity-matrix.md | release-gate coverage by family |
editor-protocol-matrix.md | exhaustive scenario matrix |
This file must follow the authority stack in markdown-standards.md.
That means each family-level table should only give routing hints.
Actual rows still choose authority explicitly.
Each family should name likely:
Syntax / Serialization RefCommon UX CandidatesCommon Cross-Checks / Adjacent RefsFallback Needed?Do not cite stale editor-protocol GitHub issues as authority.
If an older issue happens to describe a useful scenario, port the scenario into this file in Plate's current vocabulary and then drop the link.
Each scenario row should eventually answer:
| Column | Meaning |
|---|---|
Family | markdown-native, markdown extension, block-editor-native, styling/layout, collaboration, cross-surface |
Entity | paragraph, table cell, link, mention, media, etc. |
Node Model | block non-void, block void atom, inline non-void span, inline void atom, leaf mark, text token, overlay / no node |
Context | root, quote, list, table, column, closed container, open container, adjacent to atom, etc. |
Selection | collapsed, expanded-inline, expanded-multiblock, backward, cell-range, node-selected |
Caret / Edge | start, middle, end, before atom, after atom, first visual line, last visual line |
Input | ↵, ⌫, ⌦, ⇥, ⇤, arrows, ⇧+arrow, ⌘+A, copy, paste, hover, plain-click, mod-click, drag, delete command |
Expected | split, reset, lift, unwrap, select container, delete atom, keep native, no-op, etc. |
Authority | syntax ref + primary/secondary UX refs |
Spec ID | canonical ID from the readable spec when one exists |
Evidence | current tests or implementation seams |
Status | one of the statuses below |
seeded
family is listed, but scenarios are not expanded yetspecified
scenario has a chosen rule in the readable spec and is not currently parked
as a deferred runtime/product lanetested
scenario is backed by one or more real testspartial
some parts exist, but the scenario still needs refinementdeferred
scenario or family is intentionally deferred to a later release even if the
readable law already names the intended behaviorThese are real editor-protocol dimensions, but they are not part of the current content-editing completion claim yet.
They live in the deferred integration red suite at
apps/www/src/__tests__/package-integration/__deferred__/.
Run them explicitly with pnpm test:deferred.
| Interaction Class | Primary Authority | Secondary Ref | Current State |
|---|---|---|---|
| Clipboard variants | Typora for general markdown-first clipboard semantics, Google Docs for table and document fidelity | Milkdown, current package integration seams | specified |
| Mouse drag / mouse selection | Google Docs for document selection, Notion for block drag semantics | Milkdown, current DnD and selection seams | specified |
| Interactive preview / navigation | strongest owner by surface: Typora for markdown-native spans and HTML-block edit entry, Obsidian for dual-mode and note-linked navigation surfaces, Google Docs for linear heading navigation, Notion for block-editor-native references | Milkdown, current package and docs seams | specified |
| Navigation feedback / target flash | strongest owner by target surface, with one shared editor-scoped feedback primitive | current package and docs seams | specified |
| Platform shortcuts | strongest product authority for the owning surface | current hotkey and selection seams | specified |
| Delete command variants | Typora for paragraph, code, and math delete-range semantics; Google Docs for table row and column destructive commands | current delete transforms and menu-like seams | specified |
| IME / composition | platform text-editing norms with product-specific owner behavior | current atom/code/table seams | specified |
These are the families that need scenario-complete coverage.
| Family | Common Syntax / Serialization Candidates | Common UX Candidates | Common Cross-Checks / Adjacent Refs | Fallback Needed? | Current State |
|---|---|---|---|---|---|
| Markdown-native structural keys | CommonMark | Typora | Milkdown | only when refs are silent or incompatible | tested |
| Markdown extensions | GFM / GitHub Docs / LaTeX-style math / local MDX contracts | Typora, GitHub Docs, Google Docs, or Obsidian depending on the surface | Milkdown, Notion, current package behavior | sometimes | tested |
| Block-editor-native elements | local serialized shape | Notion and the strongest adjacent mainstream product for the concrete element | Milkdown, current package behavior | sometimes | tested except deferred toggle |
| Styling / layout | local serialized shape + HTML/CSS expectations | Google Docs and the strongest document-style precedent for the concrete surface | Notion, current package behavior | sometimes | tested |
| Cross-surface interactions | mixed by owning surface | Typora, Obsidian, Google Docs, Notion, or a local shared contract depending on the active surface | Milkdown and current package seams | often | specified |
| Collaboration / editor-only | local serialized shape or editor-only contract | Google Docs and the strongest collaboration precedent for the concrete surface | Notion, current package behavior | sometimes | deferred |
This is the canonical model map for the current feature set.
Scenario rows below inherit the entity model from this table unless a row says otherwise.
| Family | Entity | Node Model | Affinity / Boundary Policy |
|---|---|---|---|
| markdown-native | paragraph | block non-void | n/a |
| markdown-native | heading | block non-void | n/a |
| markdown-native | blockquote | block non-void container | n/a |
| markdown-native | list item | block non-void container | n/a |
| markdown-native | link | inline non-void span | directional |
| markdown-native | image | block void media atom | n/a |
| markdown-native | soft mark | leaf mark | directional |
| markdown-native | hard mark | leaf mark | hard |
| markdown-native | code block | block non-void owner | n/a |
| markdown-native | thematic break | block void atom | n/a |
| markdown-native | hard line break | text token | n/a |
| markdown-extension | task list item | block non-void container | n/a |
| markdown-extension | table | block non-void grid owner | n/a |
| markdown-extension | inline math | inline void atom | n/a |
| markdown-extension | block math | block void atom | n/a |
| markdown-extension | autolink literal | inline non-void link span | directional |
| markdown-extension | footnote reference | inline void atom | n/a |
| markdown-extension | footnote definition | block non-void container | n/a |
| markdown-extension | emoji shortcode | text token after parse | n/a |
| block-editor-native | mention | inline void atom | n/a |
| block-editor-native | date | inline void atom | n/a |
| block-editor-native | callout | block non-void container | n/a |
| block-editor-native | toggle | block non-void container | n/a |
| block-editor-native | TOC | block void atom | n/a |
| block-editor-native | column group / item | block non-void container | n/a |
| block-editor-native | media embed | block void atom | n/a |
| block-editor-native | media block | block void media atom | n/a |
| block-editor-native | caption | block non-void helper | n/a |
| block-editor-native | code drawing / excalidraw | block void atom | n/a |
| styling/layout | block style property | block non-void property | n/a |
| styling/layout | style mark | leaf mark | directional |
| collaboration | comment | leaf metadata mark | outward |
| collaboration | suggestion | leaf metadata mark plus block wrapper | outward |
| collaboration | discussion | overlay / anchor surface | n/a |
| collaboration | yjs cursor overlay | overlay / no node | n/a |
These are the first real protocol rows. They are grouped by family and should be extended until every in-scope feature family is scenario-complete.
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| markdown-native | paragraph | root | collapsed | middle | ↵ | split paragraph into two blocks | CommonMark + Typora / Milkdown | EDIT-P-ENTER-001 | withBreakRules.spec.tsx | tested |
| markdown-native | paragraph | root | collapsed | empty block | ↵ | keep generic root split behavior | CommonMark + Typora / Milkdown | EDIT-P-ENTER-EMPTY-001 | withBreakRules.spec.tsx | tested |
| markdown-native | paragraph | root | collapsed | block start, non-empty | ⌫ | merge with previous block when valid | Typora / Milkdown | EDIT-P-BS-START-001 | withMergeRules.spec.tsx | tested |
| markdown-native | paragraph | root | collapsed | empty block | ⌫ | merge into previous block | Typora / Milkdown | EDIT-P-BS-START-EMPTY-001 | withMergeRules.spec.tsx | tested |
| markdown-native | paragraph | root | collapsed | block start | ⇥ | indent paragraph | Typora / Milkdown | EDIT-P-TAB-001 | withIndent.spec.tsx | tested |
| markdown-native | paragraph | root | collapsed | indented paragraph | ⇤ | outdent paragraph | Typora / Milkdown | EDIT-P-STAB-001 | withIndent.spec.tsx | tested |
| markdown-native | paragraph | root | expanded-inline | same block | ↵ | replace the selection with one paragraph split result | CommonMark + Typora / Milkdown | EDIT-SEL-ENTER-001 | withBreakRules.spec.tsx | tested |
| markdown-native | paragraph | root | expanded-inline | same block | ⌫ | delete the selected text in place and keep the paragraph wrapper | Typora / Milkdown | EDIT-SEL-BS-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | paragraph | root | expanded-inline | same block | ⌦ | delete the selected text in place and keep the paragraph wrapper | Typora / Milkdown | EDIT-SEL-BS-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | paragraph | root | expanded-multiblock | mixed blocks | ↵ | replace the selection with one paragraph split result without orphaning surrounding structure | Typora / Milkdown | EDIT-SEL-ENTER-001 | withBreakRules.spec.tsx | tested |
| markdown-native | paragraph | root | expanded-multiblock | mixed blocks | ⌫ | remove the selection without corrupting surrounding structure | Typora / Milkdown | EDIT-SEL-BS-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | paragraph | root | backward expanded-multiblock | mixed blocks | ⌫ | use the same structural cleanup as forward expanded delete | Typora / Milkdown | EDIT-SEL-BS-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | heading | root | collapsed | middle | ↵ | split heading, reset new block to paragraph | Typora / Milkdown | EDIT-H-ENTER-001 | withBreakRules.spec.tsx | tested |
| markdown-native | heading | root | collapsed | end | ↵ | insert paragraph after heading | Typora / Milkdown | EDIT-H-ENTER-END-001 | withBreakRules.spec.tsx | tested |
| markdown-native | heading | root | collapsed | block start | ⌫ | reset heading to paragraph | Typora / Milkdown | EDIT-H-BS-START-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | heading | root | collapsed | empty heading | ⌫ | reset empty heading to empty paragraph | Typora / Milkdown | EDIT-H-BS-START-EMPTY-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | heading | root | expanded-inline | same heading | ↵ | replace the selection and reset the trailing block to paragraph | Typora / Milkdown | EDIT-H-ENTER-001 | withBreakRules.spec.tsx | tested |
| markdown-native | heading | root | expanded-inline | same heading | ⌫ | delete the selection in place and keep the heading type | Typora / Milkdown | — | withDeleteRules.spec.tsx | tested |
| markdown-native | heading | root | expanded-multiblock | heading into paragraph | ⌫ | remove the selection and keep the surviving heading boundary coherent | Typora / Milkdown | EDIT-SEL-BS-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | list item | list | collapsed | middle | ↵ | split item | CommonMark + Typora / Milkdown | EDIT-LIST-ENTER-001 | withList.spec.tsx | tested |
| markdown-native | list item | list | collapsed | empty nested item | ↵ | outdent one level | Typora / Milkdown | EDIT-LIST-ENTER-EMPTY-001 | withList.spec.tsx | tested |
| markdown-native | list item | list | collapsed | empty root item | ↵ | exit list to paragraph | Typora / Milkdown | EDIT-LIST-ENTER-EMPTY-ROOT-001 | withList.spec.tsx | tested |
| markdown-native | list item | list | collapsed | block start | ⌫ | remove one list layer | Typora / Milkdown | EDIT-LIST-BS-START-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | list item | list | collapsed | nested item | ⇥ | indent one list level | Typora / Milkdown | EDIT-LIST-TAB-001 | withList.spec.tsx | tested |
| markdown-native | list item | list | collapsed | nested item | ⇤ | outdent one list level | Typora / Milkdown | EDIT-LIST-STAB-001 | withList.spec.tsx | tested |
| markdown-native | blockquote | quote | collapsed | middle | ↵ | split quoted block | CommonMark + Typora / Milkdown | EDIT-BQ-ENTER-001 | withBreakRules.spec.tsx | tested |
| markdown-native | blockquote | quote | collapsed | empty top-level quoted block | ↵ | exit one quote level | Typora / Milkdown | EDIT-BQ-ENTER-EMPTY-001 | withBreakRules.spec.tsx | tested |
| markdown-native | blockquote | nested quote | collapsed | empty quoted block | ↵ | exit one quote level only | Typora / Milkdown | EDIT-BQ-ENTER-EMPTY-NESTED-001 | withBreakRules.spec.tsx | tested |
| markdown-native | blockquote | nested quote | collapsed | middle | ↵ | split the current inner quoted block and keep both blocks inside the same inner quote | CommonMark + Typora / Milkdown | EDIT-BQ-ENTER-001 | withBreakRules.spec.tsx | tested |
| markdown-native | blockquote | quote | collapsed | block start | ⌫ | lift one quote level | Typora / Milkdown | EDIT-BQ-BS-START-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | blockquote | quote | collapsed | empty non-first block | ⌫ | delete in place inside quote before lifting | Typora / Milkdown | EDIT-BQ-BS-START-EMPTY-NONFIRST-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | blockquote | nested quote | collapsed | first block start | ⌫ | lift one inner quote level and keep outer quote intact | Typora / Milkdown | EDIT-BQ-BS-START-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | blockquote | nested quote | collapsed | empty non-first block | ⌫ | delete in place inside the same inner quote before lifting | Typora / Milkdown | EDIT-BQ-BS-START-EMPTY-NONFIRST-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | blockquote | quote with nested list | collapsed | quoted list item at block start | ⌫ | remove the list layer before the quote layer | Typora / Milkdown | EDIT-LIST-BS-START-001 | withDeleteRules.spec.tsx | tested |
| markdown-native | blockquote | quote | collapsed | quoted paragraph | ⇤ | lift one quote level after indent is exhausted | Typora / Milkdown | EDIT-BQ-STAB-001 | withIndent.spec.tsx | tested |
| markdown-native | blockquote | quote | collapsed | quoted paragraph | ⇥ | keep tab editor-owned via indent | Typora / Milkdown | EDIT-BQ-TAB-001 | withIndent.spec.tsx | tested |
| markdown-native | blockquote | nested quote | expanded-multiblock | mixed inner quote blocks | ⇤ | outdent all selected quoted blocks one quote level after stronger owners | Typora / Milkdown | EDIT-SEL-STAB-001 | withIndent.spec.tsx | tested |
| markdown-native | soft mark | paragraph | collapsed | mark boundary | insert text | directional boundary for soft marks such as bold, italic, and strikethrough | Typora / Milkdown | EDIT-AFF-MARK-001 | AffinityPlugin.spec.tsx, basic-marks.spec.tsx | specified |
| markdown-native | link | paragraph | collapsed | before link end | insert text | extend link when affinity comes from linked side | CommonMark + Typora / Milkdown | EDIT-AFF-LINK-001 | AffinityPlugin.spec.tsx | tested |
| markdown-native | link | paragraph | collapsed | before link start | insert text | keep text outside link when affinity comes from plain side | CommonMark + Typora / Milkdown | EDIT-AFF-LINK-001 | AffinityPlugin.spec.tsx | tested |
| markdown-native | hard mark | paragraph | collapsed | mark boundary | insert text | hard boundary for inline code / kbd | Typora / Milkdown | EDIT-AFF-HARD-001 | AffinityPlugin.spec.tsx | tested |
| markdown-native | code block | code block | collapsed | middle | ↵ | insert code line break inside block | CommonMark + Typora / Milkdown | EDIT-CB-ENTER-001 | withCodeBlock.spec.tsx | tested |
| markdown-native | code block | code block | expanded-inline | one code line | ↵ | replace the selection with a code-local line split | CommonMark + Typora / Milkdown | EDIT-CB-ENTER-001 | withCodeBlock.spec.tsx | tested |
| markdown-native | code block | code block | collapsed | first non-empty line start | ⌫ | keep deletion local to the code line instead of unwrapping | Typora / Milkdown | EDIT-CB-BS-START-001 | withCodeBlock.spec.tsx | tested |
| markdown-native | code block | code block | collapsed | empty non-first line start | ⌫ | merge the empty line into the previous code line and keep the code block | Typora / Milkdown | EDIT-CB-BS-START-001 | withCodeBlock.spec.tsx | tested |
| markdown-native | code block | code block | collapsed | empty block | ⌫ | unwrap to paragraph | Typora / Milkdown | EDIT-CB-BS-START-EMPTY-001 | withCodeBlock.spec.tsx | tested |
| markdown-native | code block | code block | expanded-multiline | many lines | ⇥ | indent every selected code line | Typora / Milkdown | EDIT-CB-TAB-001 | withCodeBlock.spec.tsx | tested |
| markdown-native | code block | code block | expanded-multiline | many lines | ⇤ | outdent every selected code line | Typora / Milkdown | EDIT-CB-STAB-001 | withCodeBlock.spec.tsx | tested |
| markdown-native | code block | code block | inside block | any | ⌘+A | expand the selection to the whole code block | Typora / Milkdown | — | withCodeBlock.spec.tsx | tested |
| markdown-extension | math block | math block | collapsed | first non-empty line start | ⌫ | keep deletion inside math editing instead of generic block exit | Typora / Milkdown with local owner decision | EDIT-MATH-BS-START-001 | markdown-editing-reference-audit.md | specified |
| markdown-extension | math block | math block | collapsed | empty block | ⌫ | exit the empty math block to a paragraph | Typora / Delete Range with local owner decision | EDIT-MATH-BS-START-EMPTY-001 | markdown-editing-reference-audit.md | specified |
| markdown-extension | math block | math block | collapsed | any | ⇥ | keep tab owned by math editing unless a stronger math surface overrides it | local owner decision informed by Typora / Milkdown | EDIT-MATH-TAB-001 | markdown-editing-spec.md | specified |
| markdown-native | hard line break | paragraph | collapsed | inline | serialize | preserve explicit hard break | CommonMark + Typora / Milkdown | EDIT-HARD-* | commonmarkSurface.spec.ts | tested |
| markdown-native | hard line break | blockquote | collapsed | inline | serialize | preserve quoted hard break and trailing break semantics | CommonMark + Typora / Milkdown | EDIT-HARD-* | commonmarkSurface.spec.ts | tested |
| markdown-native | thematic break | root | collapsed | adjacent block boundary | ↵ | create an adjacent paragraph instead of text inside the break | CommonMark + Typora / Milkdown | EDIT-HR-ENTER-001 | markdown-editing-reference-audit.md | specified |
| markdown-native | atomic block | adjacent block boundary | collapsed | block start before atomic node | ⌫ | select or remove according to atomic ownership instead of generic merge | local owner decision | EDIT-ATOMIC-BS-START-001 | markdown-editing-spec.md | specified |
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| markdown-extension | table cell | table | collapsed | inside cell | ↵ | keep Enter inside the same cell | GFM + Google Docs / Notion | EDIT-TABLE-ENTER-001 | withTable.spec.tsx | tested |
| markdown-extension | table cell | table | collapsed | cell start | ⌫ | keep backspace inside current cell | GFM + Google Docs / Notion | EDIT-TABLE-BS-START-001 | withTable.spec.tsx | tested |
| markdown-extension | table cell | table | collapsed | current cell | ⇥ | move to next cell | Google Docs / Notion | EDIT-TABLE-TAB-001 | withTable.spec.tsx | tested |
| markdown-extension | table cell | table | collapsed | current cell | ⇤ | move to previous cell | Google Docs / Notion | EDIT-TABLE-STAB-001 | withTable.spec.tsx | tested |
| markdown-extension | table cell | table | collapsed | last visual line | ↓ | move to cell below | Google Docs / Notion | EDIT-TABLE-ARROWDOWN-MULTIBLOCK-001 | withTable.spec.tsx | tested |
| markdown-extension | table cell | table | collapsed | first visual line | ↑ | move to cell above | Google Docs / Notion | EDIT-TABLE-ARROWUP-MULTIBLOCK-001 | withTable.spec.tsx | tested |
| markdown-extension | table | table | expanded-outward | anchor in cell, focus after table | drag select | clamp focus to the end of the table instead of extending native selection past it | Google Docs / Notion | — | withApplyTable.spec.tsx | tested |
| markdown-extension | table | table | backward expanded-outward | anchor after table, focus in cell | drag select | clamp backward focus to the point before the table | Google Docs / Notion | — | withApplyTable.spec.tsx | tested |
| markdown-extension | table | table | cell-range | n/a | copy | copy selected cells as a subtable | Google Docs / Notion | — | withGetFragmentTable.spec.tsx | tested |
| markdown-extension | table | table | many cells selected | n/a | paste / insert blocks | replace or expand selected cells according to table rules | Google Docs / Notion | — | withInsertFragmentTable.spec.tsx | tested |
| markdown-extension | table | table | collapsed in cell | n/a | first ⌘+A | select the whole table when the caret is inside it | Google Docs / Notion | — | withTable.spec.tsx | tested |
| markdown-extension | table | table | cell-range | n/a | ⇧+arrow | expand selection across cells | Google Docs / Notion | — | onKeyDownTable.spec.tsx, withTableCellSelection.spec.tsx | tested |
| markdown-extension | table | table | cell-range | n/a | addMark | apply the mark to every selected text node across cells | Google Docs / Notion | — | withTableCellSelection.spec.tsx | tested |
| markdown-extension | table | table | cell-range | n/a | removeMark | remove only the requested mark across selected cells | Google Docs / Notion | — | withTableCellSelection.spec.tsx | tested |
| markdown-extension | table | table | cell-range | n/a | marks() | return only marks shared by every selected text node | Google Docs / Notion | — | withTableCellSelection.spec.tsx | tested |
| markdown-extension | table | adjacent block after table | collapsed | block start | ⌫ | move selection toward the adjacent table instead of deleting through a cell boundary | Google Docs / Notion | — | withDeleteTable.spec.tsx | tested |
| markdown-extension | table | table | cell-range | n/a | deleteFragment | clear selected cell contents while keeping the table shape intact | Google Docs / Notion | — | withDeleteTable.spec.tsx | tested |
| markdown-extension | table | table | node-selected table | n/a | second ⌘+A | escalate from table selection to document selection | Google Docs / Notion | — | withTable.spec.tsx | tested |
| markdown-extension | table row | table | collapsed in row | current row | insert row after | insert a row with empty cells after the current row and move selection into it when requested | Google Docs / Notion | EDIT-TABLE-ROW-INSERT-001 | insertTableRow.spec.tsx | tested |
| markdown-extension | table row | table | collapsed in row | current row | insert row before | insert a row with empty cells before the current row and move selection into it when requested | Google Docs / Notion | EDIT-TABLE-ROW-INSERT-002 | insertTableRow.spec.tsx | tested |
| markdown-extension | table column | table | collapsed in column | current column | insert column after | insert a column with empty cells after the current column and move selection into it when requested | Google Docs / Notion | EDIT-TABLE-COL-INSERT-001 | insertTableColumn.spec.tsx | tested |
| markdown-extension | table column | table | collapsed in column | current column | insert column before | insert a column with empty cells before the current column and move selection into it when requested | Google Docs / Notion | EDIT-TABLE-COL-INSERT-002 | insertTableColumn.spec.tsx | tested |
| markdown-extension | table row | merged table | collapsed / expanded | current row | delete row | remove the current row and repair row spans instead of corrupting the merged table | Google Docs / Notion | EDIT-TABLE-ROW-DELETE-001 | transforms/deleteRow.spec.tsx, merge/deleteRow.spec.tsx, merge/deleteRowWhenExpanded.spec.ts | tested |
| markdown-extension | table column | merged table | collapsed / expanded | current column | delete column | remove the current column and repair col spans instead of corrupting the merged table | Google Docs / Notion | EDIT-TABLE-COL-DELETE-001 | transforms/deleteColumn.spec.tsx, merge/deleteColumn.spec.tsx | tested |
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| markdown-extension | task list item | list | round-trip | checked / unchecked | serialize / deserialize | preserve todo checked state through markdown package surfaces | GFM + Typora / Milkdown | EDIT-TASK-* | taskList.spec.ts, deserializeMdList.spec.tsx, listToMdastTree.spec.ts | tested |
| markdown-extension | task list item | list | collapsed | item end | ↵ | insert a new todo line with the same checked-state formatting | Typora / Milkdown | EDIT-LIST-ENTER-001 | withInsertBreakList.spec.tsx | tested |
| markdown-extension | task list item | list | expanded-inline | inside item | ↵ | follow the normal list split path while preserving todo metadata | Typora / Milkdown | EDIT-LIST-ENTER-001 | withInsertBreakList.spec.tsx | tested |
| markdown-extension | strikethrough | paragraph | round-trip | inline mark | serialize / deserialize | preserve ~~strike~~ as a markdown mark | GFM + Typora / Milkdown | — | commonmarkSurface.spec.ts, serializeInlineMd.spec.ts, BaseMarkPlugins.spec.ts | tested |
| markdown-extension | highlight | paragraph | round-trip | inline mark | serialize / deserialize | preserve highlight as <mark>...</mark> MDX text elements | local MDX mark contract informed by Typora / Milkdown | EDIT-MARK-MDX-001 | mdxMarks.spec.tsx, BaseHighlightPlugin.ts | tested |
| markdown-extension | subscript | paragraph | round-trip | inline mark | serialize / deserialize | preserve subscript as <sub>...</sub> MDX text elements | local MDX mark contract informed by Typora / Milkdown | EDIT-MARK-MDX-002 | mdxMarks.spec.tsx, BaseSubscriptPlugin.ts | tested |
| markdown-extension | superscript | paragraph | round-trip | inline mark | serialize / deserialize | preserve superscript as <sup>...</sup> MDX text elements | local MDX mark contract informed by Typora / Milkdown | EDIT-MARK-MDX-003 | mdxMarks.spec.tsx, BaseSuperscriptPlugin.ts | tested |
| markdown-extension | inline math | paragraph | collapsed / expanded | insertion point | insert inline equation | insert an inline void equation and use selected text as the default expression | remark-math + Typora / Milkdown | EDIT-MATH-INLINE-INSERT-001 | insertInlineEquation.spec.ts, BaseInlineEquationPlugin.spec.ts | tested |
| markdown-extension | inline math | inline equation input | collapsed | input left / right edge | ArrowLeft / ArrowRight | hand control back to the editor at text edges | Typora / Milkdown | EDIT-MATH-INLINE-ARROW-001 | useEquationInput.spec.tsx | tested |
| markdown-extension | block math | root | collapsed | insertion point | insert equation | insert a void block equation at the requested path | remark-math + Typora / Milkdown | EDIT-MATH-BLOCK-INSERT-001 | insertEquation.spec.ts, BaseEquationPlugin.spec.ts | tested |
| markdown-extension | block math | next block | collapsed | block start after equation | ⌫ | move selection onto the equation instead of deleting through it | Typora / Milkdown | EDIT-MATH-BLOCK-BS-START-001 | BaseEquationPlugin.spec.ts | tested |
| markdown-extension | autolink literal | paragraph | collapsed | end of URL candidate | type space / ↵ | finalize the URL as a link using the current autolink heuristics and serialize plain URL links back to bare URL markdown | GFM / GitHub Docs + Typora / Milkdown | EDIT-AFF-LINK-001 | withLink.spec.tsx, gfmSurface.spec.ts | tested |
| markdown-extension | footnote definition | paragraph / block | round-trip | footnote definition block | serialize / deserialize | preserve footnote definitions as dedicated footnoteDefinition blocks with an identifier and block children | GFM / GitHub Docs | EDIT-FOOTNOTE-DEF-001 | gfmSurface.spec.ts, packages/footnote/src/lib/BaseFootnoteDefinitionPlugin.ts, defaultRules.ts | tested |
| markdown-extension | footnote reference | paragraph | round-trip | footnote reference token | serialize / deserialize | preserve footnote references as dedicated inline footnoteReference elements with an identifier | GFM / GitHub Docs | EDIT-FOOTNOTE-REF-001 | gfmSurface.spec.ts, packages/footnote/src/lib/BaseFootnoteReferencePlugin.ts, defaultRules.ts | tested |
| markdown-extension | footnote package surface | editor | collapsed / expanded | insertion point | insert footnote | insert a reference, create a missing definition, seed the definition from the current selection when expanded, and focus the definition body | Typora-informed package contract + GFM / GitHub Docs | EDIT-FOOTNOTE-INSERT-001 | insertFootnote.spec.ts, BaseFootnotePlugins.spec.ts | tested |
| markdown-extension | footnote package surface | editor | any | unresolved identifier | create definition | create the missing definition for an existing identifier without inserting another reference and optionally focus the new definition body | local product contract informed by explicit repair flows | EDIT-FOOTNOTE-PKG-001 | createFootnoteDefinition.spec.ts, BaseFootnoteReferencePlugin.ts, content/(plugins)/(elements)/footnote.mdx | tested |
| markdown-extension | footnote reference | paragraph | collapsed | rendered superscript | hover | show footnote content preview instead of entering generic text editing | Typora + GFM / GitHub Docs | EDIT-FOOTNOTE-PREVIEW-001 | markdown-reference.json, content/(plugins)/(elements)/footnote.mdx | specified |
| markdown-extension | footnote reference | paragraph | collapsed | rendered superscript | mod-click | scroll to the matching footnote definition and land a collapsed caret at the start of its body; if unresolved, create the missing definition and focus it instead of failing silently | Typora + GFM / GitHub Docs + local unresolved-repair contract | EDIT-FOOTNOTE-NAV-001 | what-s-new-0-9-84.json, content/(plugins)/(elements)/footnote.mdx, focusFootnoteDefinition.ts, createFootnoteDefinition.spec.ts, footnote-node.spec.tsx | tested |
| markdown-extension | footnote definition | footnote definition block | collapsed | backlink surface | plain-click | scroll back to the matching reference and prefer the nearest stable insertion point outside the ref; atom-selection fallback must show a visible target state and suppress generic formatting chrome | Typora + GFM / GitHub Docs | EDIT-FOOTNOTE-NAV-002 | what-s-new-0-9-84.json, content/(plugins)/(elements)/footnote.mdx, focusFootnoteReference.ts | specified |
| cross-surface | navigation feedback | footnote definition target | after footnote ref jump | collapsed | landed definition body | briefly highlight the landed definition target while preserving the caret at the definition start | local shared navigation-feedback contract informed by Typora / Obsidian / Google Docs | EDIT-NAV-FEEDBACK-* | markdown-editing-spec.md, focusFootnoteDefinition.ts | specified |
| cross-surface | navigation feedback | footnote reference target | after footnote backlink jump | collapsed | landed reference vicinity | briefly highlight the landed reference target while preserving the adjacent caret point or explicit fallback selection state | local shared navigation-feedback contract informed by Typora / Obsidian / Google Docs | EDIT-NAV-FEEDBACK-* | markdown-editing-spec.md, focusFootnoteReference.ts | specified |
| markdown-extension | footnote package surface | editor | any | identifier lookup | definition / references / preview lookup | resolve through one lazy registry-backed index per editor instead of rescanning the whole document or copying preview text onto references | local package contract informed by performance-first editor ownership | EDIT-FOOTNOTE-PKG-001 | registry.ts, footnoteRegistry.spec.ts, BaseFootnoteReferencePlugin.ts | tested |
| markdown-extension | footnote package surface | editor | any | identifier status | resolved / duplicate detection | expose unresolved and duplicate-definition status through package helpers instead of making every render layer rediscover it independently | local package contract informed by performance-first editor ownership | EDIT-FOOTNOTE-PKG-001 | registry.ts, footnoteRegistry.spec.ts, BaseFootnoteReferencePlugin.ts | tested |
| markdown-extension | footnote definition set | editor | duplicate definitions present | same identifier reused across multiple definitions | normalize / repair duplicate definitions | keep the first definition canonical, keep later duplicates explicit invalid definitions, and only renumber on explicit repair action instead of silently merging or renumbering | local owner decision after GFM / GitHub Docs silence on duplicate-definition repair semantics | EDIT-FOOTNOTE-DUP-001 | markdown-editing-spec.md, content/(plugins)/(elements)/footnote.mdx, footnoteRegistry.spec.ts, footnote-node.spec.tsx | tested |
| markdown-extension | footnote package surface | editor | n/a | n/a | toolbar / slash | app-level toolbar and slash-command entries should call the same footnote insert transform instead of inventing separate creation logic | local package contract informed by Typora / Notion-style insertion chrome | EDIT-FOOTNOTE-PKG-001 | transforms.ts, transforms-classic.ts, insert-toolbar-button.tsx, insert-toolbar-classic-button.tsx, slash-node.tsx | specified |
| markdown-extension | emoji shortcode | paragraph | round-trip | shortcode token | serialize / deserialize | accept :shortcode: input in the default markdown profile, normalize it to unicode text, and serialize the unicode text back out | local remark plugin contract informed by Typora / GitHub Docs | EDIT-EMOJI-001 | emojiSurface.spec.tsx, packages/markdown/src/lib/__tests__/createTestEditor.tsx, apps/www/src/registry/components/editor/plugins/markdown-kit.tsx | tested |
| markdown-native | image | paragraph | round-trip | width / height present on node | serialize | keep plain markdown limited to alt, src, and optional title; width and height remain HTML/MDX-only | CommonMark + Typora / Milkdown | EDIT-IMG-* | commonmarkSurface.spec.ts, defaultRules.spec.ts | tested |
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| block-editor-native | callout | callout | collapsed | non-empty content | ↵ | insert soft break inside callout | local callout contract informed by Notion / Milkdown | EDIT-CALLOUT-ENTER-001 | withBreakRules.spec.tsx | tested |
| block-editor-native | callout | callout | collapsed | empty block | ↵ | reset to paragraph | local callout contract informed by Notion / Milkdown | EDIT-CALLOUT-ENTER-EMPTY-001 | withBreakRules.spec.tsx | tested |
| block-editor-native | callout | callout | collapsed | block start | ⌫ | reset to paragraph | local callout contract informed by Notion / Milkdown | EDIT-CALLOUT-BS-START-001 | withDeleteRules.spec.tsx | tested |
| block-editor-native | mention | paragraph | collapsed | block end insertion | insert mention | insert mention atom and optional trailing space | local mention contract informed by Notion / Milkdown | EDIT-MENTION-INSERT-END-001 | getMentionOnSelectItem.spec.tsx | tested |
| block-editor-native | mention | paragraph | collapsed | mid-block insertion | insert mention | insert mention atom without trailing space | local mention contract informed by Notion / Milkdown | EDIT-MENTION-INSERT-MID-001 | getMentionOnSelectItem.spec.tsx | tested |
| block-editor-native | mention | paragraph | collapsed | after mention | ⌫ | delete whole mention atom | local mention contract informed by Notion / Milkdown | EDIT-MENTION-BS-START-001 | BaseMentionPlugin.spec.tsx | tested |
| block-editor-native | mention | paragraph | collapsed | before mention | ⌦ | delete whole mention atom | local mention contract informed by Notion / Milkdown | EDIT-MENTION-DEL-END-001 | BaseMentionPlugin.spec.tsx | tested |
| block-editor-native | mention | paragraph | collapsed | before mention | → | move into the mention child so the inline void stays keyboard-accessible | local mention contract informed by Notion / Milkdown | — | BaseMentionPlugin.spec.tsx | tested |
| block-editor-native | mention | paragraph | collapsed | after mention | ← | move into the mention child so the inline void stays keyboard-accessible | local mention contract informed by Notion / Milkdown | — | BaseMentionPlugin.spec.tsx | tested |
| block-editor-native | date | paragraph | collapsed | insertion | insert date | insert date atom plus trailing space | local date contract informed by Notion / Google Docs | EDIT-DATE-INSERT-001 | insertDate.spec.tsx | tested |
| block-editor-native | date | paragraph | collapsed | after date | ⌫ | delete whole date atom | local date contract informed by Notion / Google Docs | EDIT-DATE-BS-START-001 | BaseDatePlugin.spec.tsx | tested |
| block-editor-native | date | paragraph | collapsed | before date | ⌦ | delete whole date atom | local date contract informed by Notion / Google Docs | EDIT-DATE-DEL-END-001 | BaseDatePlugin.spec.tsx | tested |
| block-editor-native | date | paragraph | collapsed | before date | → | move into the date child so the inline void stays keyboard-accessible | local date contract informed by Notion / Google Docs | — | BaseDatePlugin.spec.tsx, isPointNextToNode.spec.tsx | tested |
| block-editor-native | date | paragraph | collapsed | after date | ← | move into the date child so the inline void stays keyboard-accessible | local date contract informed by Notion / Google Docs | — | BaseDatePlugin.spec.tsx, isPointNextToNode.spec.tsx | tested |
| block-editor-native | date | markdown / mdx | round-trip | canonical or legacy date element | serialize / deserialize | canonicalize safe date input into one YYYY-MM-DD node value, write canonical dates as <date value=\"...\" />, and preserve non-normalizable legacy child text on a raw fallback path | local MDX date contract | EDIT-DATE-MDX-001 | dateElement.spec.ts, content/(plugins)/(serializing)/markdown.mdx | tested |
| block-editor-native | date | markdown / mdx | round-trip | legacy child-text <date>...</date> | deserialize | accept legacy child-text date input for compatibility even though canonical write output uses attribute form | local MDX date contract | EDIT-DATE-MDX-001 | dateElement.spec.ts | tested |
| block-editor-native | date | render layer | inline chip | canonical node.date or raw fallback text | render | bundled UI derives relative labels from canonical YYYY-MM-DD values without timezone drift and renders raw fallback text literally | local current date render contract layered on top of the MDX payload contract | EDIT-DATE-MDX-* | date-node.spec.tsx, date-node-static.spec.tsx, content/(plugins)/(elements)/date.mdx | tested |
| block-editor-native | date | markdown / mdx | round-trip | display-vs-value, locale/timezone, or richer date payload | serialize / deserialize | heavier serialized date semantics beyond the current canonical attribute writer remain deferred until a separate date-expansion lane chooses them explicitly | local MDX date contract with no stronger external authority yet | EDIT-DATE-MDX-* | markdown-editing-spec.md, content/(plugins)/(elements)/date.mdx, content/(plugins)/(serializing)/markdown.mdx | deferred |
| block-editor-native | toc | root | collapsed | insertion | insert toc | insert atomic TOC block | local TOC contract informed by Notion conventions | EDIT-TOC-INSERT-001 | insertToc.spec.ts | tested |
| block-editor-native | toc | toc block | node-selected / collapsed | selected TOC | ⌦ | delete TOC block | local TOC contract informed by Notion conventions | EDIT-TOC-DEL-SELECTED-001 | BaseTocPlugin.spec.ts | tested |
| block-editor-native | toc | next block | collapsed | start of next block | ⌫ | move selection onto TOC instead of deleting through it | local TOC contract informed by Notion conventions | EDIT-TOC-BS-NEXT-001 | BaseTocPlugin.spec.ts | tested |
| block-editor-native | toc | next block | collapsed | start of next block | ↑ | move selection onto the TOC instead of entering its empty child | local TOC contract informed by Notion conventions | — | BaseTocPlugin.spec.ts | tested |
| block-editor-native | toc | toc block | node-selected | selected TOC | ↵ | keep the TOC atomic instead of creating text inside it | local TOC contract informed by Notion conventions | — | BaseTocPlugin.spec.ts | tested |
| block-editor-native | toc | toc block | node-selected | selected TOC | ⇥ | move focus onward or fall through, never tab into TOC text | local TOC contract informed by Notion conventions | — | BaseTocPlugin.spec.ts | tested |
| block-editor-native | columns | paragraph | collapsed | toggle action | toggle columns | wrap content into first column and create empty siblings | local column contract informed by Notion layout behavior | EDIT-COLUMN-TOGGLE-001 | toggleColumnGroup.spec.tsx | tested |
| block-editor-native | columns | column group | collapsed | set columns | update layout | preserve content and redistribute widths | local column contract informed by Notion layout behavior | EDIT-COLUMN-SET-001 | setColumns.spec.tsx | tested |
| block-editor-native | columns | column | inside column | selection in text | first ⌘+A | select the containing column | local column contract informed by Notion layout behavior | — | withColumn.spec.ts | tested |
| block-editor-native | columns | column group | column already selected | second ⌘+A | select the parent column group | local column contract informed by Notion layout behavior | — | withColumn.spec.ts | tested | |
| block-editor-native | columns | paragraph inside column | collapsed | middle | ↵ | split inside the same column and keep the column group intact | local column contract informed by Notion layout behavior | — | withColumn.spec.ts | tested |
| block-editor-native | columns | paragraph inside column | collapsed | block start | ⌫ | respect the contained block owner before any column-group unwrap | local column contract informed by Notion layout behavior | — | withColumn.spec.ts | tested |
| block-editor-native | columns | paragraph inside column | collapsed | any | ⇥ | defer to the stronger local owner; columns are not a direct tab owner | local column contract informed by Notion layout behavior | — | withColumn.spec.ts | tested |
| block-editor-native | media | paragraph | collapsed | insert media | toolbar / URL insert | insert image or media embed according to chosen type | local media contract informed by Notion / Docs | — | insertMedia.spec.ts | tested |
| block-editor-native | media void block | next block | collapsed | block start after media | ⌫ | move selection onto the media node instead of deleting through it | local media contract informed by Notion / Docs | EDIT-MEDIA-* | BaseMediaPluginContracts.spec.ts | tested |
| block-editor-native | media | markdown / mdx | round-trip | file/audio/video/embed | serialize / deserialize | preserve media node shape and MDX attributes | local media contract informed by Notion / Docs | EDIT-MEDIA-* | mediaSurface.spec.ts, parseAttributes.spec.ts | tested |
| block-editor-native | media embed | editor | collapsed | pasted URL or iframe code | insert embed | normalize supported iframe or provider input into a canonical embed url plus current normalized metadata instead of storing raw iframe markup | local media contract informed by Notion / Docs | EDIT-MEDIA-* | parseIframeUrl.spec.ts, parseVideoUrl.spec.ts, parseTwitterUrl.spec.ts, insertMediaEmbed.spec.ts, insertMedia.spec.ts | tested |
| block-editor-native | media embed | editor | collapsed | allowlisted twitter/x sharing snippet | insert / edit embed | extract the canonical status URL and reuse the existing twitter embed path instead of storing the raw snippet | local media contract informed by Notion / Docs | EDIT-MEDIA-* | parseIframeUrl.spec.ts, BaseMediaEmbedPlugin.spec.ts, submitFloatingMedia.spec.ts | tested |
| block-editor-native | media embed | render layer | rendered video or embed node | supported provider metadata | render | current render layer may choose provider-specific preview paths from normalized provider / id / url metadata and prefer optional sourceUrl for edit surfaces without reparsing raw input in app code | local current media render contract layered on top of the normalized embed contract | EDIT-MEDIA-* | useMediaState.spec.ts, media-video-node.spec.tsx, content/(plugins)/(elements)/media.mdx | tested |
| block-editor-native | media placeholder | editor | upload placeholder | upload completes | replace placeholder | replace the placeholder with the final media node and rewrite upload history so undo/redo tracks the real media node | local media contract informed by Notion / Docs | EDIT-MEDIA-* | BasePlaceholderPlugin.spec.ts, history.spec.ts, media-placeholder-node.tsx | tested |
| block-editor-native | media authoring | local video / audio | editor | local file insertion or drag / drop | path policy | follow the same image-path policy family for local media files instead of inventing a separate local-media path contract | Typora + local media contract | EDIT-MEDIA-* | media-authoring-and-path-policy.md, images.json, media.json | specified |
| block-editor-native | media embed | editor | non-allowlisted script-based sharing snippet | paste embed code | trust boundary | do not treat arbitrary script-based embed markup as baseline behavior; only explicit allowlisted transforms may extract canonical embed URLs | Typora + local trust boundary | EDIT-MEDIA-* | media-authoring-and-path-policy.md, media.json | specified |
| block-editor-native | media embed | editor | PDF iframe snippet | paste embed code | baseline support | do not assume PDF iframe support as a baseline current embed path just because generic iframe syntax exists | Typora + local product decision | EDIT-MEDIA-* | media-authoring-and-path-policy.md, media.json | specified |
| block-editor-native | media / embed | markdown / mdx | round-trip / authoring | broader authoring/path-policy, PDF, or open-ended script embeds | serialize / deserialize / edit | broader media/embed product semantics beyond the current normalized url / provider / id / optional sourceUrl contract remain deferred until a separate media-expansion lane locks them | local media contract informed by Notion / Docs with thin external evidence beyond current package behavior | EDIT-MEDIA-* | markdown-editing-spec.md, content/(plugins)/(elements)/media.mdx | deferred |
| block-editor-native | caption | media host | collapsed | move down from host | ↓ | move focus into caption | local caption contract informed by Notion / Docs | EDIT-CAPTION-* | withCaption.spec.tsx | tested |
| block-editor-native | caption | media host | collapsed | move down from disallowed block | ↓ | fall through, do not claim movement | local caption contract informed by Notion / Docs | EDIT-CAPTION-* | withCaption.spec.tsx | tested |
| block-editor-native | toggle | toggle | title row / nested content | collapsed | ↵ / ⌫ / ⇥ | open toggles create nested paragraphs, closed toggles insert the next toggle after hidden content, start-delete removes the toggle shell, and nested content yields to stronger child owners before toggle claims tab | Notion / Milkdown | EDIT-TOGGLE-* | packages/toggle/src/lib/BaseTogglePlugin.spec.ts, packages/toggle/src/react/withToggle.spec.tsx | specified |
| block-editor-native | code drawing | editor | atomic block | n/a | insert / delete boundary | insertion creates one atomic drawing block and adjacent destructive movement targets the block boundary instead of generic merge | Notion-like board tools / local package contract | EDIT-DRAWING-* | insertCodeDrawing.spec.ts, BaseCodeDrawingPlugin.spec.ts | specified |
| block-editor-native | excalidraw | editor | atomic block | n/a | insert / delete boundary | insertion creates one atomic excalidraw block and adjacent destructive movement targets the block boundary instead of generic merge | Notion-like board tools / local package contract | EDIT-DRAWING-* | insertExcalidraw.spec.ts, BaseExcalidrawPlugin.spec.ts | specified |
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| styling/layout | indent | paragraph / quote | collapsed | any | ⇥ / ⇤ | adjust paragraph indent without stealing stronger owners | Google Docs / Notion | EDIT-INDENT-* | withIndent.spec.tsx, setIndent.spec.ts, withList.spec.tsx | tested |
| styling/layout | text align | block | block selection | any | set / clear align | set alignment prop or clear to default | local block style contract informed by Google Docs / Notion | EDIT-ALIGN-* | BaseTextAlignPlugin.spec.ts | tested |
| styling/layout | text indent | block | block selection | any | set / clear text indent | set textIndent prop or clear to default | local block style contract informed by Google Docs / Notion | EDIT-TEXT-INDENT-* | BaseTextIndentPlugin.spec.ts | tested |
| styling/layout | line height | block | block selection | any | set / clear line height | set lineHeight prop or clear to default | local style contract informed by Google Docs / Notion | EDIT-LINE-HEIGHT-* | BaseLineHeightPlugin.spec.ts | tested |
| styling/layout | font family | marked text | collapsed / expanded | boundary | add mark | apply fontFamily leaf mark | local style contract informed by Google Docs / Notion | EDIT-STYLE-* | BaseFontFamilyPlugin.spec.ts | tested |
| styling/layout | font size | marked text | collapsed / expanded | boundary | add mark | apply fontSize leaf mark | local style contract informed by Google Docs / Notion | EDIT-STYLE-* | BaseFontSizePlugin.spec.ts | tested |
| styling/layout | font weight | marked text | collapsed / expanded | boundary | add mark | apply fontWeight leaf mark | local style contract informed by Google Docs / Notion | EDIT-STYLE-* | BaseFontWeightPlugin.spec.ts | tested |
| styling/layout | font color | marked text | collapsed / expanded | boundary | add mark | apply color leaf mark | local style contract informed by Google Docs / Notion | EDIT-STYLE-* | BaseFontColorPlugin.spec.ts | tested |
| styling/layout | font background | marked text | collapsed / expanded | boundary | add mark | apply backgroundColor leaf mark | local style contract informed by Google Docs / Notion | EDIT-STYLE-* | BaseFontBackgroundColorPlugin.spec.ts | tested |
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| collaboration | comment | editor-only | any | any | create/remove/overlap | comments attach metadata to text ranges, survive editing as marks, and stay excluded from markdown serialization | editor-only contract + Google Docs / Notion | EDIT-COMMENT-* | family matrix only | specified |
| collaboration | suggestion | editor-only | any | any | insert/delete/accept/reject | suggestions wrap editing intent in metadata, preserve accept/reject semantics, and stay excluded from markdown serialization | editor-only contract + Google Docs / Notion | EDIT-SUGGESTION-* | family matrix only | specified |
| collaboration | discussion | editor-only | any | any | discussion anchor / block discussion | discussion anchors attach to content as editor-only references and stay outside markdown serialization | editor-only contract + Google Docs / Notion | EDIT-DISCUSSION-* | family matrix only | specified |
| collaboration | yjs | editor-only | any | any | cursor / presence / collaboration policy | presence and remote cursors are runtime collaboration state layered over the editor, not persisted markdown content | editor-only contract + Google Docs / Figma / Notion | EDIT-COLLAB-* | family matrix only | specified |
These rows are still part of the markdown-native family, but they are worth tracking separately because link behavior is much denser than the current law shows.
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| markdown-native | link | paragraph | collapsed | plain text | paste URL | insert a link with the pasted URL text | CommonMark + Typora / Milkdown | EDIT-AFF-LINK-001 | withLink.spec.tsx | tested |
| markdown-native | link | paragraph | expanded-inline | selected plain text | paste URL | keep selected text as link text by default | CommonMark + Typora / Milkdown | — | withLink.spec.tsx | tested |
| markdown-native | link | paragraph | expanded-inline | selected plain text | paste URL with keepSelectedTextOnPaste: false | replace selected text with URL text | CommonMark + Typora / Milkdown | — | withLink.spec.tsx | tested |
| markdown-native | link | paragraph | collapsed | rendered link | plain-click | expand the link for editing instead of navigating away immediately | Typora | EDIT-LINK-CLICK-001 | markdown-reference.json, content/(plugins)/(elements)/link.mdx | specified |
| markdown-native | link | paragraph | collapsed | rendered link | mod-click | open the target in the browser | Typora | EDIT-LINK-CLICK-002 | markdown-reference.json, content/(plugins)/(elements)/link.mdx | specified |
| markdown-native | link | paragraph | collapsed | end of URL text | type space | wrap preceding URL as a link | CommonMark + Typora / Milkdown | — | withLink.spec.tsx | tested |
| markdown-native | link | paragraph | collapsed | end of visible URL text | type space with getUrlHref | wrap visible text with computed href | CommonMark + Typora / Milkdown | — | withLink.spec.tsx | tested |
| markdown-native | link | paragraph | collapsed | inside existing link | type space | do not wrap again | CommonMark + Typora / Milkdown | — | withLink.spec.tsx | tested |
| markdown-native | link | paragraph | collapsed | end of autolink candidate | ↵ | finalize autolink before creating the next block | CommonMark + Typora / Milkdown | — | withLink.spec.tsx | tested |
| markdown-native | link | paragraph | collapsed | empty link after deletion | normalize | remove empty link wrapper | CommonMark + Typora / Milkdown | — | withLink.spec.tsx | tested |
| markdown-native | link | paragraph | collapsed or expanded | inside/outside link | upsert URL/text | preserve marks, update href/text, or unwrap according to transform intent | CommonMark + Typora / Milkdown | — | upsertLink.spec.tsx, unwrapLink.spec.tsx | tested |
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| block-editor-native | media embed | paragraph | collapsed | with selection parent | insert embed | insert embed node at the parent path with nextBlock semantics | local media contract informed by Notion / docs | EDIT-MEDIA-* | insertMediaEmbed.spec.ts | tested |
| block-editor-native | media embed | paragraph | no selection | n/a | insert embed | no-op | local media contract informed by Notion / docs | EDIT-MEDIA-* | insertMediaEmbed.spec.ts | tested |
| block-editor-native | image upload | editor | data transfer with image file | n/a | insert data | current default path ignores upload without a configured override | local media contract informed by Notion / docs | EDIT-MEDIA-* | withImageUpload.spec.tsx | tested |
| block-editor-native | image upload | editor | no files | n/a | insert data | fall through to default insert data behavior | local media contract informed by Notion / docs | EDIT-MEDIA-* | withImageUpload.spec.tsx | tested |
| block-editor-native | image upload | editor | non-image file | n/a | insert data | ignore non-image file without changing editor | local media contract informed by Notion / docs | EDIT-MEDIA-* | withImageUpload.spec.tsx | tested |
| block-editor-native | toc | editable document | n/a | generated entry | plain-click | navigate to the matching heading while keeping the TOC non-editable; do not place a caret in the landed heading or enter block-selection mode as a side effect | local TOC contract informed by Notion block shell plus Typora / Google Docs heading navigation | EDIT-TOC-NAV-001 | content/(plugins)/(elements)/toc.mdx, markdown-editing-spec.md, navigation-search-outline-and-toc.md | specified |
| block-editor-native | toc | readonly document | n/a | generated entry | plain-click | navigate to the matching heading without selection or edit-entry side effects | local TOC contract informed by Typora / Google Docs heading navigation | EDIT-TOC-NAV-001 | content/(plugins)/(elements)/toc.mdx, markdown-editing-spec.md, navigation-search-outline-and-toc.md | specified |
| block-editor-native | toc | editable / readonly document | n/a | focused generated entry | ↵ / Space | perform the same navigation as pointer activation while keeping the entry keyboard-accessible and avoiding hidden editor-selection focus traps | local TOC contract informed by Typora / Google Docs heading navigation and Obsidian-style navigation chrome pressure | EDIT-TOC-NAV-002 | markdown-editing-spec.md, navigation-search-outline-and-toc.md, linking-navigation-and-search.md | specified |
| block-editor-native | toc | toc block | generated entry set | current active section | scroll / edit | keep exactly one TOC entry marked current so the live TOC reflects the heading nearest the current document position | local TOC contract informed by Typora / Google Docs heading navigation plus current Plate TOC observer surfaces | EDIT-TOC-NAV-003 | useContentController.spec.tsx, useTocElement.spec.tsx, toc-node.spec.tsx | tested |
| block-editor-native | caption | media host | collapsed | arrow-up from caption boundary | ↑ | store focusEndPath when caption has content | local caption contract informed by Notion / Docs | EDIT-CAPTION-* | withCaption.spec.tsx | tested |
| block-editor-native | caption | media host | collapsed | arrow-up from caption boundary | ↑ | skip delayed focus when caption is empty | local caption contract informed by Notion / Docs | EDIT-CAPTION-* | withCaption.spec.tsx | tested |
| Family | Entity | Context | Selection | Caret / Edge | Input | Expected | Authority | Spec ID | Evidence | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| cross-surface | source-entry surface | rendered markdown-native surface | collapsed | source-editable target | plain-click | prefer source-oriented edit entry over passive preview-only behavior | Typora | EDIT-INTERACT-* | links-images-and-html-behavior.md, source-entry-surface.md, markdown-editing-spec.md | specified |
| cross-surface | source-entry surface | rendered markdown-native surface | collapsed | openable target | mod-click | open or jump to the target instead of entering edit mode | Typora | EDIT-INTERACT-* | links-images-and-html-behavior.md, source-entry-surface.md, markdown-editing-spec.md | specified |
| cross-surface | clipboard | mixed rich selection | any | n/a | copy | expose rich and plain clipboard representations together while preserving the strongest available structure | Typora for general markdown-first clipboard semantics, Google Docs for table/document fidelity | EDIT-CLIPBOARD-* | copy-and-paste.json, MarkdownPlugin.spec.ts, PlateView.tsx, withSetFragmentDataTable.spec.tsx | partial |
| cross-surface | clipboard | editor | clipboard carries html plus plain text | n/a | paste | prefer HTML reconstruction, then fall back to markdown source or plain text without dropping structure too early | Typora for general markdown-first paste semantics, Google Docs for table/document fidelity | EDIT-CLIPBOARD-* | copy-and-paste.json, MarkdownPlugin.spec.ts, withInsertFragmentTable.spec.tsx | specified |
| cross-surface | delete command | paragraph | collapsed | current sentence | delete command | delete the current sentence instead of treating the action like block removal | Typora | EDIT-CMD-DELETE-* | delete-range.json | specified |
| cross-surface | delete command | table | collapsed | current row | delete command | delete the current row instead of applying generic text deletion inside the active cell | Google Docs + Typora | EDIT-CMD-DELETE-* | delete-range.json, transforms/deleteRow.spec.tsx, merge/deleteRow.spec.tsx | specified |
| cross-surface | delete command | code block | collapsed | current line | delete command | delete the current code line like a code editor instead of structurally exiting the block | Typora | EDIT-CMD-DELETE-* | delete-range.json, withCodeBlock.spec.tsx | specified |
| cross-surface | delete command | math block | collapsed | current line | delete command | delete the current math line like a code-like editing surface instead of structurally exiting the block | Typora | EDIT-CMD-DELETE-* | delete-range.json, markdown-editing-reference-audit.md | specified |
| cross-surface | search | document | collapsed | current caret | open find | open current-file search without changing document structure | Typora | EDIT-SEARCH-* | search.json, shortcut-keys.json | deferred |
| cross-surface | search | document | collapsed | active selection | open search from selection | seed the search surface from the current selection instead of discarding it and reopening with an empty query | Obsidian for selected-text search kickoff, Typora as the current-file find secondary check | EDIT-SEARCH-* | Search.md, search.json, shortcut-keys.json | deferred |
| cross-surface | search | document | collapsed | current caret | find next / previous | move to the next or previous match from the active search state instead of restarting generic navigation | Typora | EDIT-SEARCH-* | search.json, shortcut-keys.json, what-s-new-0-9-54.json | deferred |
| cross-surface | search | document | collapsed | current selection | jump to selection | scroll and focus the active selection instead of changing document content | Typora | EDIT-SEARCH-* | shortcut-keys.json | deferred |
| cross-surface | search | document | collapsed / expanded | active match | replace | replace only the matched range and preserve surrounding block structure instead of degrading into raw text replacement across unrelated nodes | Typora | EDIT-SEARCH-* | search.json, shortcut-keys.json, content/(plugins)/(functionality)/find-replace.mdx | deferred |
| cross-surface | navigation feedback | search target | after search jump | collapsed / expanded | navigation completes | briefly highlight the landed search target while preserving active search state and the landed caret or selection | local shared navigation-feedback contract informed by Typora / Obsidian / Google Docs | EDIT-NAV-FEEDBACK-* | markdown-editing-spec.md, search.json, Search.md | deferred |
| cross-surface | outline | document heading tree | n/a | outline item | plain-click | navigate to the matching heading and keep current-section highlighting coherent while editing and scrolling; do not create landed caret or block-selection state as a side effect | Obsidian for persistent outline chrome, Google Docs for linear heading jump, Typora as markdown-first secondary check | EDIT-INTERACT-* | Outline.md, outline.json, markdown-editing-spec.md | specified |
| cross-surface | outline | document heading tree | n/a | focused outline item | ↵ / Space | perform the same navigation as pointer activation while keeping the outline keyboard-accessible | Obsidian for persistent outline chrome, Google Docs for linear heading jump | EDIT-INTERACT-* | Outline.md, outline.json, markdown-editing-spec.md | specified |
| cross-surface | outline | document heading tree | n/a | current active section | scroll / edit | highlight the current heading in the outline while the user edits or scrolls through the document | Google Docs for linear document navigation, Obsidian as persistent-outline pressure | EDIT-INTERACT-* | outline.json, Outline.md | specified |
| cross-surface | outline | document heading tree | n/a | filter input | search headers | filter the outline to quickly locate target headings without changing document content | Typora + Google Docs-style document navigation | EDIT-SEARCH-* | outline.json, what-s-new-0-9-61.json | deferred |
| cross-surface | navigation feedback | heading target | after TOC / outline jump | n/a | navigation completes | briefly highlight the landed heading while preserving the navigation result and current-section state | local shared navigation-feedback contract informed by Obsidian / Google Docs | EDIT-NAV-FEEDBACK-* | markdown-editing-spec.md, toc.mdx, Outline.md | specified |
| cross-surface | typed syntax-trigger conversion | markdown-native source syntax | collapsed / expanded-inline | incomplete or ambiguous source | type intermediate delimiter or partial source entry | keep the source literal instead of converting early | Typora primary; Obsidian and Milkdown as conversion-boundary counterweights | EDIT-CONVERT-001 | input-autoformat-lanes.md, math-delimiters-and-pair-settings.md, markdown-editing-spec.md | specified |
| cross-surface | typed syntax-trigger conversion | markdown-native source syntax | collapsed / expanded-inline | explicit completing trigger | type the completing trigger for the surface | convert only at an explicit boundary and preserve the subfamily's explicit re-entry path instead of leaving passive preview-only output | Typora primary; Obsidian and Milkdown as row-specific cross-checks | EDIT-CONVERT-002 | input-autoformat-lanes.md, math-delimiters-and-pair-settings.md, markdown-editing-spec.md | specified |
| cross-surface | html block | markdown / mdx | round-trip / edit-entry fallback | raw HTML block in markdown input | deserialize | preserve the HTML block as editable source text instead of dropping attributes or degrading it into lossy fallback text | CommonMark HTML block semantics + Typora source-entry pressure | EDIT-INTERACT-* | deserializeMd.spec.ts, customMdxDeserialize.spec.ts, links-images-and-html-behavior.md | tested |
| cross-surface | html block | html block | collapsed | non-interactive region of a richer rendered html surface | plain-click / mod-click / cursor-entry | enter HTML-block edit mode instead of treating the block as pure rendered output chrome | Typora + CommonMark HTML block semantics | EDIT-INTERACT-* | html.json | deferred |
| cross-surface | image authoring | editor | collapsed | insertion point | drag / drop / paste image | follow the active image path policy and insert an image surface without forcing raw file URLs into generic text | Typora for markdown-native authoring expectations, local media contract for current package seams | EDIT-IMG-* | images.json, upload-image.json, withImageUpload.spec.tsx | specified |
| cross-surface | image authoring | markdown image | collapsed | rendered image | plain-click | prefer source editing when the image surface is directly editable | Typora | EDIT-IMG-* | markdown-reference.json, images.json | specified |
| cross-surface | image authoring | markdown image | collapsed | existing image source | move / copy image path action | rewrite the stored path and keep markdown references coherent when the product exposes explicit path-management actions | Typora | EDIT-IMG-* | images.json | specified |
| cross-surface | media authoring | video / audio / embed block | collapsed | insertion point | drag / drop or paste supported media | follow the same active path-policy family as images instead of inventing a separate media path model | Typora for path expectations, local media contract for current package seams | EDIT-MEDIA-* | media.json, withImageUpload.spec.tsx | specified |
| cross-surface | block shorthand autoformat | paragraph | collapsed | block start | type # | retag the current block into a heading when the shorthand closes | CommonMark heading syntax + Typora / Milkdown | EDIT-PROFILE-AUTOFMT-BLOCK-001 | markdown-shorthand-and-inline-autoformat.md, input-autoformat-lanes.md, withAutoformat/block/heading.spec.tsx | specified |
| cross-surface | block shorthand autoformat | paragraph / quote paragraph | collapsed | block start | type > | wrap the current block in a blockquote container, including nested quote entry when the rule allows same-type wrapping | CommonMark blockquote syntax + Typora / Milkdown | EDIT-PROFILE-AUTOFMT-BLOCK-002 | markdown-shorthand-and-inline-autoformat.md, input-autoformat-lanes.md, apps/www/src/__tests__/package-integration/autoformat/blockquote.slow.tsx | specified |
| cross-surface | block shorthand autoformat | paragraph | collapsed | block start | type - / * / 1. / 1) | convert the block into a list item and preserve explicit ordered starts when supplied | CommonMark / GFM list syntax + Typora / Milkdown | EDIT-PROFILE-AUTOFMT-BLOCK-003 | markdown-shorthand-and-inline-autoformat.md, input-autoformat-lanes.md, apps/www/src/__tests__/package-integration/autoformat/list.slow.tsx | specified |
| cross-surface | block shorthand autoformat | paragraph | collapsed | block start | type [] / [x] | current kit creates unchecked or checked todo items from condensed task shorthand | local current task-shorthand contract informed by Typora / Milkdown task syntax | EDIT-PROFILE-AUTOFMT-BLOCK-004 | apps/www/src/registry/components/editor/plugins/autoformat-kit.tsx, apps/www/src/__tests__/package-integration/autoformat/list.slow.tsx | specified |
| cross-surface | block shorthand autoformat | paragraph | collapsed | fence trigger | type the third backtick of a triple-backtick sequence | current kit promotes immediately into a code block owner when the triple-backtick shorthand closes | local current code-fence trigger contract informed by Typora code-fence docs | EDIT-PROFILE-AUTOFMT-BLOCK-005 | markdown-shorthand-and-inline-autoformat.md, withAutoformat/block/code-block.spec.tsx | specified |
| cross-surface | block shorthand autoformat | paragraph | collapsed | hr trigger | type --- / —- / ___ | current kit inserts a horizontal rule and a trailing paragraph immediately when the shorthand closes | local current HR shorthand contract informed by Typora thematic-break docs | EDIT-PROFILE-AUTOFMT-BLOCK-006 | markdown-shorthand-and-inline-autoformat.md, apps/www/src/registry/components/editor/plugins/autoformat-kit.tsx | specified |
| cross-surface | inline mark autoformat | paragraph | collapsed | valid delimiter span | type closing * / _ / ~~ / ` | convert the delimited span to the target mark and remove the wrappers | CommonMark / GFM + Typora / Milkdown | EDIT-PROFILE-AUTOFMT-MARK-001 | markdown-shorthand-and-inline-autoformat.md, input-autoformat-lanes.md, withAutoformat/mark/basic-marks.spec.tsx | specified |
| cross-surface | inline mark autoformat | paragraph | collapsed | valid == / ~ / ^ span | type closing delimiter | convert the delimited span to highlight, subscript, or superscript mark and remove the wrappers | Typora + local current mark contract | EDIT-PROFILE-AUTOFMT-MARK-002 | markdown-shorthand-and-inline-autoformat.md, apps/www/src/registry/components/editor/plugins/autoformat-kit.tsx | specified |
| cross-surface | inline mark autoformat | paragraph | collapsed | valid composed delimiter span | type closing delimiter for *** or related compositions | apply the configured combined marks in one pass | local current mark-composition contract informed by markdown delimiter nesting | EDIT-PROFILE-AUTOFMT-MARK-003 | withAutoformat/mark/multiple-marks.spec.tsx, withAutoformat/markup.spec.tsx | specified |
| cross-surface | inline mark autoformat | paragraph | collapsed | invalid / intra-word delimiter run | type closing delimiter | leave the text literal instead of forcing a mark | Milkdown explicit + local current tests | EDIT-PROFILE-AUTOFMT-MARK-004 | input-autoformat-lanes.md, withAutoformat/invalid.spec.tsx, withAutoformat/ignoreTrim.spec.tsx | specified |
| cross-surface | inline mark autoformat | paragraph | collapsed | overlapping == trigger | type closing = around text | highlight-mark autoformat wins before equality-symbol substitution in current app-kit rule order | local current rule-order contract | EDIT-PROFILE-AUTOFMT-MARK-005 | apps/www/src/registry/components/editor/plugins/autoformat-kit.tsx, packages/autoformat/src/lib/rules/math/autoformatEquality.ts | specified |
| cross-surface | text-substitution autoformat | paragraph | collapsed | quote trigger | type a straight quote in a valid smart-quote context | replace straight quotes with smart quotes in place | mainstream typographic norms + local current contract | EDIT-PROFILE-AUTOFMT-TEXT-001 | withAutoformat/text.spec.tsx, autoformatSmartQuotes.ts | specified |
| cross-surface | text-substitution autoformat | paragraph | collapsed | punctuation shorthand | type -- / ... / >> / << | replace the shorthand with typographic punctuation in place | mainstream typographic norms + local current contract | EDIT-PROFILE-AUTOFMT-TEXT-002 | withAutoformat/text.spec.tsx, autoformatPunctuation.ts | specified |
| cross-surface | text-substitution autoformat | paragraph | collapsed | symbol shorthand | type -> / (tm) / 1/2 / >= or another configured symbol sequence | replace the shorthand with the configured symbol in place | local current shorthand contract with thinner external grounding | EDIT-PROFILE-AUTOFMT-TEXT-003 | text-substitution-autoformat-authority.md, withAutoformat/text.spec.tsx, autoformatMath.spec.ts | specified |
| cross-surface | text-substitution autoformat | paragraph | collapsed | immediately after a text substitution | press ⌫ with undo-on-delete enabled | restore the original shorthand instead of deleting the formatted symbol directly | local current contract | EDIT-PROFILE-AUTOFMT-TEXT-004 | AutoformatPlugin.spec.tsx, withAutoformat/trigger.spec.tsx | specified |
| cross-surface | autoformat gating | code block | collapsed | inside code block | type a matching shorthand | keep the text literal because the current app kits disable autoformat inside code blocks | local current kit contract | EDIT-PROFILE-AUTOFMT-TEXT-005 | apps/www/src/registry/components/editor/plugins/autoformat-kit.tsx | specified |
| cross-surface | link automd | paragraph | collapsed | complete [text](url source entry | type ) | create a structured inline link span from markdown source entry when the link-automd surface is enabled | CommonMark link syntax + Typora / Milkdown | EDIT-INTERACT-LINK-AUTOMD-001 | markdown-shorthand-and-inline-autoformat.md, input-autoformat-lanes.md, packages/link/src/lib/automd/linkAutomdInputRule.spec.tsx, apps/www/src/__tests__/package-integration/link/link-automd.slow.tsx | tested |
| cross-surface | strict mode | markdown input | collapsed | malformed heading or list-following paragraph syntax | type markdown syntax with strict mode enabled | keep malformed source as text until it satisfies stricter markdown structure rules | Typora + CommonMark / GFM strict syntax expectations | EDIT-PROFILE-STRICT-* | strict-mode.json | specified |
| cross-surface | auto pair | markdown input | collapsed | opening bracket or quote | type pair opener with auto pair enabled | insert the matching closer using standard editor pairing behavior | Typora + mainstream code-editor norms | EDIT-PROFILE-AUTOPAIR-* | auto-pair.json | specified |
| cross-surface | auto pair | markdown input | expanded-inline | selected text | type markdown-sensitive pair with auto pair enabled | wrap the selection instead of blindly inserting a closing pair for ambiguous markdown symbols | Typora + mainstream code-editor norms | EDIT-PROFILE-AUTOPAIR-* | auto-pair.json | specified |
| cross-surface | math delimiter trigger | paragraph | expanded-inline | selected text | type $ | wrap the selection in inline-math delimiters when the math-trigger surface is enabled | Obsidian explicit; Typora and Milkdown adjacent | EDIT-PROFILE-MATH-TRIGGER-001 | math-delimiters-and-pair-settings.md | deferred |
| cross-surface | math delimiter trigger | paragraph | collapsed | complete $... source before the caret | type closing $ | convert the completed delimiter run into an inline math node on explicit completion instead of pairing on the opening delimiter | local current rich-mode conversion decision informed by source-preserving conversion law, with Typora / Milkdown adjacent | EDIT-PROFILE-MATH-TRIGGER-002 | packages/autoformat/src/lib/rules/math/autoformatMathInput.spec.tsx, apps/www/src/__tests__/package-integration/math/math-trigger.slow.tsx, markdown-editing-spec.md | tested |
| cross-surface | math delimiter trigger | paragraph | collapsed | line contains $$ only | press ↵ | promote into block math editing instead of leaving raw text when the trigger surface is enabled | Typora + Milkdown explicit; Obsidian explicit for standalone-line $$ block detection and preview, not the same ↵ promotion mechanic | EDIT-PROFILE-MATH-TRIGGER-003 | packages/autoformat/src/lib/rules/math/autoformatMathInput.spec.tsx, apps/www/src/__tests__/package-integration/math/math-trigger.slow.tsx, markdown-editing-spec.md | tested |
If a row only exists in the parity matrix, it is not protocol-complete yet.