docs/plans/2026-04-21-slate-v2-hard-cut-transaction-runtime-architecture-plan.md
Build the final Slate v2 runtime architecture:
slate coreslate-reactslate-browserThis plan replaces legacy runtime architecture, not just patches it.
The huge-doc perf work proved the direction. The richtext Cmd+Z regression proved the implementation is still transitional: model truth, DOM truth, and React repair are not yet governed by one explicit runtime contract.
slate-browser, not assumed from
synthetic React tests.These cuts are architecture cuts, not cosmetic cleanup.
Child-count chunking remains only in legacy comparison fixtures and benchmark baselines.
It must not define:
slate-react rendering structureReplacement owner:
decorate As The Primary Overlay Modeldecorate may survive only as a compatibility adapter.
The primary model is typed overlay sources:
Review/comment UI is not decoration. Widget UI is not text decoration.
Editor.getSnapshot() is an observer artifact.
It is allowed for:
It is forbidden for:
Direct DOM sync is a named capability, not a DOM-shape accident.
It must declare:
Unsafe rows fall back to React.
Activation and selection are separate concepts.
Legacy compatibility can live at public boundaries as adapters.
It cannot force:
slate-react subscription topologypackages/slateOwns:
Does not own:
packages/slate-domOwns:
Consumes:
Does not own:
packages/slate-browserOwns proof infrastructure.
It is not product API.
It must prove:
The stable ready contract should become the default for maintained example
and browser proof callsites.
packages/slate-reactOwns:
Consumes:
slate-dom browser mapping and event interpretationDoes not:
Transactions are the local unit of execution.
Every transaction:
Operations remain the serialized collaboration/history facts.
Target shape:
type OperationClass = "text" | "selection" | "mark" | "structural" | "replace";
type DirtyRegion = {
paths: Path[];
runtimeIds: RuntimeId[];
topLevelRange: [number, number] | null;
wholeDocument: boolean;
};
type EditorCommit = {
version: number;
previousVersion: number;
operations: readonly Operation[];
classes: ReadonlySet<OperationClass>;
dirty: DirtyRegion;
selectionChanged: boolean;
marksChanged: boolean;
textChanged: boolean;
structureChanged: boolean;
snapshotChanged: boolean;
};
Rules:
replace is explicit and broadCore must expose live reads that do not clone the tree:
Editor.getLiveNode(editor, path);
Editor.getLiveText(editor, path);
Editor.getLiveSelection(editor);
Editor.getRuntimeId(editor, path);
Editor.getPathByRuntimeId(editor, runtimeId);
Editor.getChangedOperations(editor, sinceVersion);
Editor.getLastCommit(editor);
Constraints:
Snapshots are still valuable.
But they must be maintained from commit metadata:
Selectors consume commit records.
They should declare or infer one of:
Defaulting every selector to whole-snapshot wakeup is a regression.
Islands are semantic/runtime units, not child-count chunks.
They are driven by:
Inactive islands may be occluded. Active islands must preserve editing semantics.
Allowed only when all are true:
renderTextrenderLeafrenderSegmentRequired repair events:
Any failed eligibility check falls back to React.
Primary overlay kernel:
decorate compatibility:
slate-browser is the proof spine.
Every browser-facing runtime claim needs one of:
Required browser proof families:
historyUndo / historyRedoNo model-only proof closes a browser editing lane.
No DOM-only proof closes a model lane.
Model and DOM assertions must both exist for risky editing paths.
Owners:
Actions:
decorate as compatibility adapterEditor.getSnapshot() use in slate-reactEarliest gates:
bun completion-check remains pendingOwner:
packages/slateActions:
EditorCommitEditor.getLastCommit(editor)Earliest gates:
bun test ./packages/slate/test/transaction-contract.ts --bail 1bun test ./packages/slate/test/snapshot-contract.ts --bail 1bun test ./packages/slate/test/surface-contract.ts --bail 1bun run bench:core:observation:compare:localOwner:
packages/slateActions:
getPathByRuntimeId O(1) or close enough under edit pressureEarliest gates:
bun run bench:core:huge-document:compare:localbun run bench:core:observation:compare:localslate-dom Browser Repair ContractOwner:
packages/slate-dompackages/slate-react only where React owns visible repairActions:
Earliest gates:
bun test ./packages/slate-dom/test/bridge.ts --bail 1bun test ./packages/slate-dom/test/clipboard-boundary.ts --bail 1slate-browser Proof Harness UpgradeOwner:
packages/slate-browserActions:
openExample(...) ready contract where
usefulEarliest gates:
bun --filter slate-browser testbun run test:slate-browserslate-browser/playwrightslate-react Consumes Commit DirtinessOwner:
packages/slate-reactActions:
Editor.getSnapshot() readsEarliest gates:
bun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1bun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1bun run bench:react:rerender-breadth:localREACT_HUGE_COMPARE_BLOCKS=5000 REACT_HUGE_COMPARE_ITERATIONS=5 REACT_HUGE_COMPARE_TYPE_OPS=10 bun run bench:react:huge-document:legacy-compare:localOwner:
packages/slate-reactpackages/slate-dom if event interpretation is the blockerActions:
Earliest gates:
decorateOwner:
packages/slate-reactActions:
decorate into adapterEarliest gates:
Owner:
packages/slate-reactActions:
Earliest gates:
Owner:
packages/slate-reactpackages/slate-dom if DOM selection bridge changesslate-browser proof rowsActions:
Earliest gates:
Owner:
packages/slatepackages/slate-reactActions:
Earliest gates:
Start at Phase 0, then immediately Phase 1.
The first implementation owner is packages/slate commit records and dirty
regions.
Do not start by deleting React code. That would remove evidence before the core runtime contract exists.
Default fast gates:
bun test ./packages/slate/test/transaction-contract.ts --bail 1bun test ./packages/slate/test/snapshot-contract.ts --bail 1bun test ./packages/slate/test/surface-contract.ts --bail 1bun run bench:core:observation:compare:localReact/browser gates after core commits are live:
bun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1bun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1bunx playwright test ./playwright/integration/examples/richtext.test.ts --project=chromiumbunx playwright test ./playwright/integration/examples/large-document-runtime.test.ts --project=chromiumREACT_HUGE_COMPARE_BLOCKS=5000 REACT_HUGE_COMPARE_ITERATIONS=5 REACT_HUGE_COMPARE_TYPE_OPS=10 bun run bench:react:huge-document:legacy-compare:localslate-browser gates:
bun --filter slate-browser testbun run test:slate-browserThis lane is complete only when all are true:
decorate is not the primary overlay pathslate-react path depends on Editor.getSnapshot()slate-browser owns the browser proof spineDo not stop on:
Stop only when:
After every slice, append to this file:
Do not rely on chat history.
Editor.apply(...) already exists as the explicit public single-op
writer and should stay aligned with transactions.packages/slate-react/src/large-document/island-shell.tsxpackages/slate-react/src/hooks/use-slate-node-ref.tsxpackages/slate-react/src/components/editable-text.tsxpackages/slate-react/src/components/editable-text-blocks.tsxpackages/slate-react/src/components/editable.tsxpackages/slate-react/src/widget-store.tspackages/slate-react/src/projection-store.tspackages/slate-react/src/chunking/**packages/slate-react/src/components/chunk-tree.tsxpackages/slate-react/src/hooks/use-children.tsxpackages/slate-react/src/plugin/with-react.tspackages/slate-react/src/plugin/react-editor.tssite/examples/ts/huge-document.tsxpackages/slate-react/src/large-document/**packages/slate-react/src/components/editable-text-blocks.tsxsite/examples/ts/large-document-runtime.tsxpackages/slate-react/src/hooks/use-slate-node-ref.tsxpackages/slate-react/src/components/slate.tsxpackages/slate-react/src/components/editable-text.tsxdata-slate-dom-sync, single
[data-slate-string], no composition, and component-level custom
render/projection/placeholder checks.packages/slate-react/src/components/editable.tsxhistoryUndo / historyRedo, select-all, and shell-backed paste.SnapshotChange exists and carries classes, dirty paths, touched runtime
ids, and selection/mark/children flags.EditorCommit.Editor.getLastCommit(editor).(snapshot, change).getPathByRuntimeId is still recursive, not indexed.packages/slate.EditorCommit and Editor.getLastCommit
while preserving existing SnapshotChange subscriber compatibility.bun test ./packages/slate/test/surface-contract.ts --bail 1bun test ./packages/slate/test/transaction-contract.ts --bail 1bun test ./packages/slate/test/snapshot-contract.ts --bail 1SnapshotChange, but the missing
durable owner was a first-class commit record available without
subscribers.EditorCommit, DirtyRegion, and OperationClass typesSnapshotChange an alias of the richer EditorCommitEditor.getLastCommit(editor)notifyListeners even when there are
no subscribersgetLastCommitslate patch changeset.tmp/slate-v2/packages/slate/src/interfaces/editor.ts.tmp/slate-v2/packages/slate/src/core/public-state.ts.tmp/slate-v2/packages/slate/src/core/apply.ts.tmp/slate-v2/packages/slate/src/create-editor.ts.tmp/slate-v2/packages/slate/test/transaction-contract.ts.tmp/slate-v2/packages/slate/test/surface-contract.ts.tmp/slate-v2/.changeset/slate-commit-metadata.mddocs/research/decisions/slate-v2-data-model-first-react-perfect-runtime.mdbun test ./packages/slate/test/transaction-contract.ts --bail 1
passed, 13 testsbun test ./packages/slate/test/surface-contract.ts --bail 1
passed, 9 testsbun test ./packages/slate/test/snapshot-contract.ts --bail 1
passed, 190 testsbun run bench:core:observation:compare:local passed; current remains
bounded slower than legacy on observation lanesbun run bench:core:huge-document:compare:local passed; current remains
slower on typing and faster on replace/fragment lanesbunx turbo build --filter=./packages/slate --force passedbunx turbo typecheck --filter=./packages/slate --force passedbun run lint:fix passedbun run lint passed+2.91ms+2.03ms+2.74ms+3.57ms+3.37ms-5.19ms-5.59ms0mspackages/slate so
Editor.getPathByRuntimeId is not recursive and commit dirty regions can
publish runtime ids cheaply.EditorCommit and Editor.getLastCommit are green.getPathByRuntimeId is recursive.bun test ./packages/slate/test/surface-contract.ts --bail 1bun test ./packages/slate/test/transaction-contract.ts --bail 1bun test ./packages/slate/test/snapshot-contract.ts --bail 1bun run bench:core:observation:compare:localpackages/slate.packages/slateEditor.getPathByRuntimeId through the live index15ms15msinsert_node, remove_node, move_node, merge_node, split_node..tmp/slate-v2/packages/slate/src/core/public-state.ts.tmp/slate-v2/packages/slate/src/interfaces/editor.ts.tmp/slate-v2/packages/slate/test/surface-contract.tsbun test ./packages/slate/test/surface-contract.ts --bail 1
passed, 10 testsbun test ./packages/slate/test/transaction-contract.ts --bail 1
passed, 13 testsbun test ./packages/slate/test/snapshot-contract.ts --bail 1
passed, 190 testsbun run bench:core:observation:compare:local passed after repair:
4.81ms, legacy 1.92ms12.76ms, legacy 10.84ms4.43ms, legacy 2.28msbun run bench:core:huge-document:compare:local passed after repair:
4.20ms, legacy 0.71ms4.36ms, legacy 0.54ms3.50ms, legacy 9.13ms3.43ms, legacy 8.75msbun run lint:fix passedbun run lint passedbunx turbo build --filter=./packages/slate --force passedbunx turbo typecheck --filter=./packages/slate --force passedEditor.getSnapshot() rebuild cost and decide whether the next
owner is incremental snapshot/index maintenance or moving React away from
snapshot-hot reads now that commit metadata and live runtime indexes
exist.slate-react runtime-id snapshot-hot reads.
Editor.getSnapshot().index.useSlateNodeRef runtime-id path lookup with
Editor.getPathByRuntimeIdEditableText bound text lookup with Editor.getRuntimeId,
Editor.getPathByRuntimeId, and Editor.getLiveTextEditableTextBlocks node binding and top-level runtime id
derivation with live readsLargeDocumentIslandShell preview lookup with live path/node
readsslate-react patch changesetslate-react Editor.getSnapshot() reads:
editable.tsx selection reads: explicit selection path, not runtime-id
lookupbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passed, 14 testsbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passed, 4 testsbunx playwright test ./playwright/integration/examples/large-document-runtime.test.ts --project=chromium -g "DOM-owned|custom|projection|IME|undo|redo|delete"
passed, 14 testsbun run bench:react:rerender-breadth:local passed locality guardrailsbunx turbo build --filter=./packages/slate --filter=./packages/slate-dom --filter=./packages/slate-react --force
passedbun run lint passedmiddleBlockPromoteThenTypeMs: v2 52.40ms vs chunking-on 37.99msselectAllMs: v2 4.00ms vs chunking-on 0.73ms, with clear
outliersbunx turbo typecheck --filter=./packages/slate --filter=./packages/slate-dom --filter=./packages/slate-react --force
is blocked by the known slate-dom generated declaration alias issue
where slate-dom cannot resolve module slate.middleBlockPromoteThenTypeMs red row after
live runtime reads, then decide whether the owner is shell preview live
lookup, shell activation/render, select-all shell-backed state, or
benchmark noise.activeRadius=0, 5000 blocks, 3
iterations, 10 type ops.slate, slate-dom, and slate-react.3 iterations.2.72msmiddlePromoteThenType total act mean 51.97ms12.44ms, chunk-on 348.42ms22.74ms, chunk-on 42.87ms19.59ms, chunk-on 44.59ms23.97ms, chunk-on 63.23ms29.21ms, chunk-on 50.15ms52.40ms, chunk-on 37.99ms4.00ms, chunk-on 0.73msbunx playwright test ./playwright/integration/examples/large-document-runtime.test.ts --project=chromium -g "DOM-owned|custom|projection|IME|undo|redo|delete"
passed, 14 tests.REACT_ACTIVE_TYPING_BREAKDOWN_CUSTOM_RENDERERS=0 support to
scripts/benchmarks/browser/react/active-typing-breakdown.tsx.activeRadius=0, 5000
blocks, 3 iterations, and 10 type ops.middlePromoteThenType default-renderer breakdown:
2.06ms11.69ms11.68ms00startActiveTyping default-renderer breakdown:
11.03ms11.03ms0middleShelledModelOnly default-renderer breakdown:
13.73ms13.69ms0bun run lint:fix passedbun run lint passedmiddleBlockPromoteThenTypeMs red is not
shell promotion or React render in the default-renderer path.huge-document-legacy-compare.mjs promotion/type lane against
active-typing-breakdown.tsx and either align the harness or document
the accepted first-activation tradeoff with stable evidence.middleBlockPromoteThenTypeMs,
middleBlockSelectThenTypeMs, and selectAllMs rows even though focused
source and built-package probes showed the product path was cheap and had
zero React commits.huge-document-legacy-compare.mjs to prefer React.act and
fall back to react-dom/test-utils.act for legacy React compatibility.active-typing-breakdown.tsx with:
15.13ms, profiler commits 023.06ms, profiler commits 019.74ms, profiler commits 110.57ms, profiler commits 011.42ms, profiler commits 05.39ms, profiler commits 0; this confirmed
select-all noise is not React rendering15.96ms, chunk-off 308.41ms, chunk-on 326.27ms0.13ms, chunk-off 14.85ms, chunk-on 0.83ms16.39ms, chunk-off 165.14ms, chunk-on 36.96ms24.26ms, chunk-off 192.93ms, chunk-on 47.80ms18.06ms, chunk-off 206.80ms, chunk-on 35.76ms21.53ms, chunk-off 187.65ms, chunk-on 36.75ms21.04ms, chunk-off 180.08ms, chunk-on 34.41ms23.45ms, chunk-off 122.52ms, chunk-on 122.43ms28.92ms, chunk-off 120.89ms, chunk-on 111.76msbun run lint:fix passedbun run lint passedbun test ./packages/slate/test/surface-contract.ts --bail 1 passedbun test ./packages/slate/test/transaction-contract.ts --bail 1 passedbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passeddata-slate-dom-sync, which makes opt-out ownership too implicit.getDOMTextSyncCapability(...) with named opt-out reasons:
empty-text, projection, custom-leaf, custom-segment,
custom-textdata-slate-dom-sync="true" surface for enabled
plain textdata-slate-dom-sync-reason for disabled default text paths and
for app-owned renderText when the app forwards attributesslate-react patch changesetbun test ./packages/slate-react/test/dom-text-sync-contract.ts --bail 1
passed, 1 testbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passed, 14 testsbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passed, 4 testsbunx playwright test ./playwright/integration/examples/large-document-runtime.test.ts --project=chromium -g "DOM-owned|IME|undo|redo|delete"
passed, 14 tests13.62ms, chunk-off 254.11ms, chunk-on 289.53ms0.13ms, chunk-off 16.13ms, chunk-on 0.81ms18.90ms, chunk-off 159.06ms, chunk-on 36.53ms20.67ms, chunk-off 169.53ms, chunk-on 34.96ms16.01ms, chunk-off 162.83ms, chunk-on 31.42ms24.99ms, chunk-off 175.43ms, chunk-on 31.07ms23.50ms, chunk-off 175.87ms, chunk-on 32.93ms26.17ms, chunk-off 107.69ms, chunk-on 115.98ms32.89ms, chunk-off 110.62ms, chunk-on 109.09msbun run lint:fix passedbun run lint passedbunx turbo build --filter=./packages/slate-react --force passedbunx turbo typecheck --filter=./packages/slate-react --force is still
blocked by the known generated slate-dom/dist/index.d.ts aliasing
issue:
SlateBaseEditorSlateEditorSlateAncestordecorate as primary overlay architecture with typed
overlay sources while keeping decorate only as a compatibility adapter.Editable internals, the safe first cut is to expose an
explicit adapter from legacy decorate(entry) callbacks to typed
projection sources.createSlateDecorationSource(decorate)SlateDecorate and SlateDecorationData exportsdataslate-react patch changeset.tmp/slate-v2/packages/slate-react/src/projection-store.ts.tmp/slate-v2/packages/slate-react/src/index.ts.tmp/slate-v2/packages/slate-react/test/projections-and-selection-contract.tsx.tmp/slate-v2/.changeset/slate-react-decoration-source-adapter.mdbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passed, 5 testsbun test ./packages/slate-react/test/dom-text-sync-contract.ts --bail 1
passedbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passedbun run lint:fix passedbun run lint passedbunx turbo build --filter=./packages/slate-react --force passeddecorate is not demoted internally yet, but a typed compatibility
adapter now exists over the projection kernel.createSlateDecorationSource, then decide whether Editable.decorate
can be implemented as an adapter over projection source without
regressing legacy decoration tests.search-highlighting through decoration-source adapter.
decorate(entry) callbacks can migrate
to createSlateDecorationSource plus EditableBlocks without changing
user-facing behavior.site/examples/ts/search-highlighting.tsx from
<Slate><Editable decorate={...}/></Slate> to EditableBlocks with a
createSlateDecorationSource(decorate) projection storerenderSegmentrenderLeaf.tmp/slate-v2/site/examples/ts/search-highlighting.tsxbunx playwright test ./playwright/integration/examples/search-highlighting.test.ts --project=chromium
passedbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passedbun run bench:react:rerender-breadth:local passed locality guardrailsbun run lint:fix passedbun run lint passedEditable.decorate internals yet; first migrate another
concrete decoration example so the adapter proves itself across more
than simple search highlighting.markdown-preview through createSlateDecorationSource, because
it is text-node decoration-only and lower risk than code highlighting.markdown-preview through decoration-source adapter.
Editable.decorate to
createSlateDecorationSource plus projection segment rendering without
user-visible behavior loss.site/examples/ts/markdown-preview.tsx to initialize the
editor directly and render with EditableBlocksdecorate(entry) callback as the compatibility
input to createSlateDecorationSourcerenderSegmentEditableBlocks surface.tmp/slate-v2/site/examples/ts/markdown-preview.tsxbunx playwright test ./playwright/integration/examples/markdown-preview.test.ts --project=chromium
passedbunx playwright test ./playwright/integration/examples/search-highlighting.test.ts --project=chromium
passedbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passedbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passedbun run bench:react:rerender-breadth:local passedbun run lint:fix passedbun run lint passedbunx turbo build --filter=./packages/slate-react --force passeddecorate now has two concrete adapter-backed example paths:
search-highlighting and markdown-preview.Editable.decorate internals until the block-level
code-highlighting case proves the adapter can handle ancestor-owned
ranges too.code-highlighting through createSlateDecorationSource; this is
the harder block-level decoration case.code-highlighting through decoration-source adapter.
site/examples/ts/code-highlighting.tsx from
Editable.decorate to createSlateDecorationSource plus EditableBlocksSlate as the outer provider because the toolbar uses
useSlateStaticSlaterenderSegment.tmp/slate-v2/site/examples/ts/code-highlighting.tsxbunx playwright test ./playwright/integration/examples/code-highlighting.test.ts --project=chromium
passed, 3 testsbunx playwright test ./playwright/integration/examples/markdown-preview.test.ts --project=chromium
passedbunx playwright test ./playwright/integration/examples/search-highlighting.test.ts --project=chromium
passedbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passed, 5 testsbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passed, 14 testsbun run bench:react:rerender-breadth:local passedbun run lint:fix passedbun run lint passedbunx turbo build --filter=./packages/slate-react --force passedEditable.decorate
itself can become adapter-backed without regressing legacy decoration
tests.Editable.decorate, useDecorations, useChildren, and
legacy decoration tests to decide whether the compatibility prop can be
implemented over projection sources now, or whether it needs a staged
adapter with tests first.Editable.decorate projection-adapter-backed.
Editable.decorate was still the primary internal decoration path even
after examples proved createSlateDecorationSource could handle text and
block-owned ranges.decorate(entry) callbacks expect live node identity. A naive
projection adapter over immutable snapshot nodes breaks callbacks that
assert Node.get(editor, path) === node.createSlateDecorationSource(decorate, { editor }) so the
adapter can traverse live editor nodes and include root/editor-owned
decorationsuseDecorateContext to route explicit custom decorate props
through an internal createSlateProjectionStoreDecoratedRange objects for the
legacy Element / Text render treedecorate on the cheap direct path so huge-doc
runtime does not create a projection store when no custom decorate prop
existsslate-react patch changesetdecorate
regressed 5000-block typing badly because every text op traversed the
document. The fixed path only enables the adapter for an explicit custom
decorate prop.bunx vitest run --config ./vitest.config.mjs test/decorations.test.tsx
passed, 20 tests across chunking and non-chunking decoration behaviorbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passed, 6 testsbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passed, 14 testsbunx playwright test ./playwright/integration/examples/search-highlighting.test.ts --project=chromium
passedbunx playwright test ./playwright/integration/examples/markdown-preview.test.ts --project=chromium
passedbunx playwright test ./playwright/integration/examples/code-highlighting.test.ts --project=chromium
passed, 3 testsbun run bench:react:rerender-breadth:local passedbun run bench:react:huge-document-overlays:local passedbun run lint:fix passedbun run lint passedbunx turbo build --filter=./packages/slate-react --force passeddecorate is now compatibility adapter-owned internally and in concrete
examples; projection sources are the primary overlay architecture.slate-react runtime.
editor.getChunkSize, renderChunk, ChunkTree, and src/chunking/**.
That kept old runtime architecture alive inside v2.getChunkSize from ReactEditoruseChildrenrenderChunk / RenderChunkProps from Editable package
surfacewithReactsrc/chunking/** and components/chunk-tree.tsxhuge-document example so it no longer teaches or
depends on child-count chunkinghuge-document Playwright row to assert zero
[data-slate-chunk] nodesslate-react patch changesetscripts/benchmarks/browser/react/huge-document-legacy-compare.mjs
remain because they execute against ../slate, not current
slate-react product runtime.getChunkSize,
renderChunk, ChunkTree, getChunkTreeForNode, or data-slate-chunk
under packages/slate-react/src, packages/slate-react/test, or
site/examples/ts/huge-document.tsxbunx vitest run --config ./vitest.config.mjs test/decorations.test.tsx test/use-selected.test.tsx
passed, 14 testsbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passedbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passedbunx playwright test ./playwright/integration/examples/huge-document.test.ts --project=chromium
passed; same-path example renders without child-count chunksbun run lint:fix passedbun run lint passedbunx turbo build --filter=./packages/slate-react --force passedbunx turbo typecheck --filter=./packages/slate-react --force remains
blocked by the known generated slate-dom/dist/index.d.ts alias issue:
missing SlateBaseEditor, SlateEditor, and SlateAncestor11.63ms, chunk-off 259.85ms, chunk-on 288.13ms2.20ms, chunk-on 0.85ms; median v2
0.14ms remains better and focused select-all proof shows no React
commits15.15ms, chunk-on 35.43ms20.52ms, chunk-on 36.84ms18.68ms, chunk-on 33.98ms16.74ms, chunk-on 36.40ms39.73ms, chunk-on
34.88ms; median v2 37.75ms vs chunk-on 34.47msaria-expanded="false" to inactive large-document shell buttonsbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passed, 15 testsbunx playwright test ./playwright/integration/examples/large-document-runtime.test.ts --project=chromium -g "activates shells by keyboard"
passedbun run lint:fix passedbun run lint passedbunx turbo build --filter=./packages/slate-react --force passedslate-dom declaration alias blocker by removing
bundled-declaration-hostile type aliases in source:
SlateBaseEditorSlateEditorSlateAncestorslate-dom and slate-react typecheck togetherEditor.getSnapshot() remains observer/devtools/test/non-urgent
surfaceEditable.decorate remains public compatibility, but internally routes
through the projection-source adapter../slate comparison fixture
generated by huge-document-legacy-compare.mjsbun test ./packages/slate-dom/test/bridge.ts --bail 1 passedbun test ./packages/slate-dom/test/clipboard-boundary.ts --bail 1
passedbunx turbo build --filter=./packages/slate-dom --filter=./packages/slate-react --force
passedbunx turbo typecheck --filter=./packages/slate-dom --filter=./packages/slate-react --force
passedbun run lint:fix passedselectAllMs and first activation samples still show
occasional noisy outliers, but focused probes show no React commits for
select-all and promotion itself is cheap. The lane is accepted under the
existing first-activation/noisy-harness tradeoff unless product requires
every mean row to beat chunking-on.getChunkSize, renderChunk, RenderChunkProps, ChunkTree,
src/chunking/**, and chunking-specific package tests from current
slate-reacthuge-document examplehuge-document.test.ts to assert no [data-slate-chunk] nodesbunx vitest run --config ./vitest.config.mjs test/decorations.test.tsx test/use-selected.test.tsx
passedbun test ./packages/slate-react/test/projections-and-selection-contract.tsx --bail 1
passedbun test ./packages/slate-react/test/large-doc-and-scroll.tsx --bail 1
passedbunx playwright test ./playwright/integration/examples/huge-document.test.ts --project=chromium
passedbunx turbo build --filter=./packages/slate-react --force passedbun run lint passedhuge-document remains as a huge-document stress example, not
a child-count chunking example.