docs/plans/2026-04-03-slate-v2-range-refs-proof-plan.md
Supporting plan. For current queue and roadmap truth, see master-roadmap.md.
Implement the first durable range-reference seam in slate-v2 so persistent
annotation anchors stop depending on ephemeral selection state.
The projection proof solved local overlay subscriptions. It did not solve durable anchors.
Without range refs or bookmarks:
slate-react-v2 remains good at ephemeral projection and bad at persistenceThe smallest honest first cut is probably:
Editor.rangeRef(editor, range)Range | nullunref() detaches it cleanlyBookmark serialization may be a later follow-up unless the first proof forces it.
Public API:
Editor.rangeRef(editor, range, options?)type RangeReftype RangeRefAffinity = 'forward' | 'backward' | 'outward' | 'inward' | nullSemantics:
inwardforwardunref() returns the latest logical range and detaches the refProof subset:
[block, 0]insert_textinsert_fragmentmove_nodeset_selection as a no-op for ref transformMap legacy behavior, current v2 seams, and issue pressure.
Write a narrow red test for one durable range-ref behavior.
Implement the smallest core seam that passes the test.
Expand to the next required operation families only if tests force it.
Verify, deslop, re-verify, architect review, cleanup.
Editor.rangeRef(editor, range, options?)RangeRefAffinityinward.tmp/slate-v2unref() detach semanticsunref() could read stale committed state when the draft ref value was already nullzsh -lc 'yarn mocha --require ./config/babel/register.cjs ./packages/slate-v2/test/range-ref-contract.ts'zsh -lc 'yarn mocha --require ./config/babel/register.cjs ./packages/slate-v2/test/snapshot-contract.ts'zsh -lc 'yarn mocha --require ./config/babel/register.cjs ./packages/slate-v2/test/clipboard-contract.ts'zsh -lc 'yarn workspace slate-react-v2 test'0 on changed filesreplaceSnapshot()APPROVE