docs/plans/2026-04-03-slate-v2-clipboard-boundary-proof-plan.md
Supporting plan. For current queue and roadmap truth, see master-roadmap.md.
Revise the clipboard-boundary proof so it reflects the real missing seam:
this is not just a DOM boundary proof. slate-v2 still needs minimal fragment
meaning and insertion-facing parse semantics before slate-dom-v2 can prove the
clipboard boundary honestly.
slate-v2: selected-fragment extraction plus one explicit fragment
insertion primitive and replacement semanticsslate-dom-v2: custom MIME key, DataTransfer, HTML scraping, plain-text
export, clipboard boundary helpersslate-v2; keep browser transport in
slate-dom-v2.slate-v2 currently lacks fragment extraction, fragment insertion-facing
semantics, delete-fragment semantics coverage, and any paste-target
primitive.slate-v2 for fragment meaning, slate-dom-v2 for clipboard transport.slate-v2 adds:
Editor.getFragment(editor)Transforms.insertFragment(editor, fragment, options?)slate-dom-v2 adds:
DataTransfer read/writeWhy chosen:
Why rejected:
Why deferred:
slate-v2 does not yet have explicit schema/editor identity, so claiming
real isolation now would be bullshit with types on itAdopt a two-package proof with a minimal core seam:
slate-v2 owns fragment extraction and one explicit fragment insertion
primitive consumed by insertion/replacement flows.slate-dom-v2 owns clipboard transport:
MIME keys, DataTransfer, HTML scraping, and plain-text export/fallback.slate-dom-v2.slate-v2 grows explicit
identity.The architect feedback is right: without core fragment extraction and insertion semantics, a DOM-only proof is fake. This split keeps core meaning in core and browser junk at the browser edge.
Descendant[] and ordinary text/block paste targets.slate-v2.slate-react-v2 work as thin delegation only.insert_node,
remove_node, or split_node, stop and re-plan.Before execution approval, prove one narrow implementation claim:
slate-v2
behind Transforms.insertFragment(...)
using private helpers only, without exporting generic low-level structural opsIf that checkpoint fails:
slate-v2:
Editor.getFragment(editor)Transforms.insertFragment(editor, fragment, options?)slate-dom-v2:
Acceptance:
Current clipboard ownership is smeared. Make the target disposition explicit before code moves:
| Current owner | Current role | Target disposition |
|---|---|---|
legacy slate editor transform surface | exposes DOM clipboard methods on editor | delete from the proof path; do not mirror into v2 |
ViewPlugin.setFragmentData | fragment MIME write plus HTML/plain-text export | move conceptually to slate-dom-v2 |
withSetFragmentDataTable | table-specific clipboard write override | audit as downstream compatibility pressure; no parity promise in this slice |
AstPlugin | fragment MIME decode/check | wrap temporarily while v2 DOM helpers take over |
ParserPlugin | DataTransfer -> deserialize -> insertFragment orchestration | replace with v2 seam and keep out of slate-react-v2 |
HtmlPlugin | current text/html parser owner | replace with DOM-owned HTML read/scrape seam in v2 |
pipeInsertDataQuery | parser eligibility / can-handle checks before insert | delete from proof path unless a specific v2 DOM helper proves it needs an eligibility hook |
pipeTransformData | payload mutation before deserialize/insert | delete from proof path in this slice |
pipeTransformFragment | transform stage before insertion | DOM-owned compatibility hook only if needed; no v2 parity promise in this slice |
pipeInsertFragment | final insert orchestration into insertFragment | replace with v2 seam and keep ownership out of slate-react-v2 |
| current React copy-event bridge | copy event glue that calls fragment-data writer | keep as thin delegation only in this slice; do not let it own semantics |
Also resolve one getFragment composition collision explicitly:
Editor.getFragment(editor) as the model-fragment meaninggetFragment to mean selected DOM fragmentgetFragment override consumers must be treated as composition pressure, not ignored:
Acceptance:
move, wrap temporarily, or deletegetFragment meaning and override/composition pressure are no longer ambiguous in the planAcceptance:
slate-v2 behind Transforms.insertFragment(...)Decision:
Acceptance:
insertFragment override consumers exists so the proof does not accidentally break hot downstream assumptions without noticing themslate-v2 minimal seamEditor.getFragment(editor).Transforms.insertFragment(editor, fragment, options?).insertFragment override consumers as compatibility pressure only:
Acceptance:
slate-v2.insertFragment possible.getFragment override/composition pressure is explicitly called out for:
slate-dom-v2 clipboard boundaryAcceptance:
Acceptance:
slate-v2 selected-fragment extraction contract.slate-v2 collapsed-selection insertFragment contract.slate-dom-v2 MIME read/write contract.slate-v2 owns Editor.getFragment(editor) and
Transforms.insertFragment(editor, fragment, options?).slate-dom-v2 owns MIME keys, DataTransfer, HTML scraping,
provenance/version envelope checks, and plain-text
export/fallback.Descendant[] shapes and ordinary text/block paste targets only.slate-v2 or
slate-dom-v2, never both.getFragment naming note remove brownfield ambiguity.Revised plan now treats clipboard-boundary proof as a two-package seam, not a
DOM-only proof. slate-v2 now gets one pinned narrow seam:
Editor.getFragment(editor) plus Transforms.insertFragment(editor, fragment, options?),
with both collapsed insertion and expanded replacement/delete-fragment semantics
covered. slate-dom-v2 keeps all transport concerns: MIME keys, DataTransfer,
HTML scraping, provenance/version envelope checks, and plain-text export/fallback.
Schema isolation is deferred; the plan now has a stop rule against drifting into
generic low-level node ops, plus a kill-test checkpoint to prove this can stay
a narrow seam instead of becoming a disguised general tree-edit rewrite.