ADR-0056: Visual-Editor Chrome via Milkdown Crepe (gated adoption)¶
- Status: accepted
- Superseded by: ADR-0059 — the Crepe chrome (§1/§4) is replaced by TipTap-based chrome; the license-sweep and spike-gating practice carry over.
- Retired in part by: ADR-0057 — the §3 canon-fencing machinery is void for tree-format versions (whatever the tree holds is exactly what renders); §1/§2 (Crepe chrome, spike-gated adoption) stand.
- Date: 2026-07-09
- Deciders: Nicolas Burri ("all in with milkdown" — torn resolved after license check and spike-gated proposal), amends the R4c slice plan of ADR-0055
- Relates to: ADR-0045 (markdown canon), ADR-0055 (visual mode, fidelity gate, entry guard)
Context¶
R4b shipped the visual mode with hand-rolled chrome (Material toolbar, minimal ProseMirror CSS). Live testing immediately surfaced the cost of owning WYSIWYG chrome: focus/caret/click-surface bugs, invisible tables, missing heading-level and table-editing UX — the class of problem the Milkdown ecosystem (editor: Crepe, same engine underneath) has already solved and maintains upstream. Nicolas's assessment: rebuilding an editor from scratch is "a catch-up race against an entire eco system", the app's Material look is not sacred (visual rework expected later anyway), and the visual editor is a primary user-acceptance driver that must properly work.
License check (2026-07-09): the ENTIRE stack is MIT — all @milkdown/* incl. Crepe, ProseMirror, remark/unified, Vue, KaTeX; full production tree swept: no GPL/LGPL/AGPL anywhere (only permissive: MIT/ISC/BSD/Apache; DOMPurify dual MPL/Apache — Apache elected). Obligation: ship a third-party-notices file pre-release (registered as a small task).
Decision¶
- Adopt Crepe as the visual-mode chrome — toolbar, slash menu, table editing UI, block handles — replacing the R4b hand-rolled toolbar. The R4b compliance architecture is UNCHANGED and non-negotiable: markdown stays the single source of truth, the shared-pipeline fidelity gate and the per-document entry guard (ADR-0055 §3/§4 incl. the D8 newline policy) now apply to CREPE'S exact parse/serialize configuration.
- Verification-first spike gates the adoption. Before any UI lands: run the fidelity corpus
against the Crepe-configured pipeline; verify per-feature fencing (LaTeX/math OFF — outside
the canon); measure the lazy-chunk cost (Vue runtime rides along; KaTeX must not, with math
off); confirm our serializer options apply. A canon-breaking finding falls back to
Material-native chrome (ADR-0055 R4c as originally planned) — the engine/pipeline work
transfers 1:1 either way. The spike also EVALUATES (facts, no adoption yet):
@milkdown/plugin-diffas a read-only RENDERED delta view between versions (presentation layer only — the source-level word-marked diff stays the controlled ground truth), and whether display rendering should later unify on remark (today markdown-it renders what remark edits — two grammars; a display-parity question for R4c-3, where the read renderer, diff view and corpus must move together with any canon change). - The canon question is decided deliberately, not inherited. Crepe's GFM is full GFM (strikethrough, task lists); the read renderer (ADR-0045) speaks CommonMark+tables. The spike enumerates what Crepe can emit; then either (a) those features are fenced off, or (b) the canon is widened to the matching GFM subset ON BOTH SIDES (read renderer + fidelity corpus + diff view) in one slice. No state where the editor can produce what the record won't render. Decided 2026-07-09 (Nicolas: "Widen is also my preference"): (b) WIDEN — the canon gains strikethrough and task lists on both sides (read renderer + corpus + diff; slice R4c-3). Sharpened by the spike's finding that R4b's input rules already emit both while the renderer showed them literally. Footnotes remain OUTSIDE the canon: the UI cannot produce them and the R4c-3 slice must close the guard-vs-renderer gap for round-trippable-but- unrendered constructs (guard should refuse what the record won't render).
- Crepe's visual theme is accepted as-is initially (themed CSS vars where cheap); the app-wide visual rework Nicolas expects will restyle it later.
Consequences¶
- R4b's hand-rolled visual toolbar (incl. the live-feedback additions) becomes interim scaffolding: it keeps the current build usable and is the documented fallback, then is removed when Crepe lands.
- The fidelity harness gains a Crepe-pipeline variant; the corpus verdict is re-baselined against it (expected: same or better than 7/19 — divergences would be new facts for the report).
- A Vue 3 runtime ships inside the lazy milkdown chunk (never the initial bundle). Accepted trade: upstream-maintained chrome over runtime purity.
- Slices: R4c-1 spike (facts + verdict + GFM decision material), R4c-2 Crepe integration behind mode toggle + entry guard, R4c-3 canon alignment per the GFM decision.