docs/research/decisions/slate-v2-architecture-verdict-after-human-stress-sweep.md
Does Slate v2 currently have the absolute best architecture for React 19.2 runtime performance, hard-cut DX, Plate/Yjs migration, regression freedom, and battle-tested editing?
No, not yet.
The architecture direction is the right one:
editor.read / editor.update are the public lifecycle.state / tx methods are the normal public read/write API.EditorCommit is the local runtime fact for history, collaboration, React,
DOM repair, and proof.state / tx namespaces and editor.extend.That is the right "starting from scratch, pulled toward Slate" answer. It correctly steals from Lexical, ProseMirror, and Tiptap while rejecting their model choices that would punish Plate and Yjs migration.
But it is still not honest to call the current state absolute, regression-free, or battle-tested. The item 4/5/6 hard-cut lane closes a serious gap: raw public write/read escape hatches are cut or fenced, compatibility aliases are guarded by release discipline, and generated browser contracts cover the reported operation families. That moves the project from "humans are the regression detector" toward a real proof spine.
It does not finish the broader architecture. The 2026-04-28 root runtime cut closed the main root-component policy ownership smell, but runtime-owned public void shells, legacy browser parity, Plate/Yjs migration proof, and real-device soak still decide whether this becomes field-best instead of merely field-serious.
The item 4/5/6 hard-cut lane is complete:
Editor.apply(editor, op), instance editor.apply(op),
setChildren, public Editor.getLive*, public <Slate onChange>,
SlateReactCompat, decorate compat adapter, and useEditor are no longer
normal public surfacesapplyOperations(...)slate-browser contracts cover inline void navigation, block void
navigation, table boundary navigation, decoration refresh, mouse-selection
toolbar, paste/normalize/undo, and IME repairbun check:full passed with release discipline, proof contracts, mobile
guard, persistent-profile soak, and 628 Playwright rows passing with 4
skipped replay-placeholder rowsThat is a real upgrade over the 2026-04-26 verdict.
The selector/live-read runtime hard-cut lane is also complete:
useNodeSelector and useTextSelector are model-truth-onlyslate/internal live reads in slate-react/src are limited to the
runtime facade modulesslate/internal importsbun check:full passes, with one Chromium richtext word-delete retry
recorded as residual flake risk and the exact row passing alone with retries
disabledThe remaining hard truth: this still does not prove absolute best architecture. It proves the current direction deserves continued investment and that the proof system is becoming serious.
The root runtime selector guard lane is complete:
EditableDOMRoot delegates root policy orchestration to
useEditableRootRuntime(...)useEditableEventRuntime(...)root-selector-sources.tsreact-runtime:stale
count after one stale core-field reference disappearedbun check:full passed with 628 browser tests passing and 4 replay-artifact
rows skippedThat removes the prior top React-component smell. The strongest remaining architecture gap is now public DX and proof breadth:
VoidElement and
InlineVoidElementchildrenrenderVoid / runtime-owned shell contract../slate examples is not yet a generated
operation-family harnessThe second hard gap is legacy browser parity. Core and benchmark lanes already
use legacy fixtures and ../slate comparisons, but the browser proof spine is
not yet a generated current-vs-legacy example parity harness. Until the same
operation-family scenarios can run against legacy Slate examples and v2
examples, "tested against legacy" is only partly true.
Stronger after the selector/live-read cut, but still not proven absolute.
The current architecture has the right runtime facts: live reads, commit dirtiness, dirty runtime ids, dirty top-level ranges, projection-source invalidation, semantic islands, direct DOM text sync with fallback, and public selector truth separated from internal mounted render skips.
The hard-cut lane adds a stronger public/runtime boundary, and generated browser contracts reduce the chance that render fixes silently break editing. The honest limit remains: React 19.2 makes Slate v2 competitive with serious engines on React integration. It does not automatically beat ProseMirror's document-view diff, Lexical's dirty-node reconciler, or VS Code's view-model split.
The next React performance cut should remove broad hot-path React subscriptions
and direct Editable policy ownership where narrower runtime/source selectors
can own the same fact.
The target DX is strong.
Keeping Slate's JSON-like model plus operation stream is the correct migration
magnet for Plate and Yjs. The hard cut away from public mutable fields,
primary Transforms.* usage, and flat public editor writes is also correct.
Public selectors staying model-truth-only is the right app DX. Extension
namespaces on state and tx are cleaner than method monkeypatching, and less
ceremonial than making Tiptap-style focus().chain().run() the default mental
model.
The weak point is not the public idea. It is migration proof. Plate and Yjs need real adapter lanes and contract tests, not confidence from core tests alone.
Better, but still not absolute.
The latest generated browser contracts close the exact class of problem exposed by the human-like paste testing: model state, DOM state, selection, focus, commit metadata, replay artifacts, and operation family coverage all matter.
That is the correct proof direction. It still needs wider operation-family coverage, Plate/Yjs migration rows, longer persistent-profile soak, and real device lanes before "regression-free" is an honest phrase.
It also needs browser parity against legacy Slate, not only core oracle rows
and performance comparisons against ../slate. The current browser stress
suite is v2-centered. That is useful, but it cannot prove that v2 preserved
legacy editing behavior across examples.
test:stress being a separate command is correct. The mistake would be
pretending that a sparse stress corpus plus bun check:full means humans will
stop finding bugs. The right bar is generated, replayable, shrinking-capable
browser contracts by operation family, called sparingly but treated as release
law.
No.
Current status is "architecture-serious with strong focused proof", not "battle-tested".
Battle-tested requires weeks of green adversarial runs across:
If the goal is absolute best, stop treating individual user reports as the test suite.
The architecture is good enough to bet on harder. It is not good enough to declare victory. The next architecture work should stay focused on runtime ownership and proof architecture:
Editable wires
runtime modules instead of owning policy. This is largely closed for the
root component after the 2026-04-28 root runtime cut; keep the guards tight.editor.applyOperations, but keep
ordinary app writes inside editor.update.Do not pivot to Lexical, ProseMirror, or Tiptap.
Do pivot harder into the current Slate v2 architecture and make the proof system brutal enough that humans stop being the regression detector.