docs/plans/2026-04-24-slate-v2-post-closure-proof-hardening-plan.md
Do not pivot architecture.
The right architecture remains:
Slate model + operations
Lexical-style editor.read / editor.update lifecycle
ProseMirror-style transaction and DOM-selection authority
Tiptap-style extension DX
React 19.2 live-read / dirty-commit runtime
EditableConformanceKernel
Generated browser gauntlets
The next lane is proof hardening and escape-hatch burn-down.
The closed absolute-architecture plan proves a strong scoped claim. It does not prove the runtime is impossible to regress under unknown real-browser behavior. This plan upgrades the system from "closed under current gates" to "hard to break without a gate screaming."
The remaining risk is not the engine choice. The remaining risk is that old escape hatches still exist and some proof lanes are too harness-shaped:
editor.update still auto-transactionTransforms.* still exists in internal/runtime/history/test lanesThis plan hardens those owners without reviving child-count chunking, exposing
tx.resolveTarget(), adding command policy objects, or pivoting to another
editor model.
Allowed docs/memory work:
docs/plans/**docs/research/**docs/slate-v2/**active goal state only when this plan becomes active executionAllowed code work:
.tmp/slate-v2/packages/slate/**.tmp/slate-v2/packages/slate-history/**.tmp/slate-v2/packages/slate-dom/**.tmp/slate-v2/packages/slate-react/**.tmp/slate-v2/packages/slate-browser/**.tmp/slate-v2/playwright/integration/examples/**.tmp/slate-v2/site/** only for examples/proof surfaces.tmp/slate-v2/package.json and test scripts only when a focused gate needs itDo not work on:
.tmp/slate-v2/packages/slate-hyperscript/** unless a public API gate proves it
is in scopeThis plan is complete when:
Transforms.*, public mirror, editor.apply, editor.onChange, direct
primitive, repair bridge, and selection bridge usages are either removed or
covered by a named allowlist with owner, rationale, and gateTransforms.*docs/slate-v2/absolute-architecture-release-claim.mdThis plan is currently planned, not active execution.
When execution starts:
status: activeactive goal state to status: pendingbun completion-check only after this plan is done or blockedGoal: create the ground-truth inventory before cutting or hardening anything.
Work:
.tmp/slate-v2:
Transforms.*editor.selectioneditor.childreneditor.markseditor.operationseditor.applyeditor.onChangeeditor.updatePrimary files:
.tmp/slate-v2/packages/slate/test/public-surface-contract.ts.tmp/slate-v2/packages/slate/test/public-field-hard-cut-contract.ts.tmp/slate-v2/packages/slate-react/test/kernel-authority-audit-contract.tsDriver gates:
rg -n "editor\\.(selection|children|marks|operations)|Transforms\\.|editor\\.apply|editor\\.onChange" packages site playwright docs --glob '!**/dist/**' --glob '!**/node_modules/**' --glob '!site/out/**' --glob '!site/.next/**'
bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/public-field-hard-cut-contract.ts --bail 1
bun test ./packages/slate-react/test/kernel-authority-audit-contract.ts --bail 1
Acceptance:
Goal: reduce compatibility pressure without breaking the architecture.
Work:
Transforms.* and public mirror usage.Transforms.* call sites to editor primitive methods
where the method runtime is already safe.editor.update should:
editor.getSelection(), editor.getChildren(),
editor.getMarks(), and editor.getOperations()editor.apply / editor.onChange as extension points.Primary files:
.tmp/slate-v2/packages/slate/src/**.tmp/slate-v2/packages/slate-history/src/**.tmp/slate-v2/site/examples/**.tmp/slate-v2/docs/** if present.tmp/slate-v2/packages/slate/test/**Acceptance:
editor.update has one explicit final
policyGoal: make illegal architecture transitions fail loudly in development/test.
Work:
editor.update inside editor.readPrimary files:
.tmp/slate-v2/packages/slate/src/**.tmp/slate-v2/packages/slate-react/src/editable/editing-kernel.ts.tmp/slate-v2/packages/slate-react/src/editable/input-state.ts.tmp/slate-v2/packages/slate-react/test/editing-kernel-contract.ts.tmp/slate-v2/packages/slate-react/test/kernel-authority-audit-contract.tsAcceptance:
Goal: turn "audited bridges" into the smallest possible bridge surface.
Work:
Primary files:
.tmp/slate-v2/packages/slate-react/src/components/editable.tsx.tmp/slate-v2/packages/slate-react/src/editable/editing-kernel.ts.tmp/slate-v2/packages/slate-react/src/editable/selection-controller.ts.tmp/slate-v2/packages/slate-react/src/editable/selection-reconciler.ts.tmp/slate-v2/packages/slate-react/src/editable/mutation-controller.ts.tmp/slate-v2/packages/slate-react/src/editable/dom-repair-queue.ts.tmp/slate-v2/packages/slate-react/src/editable/*-strategy.tsAcceptance:
EditableConformanceKernel for final authorityGoal: stop relying on one-off rows for cursor/caret confidence.
Work:
Primary files:
.tmp/slate-v2/packages/slate-browser/src/**.tmp/slate-v2/packages/slate-browser/test/core/**.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.tmp/slate-v2/playwright/integration/examples/large-document-runtime.test.ts.tmp/slate-v2/playwright/integration/examples/inlines.test.ts.tmp/slate-v2/playwright/integration/examples/paste-html.test.tsAcceptance:
Goal: catch the class of bugs where Playwright is green but the user's browser is broken.
Work:
Primary files:
.tmp/slate-v2/packages/slate-browser/src/**.tmp/slate-v2/playwright/integration/examples/richtext.test.tsAcceptance:
Goal: stop overclaiming mobile.
Work:
Primary files:
.tmp/slate-v2/packages/slate-browser/src/transports/**.tmp/slate-v2/packages/slate-browser/test/core/proof.test.ts.tmp/slate-v2/playwright/integration/examples/**.tmp/slate-v2 if presentAcceptance:
Goal: prove the DX with realistic extension pressure, not toy examples.
Work:
editor.updateeditor.extend({ methods })Transforms.* in extension-facing code.Primary files:
.tmp/slate-v2/site/examples/**.tmp/slate-v2/packages/slate/test/extension-methods-contract.ts.tmp/slate-v2/packages/slate/test/extension-contract.ts.tmp/slate-v2/playwright/integration/examples/**Acceptance:
tx.resolveTarget(), command policies, or
React-specific command wrappersGoal: separate real product failures from harness noise without hiding either.
Work:
Driver gates:
bun test:integration-local
bun run bench:react:rerender-breadth:local
REACT_HUGE_COMPARE_BLOCKS=5000 REACT_HUGE_COMPARE_ITERATIONS=5 REACT_HUGE_COMPARE_TYPE_OPS=10 bun run bench:react:huge-document:legacy-compare:local
bun run bench:core:observation:compare:local
bun run bench:core:huge-document:compare:local
Acceptance:
Goal: make the public claim match the hardened system exactly.
Work:
docs/slate-v2/absolute-architecture-release-claim.mddocs/slate-v2/release-readiness-decision.mddocs/slate-v2/replacement-gates-scoreboard.mddocs/slate-v2/true-slate-rc-proof-ledger.mddocs/research/decisions/slate-v2-post-closure-architecture-review.mdAcceptance:
active goal state is done or blocked when the active execution
lane closesRun the relevant subset by touched area, then final gates before completion:
bun test ./packages/slate/test/read-update-contract.ts ./packages/slate/test/primitive-method-runtime-contract.ts ./packages/slate/test/transaction-target-runtime-contract.ts ./packages/slate/test/commit-metadata-contract.ts ./packages/slate/test/bookmark-contract.ts --bail 1
bun test ./packages/slate-history --bail 1
bun test ./packages/slate-react/test/editing-kernel-contract.ts ./packages/slate-react/test/selection-controller-contract.ts ./packages/slate-react/test/dom-repair-policy-contract.ts ./packages/slate-react/test/target-runtime-contract.tsx ./packages/slate-react/test/dom-text-sync-contract.ts --bail 1
bun run --cwd packages/slate-browser test:core --bail 1
bunx turbo build --filter=./packages/slate --filter=./packages/slate-history --filter=./packages/slate-browser --filter=./packages/slate-dom --filter=./packages/slate-react --force
bunx turbo typecheck --filter=./packages/slate --filter=./packages/slate-history --filter=./packages/slate-browser --filter=./packages/slate-dom --filter=./packages/slate-react --force
bun run lint:fix
bun run lint
bun test:integration-local
Do not stop on a pivot, replan, or scary red row if another owner has a safe next move.
Stop only when:
Start with Batch 0.
Do not edit runtime code first. Inventory escape hatches, classify them, and add the executable allowlist gates. The fastest way to ruin this lane is to start patching another cursor symptom before the proof owners are nailed down.
Actions:
Commands:
sed -n '1,260p' docs/plans/2026-04-24-slate-v2-post-closure-proof-hardening-plan.md
sed -n '1,180p' active goal state
rg -n "cursor|caret|selection|Appium|Playwright|slate-v2|browser proof|completion-check" docs/solutions -S --glob '*.md'
sed -n '1,180p' docs/solutions/logic-errors/2026-04-24-slate-browser-proof-must-separate-model-owned-handles-root-selection-and-usable-focus.md
sed -n '1,120p' docs/solutions/developer-experience/2026-04-19-slate-public-single-op-writes-should-use-editor-apply-and-keep-onchange-behind-subscribers.md
Evidence:
docs/solutions/logic-errors/2026-04-24-slate-browser-proof-must-separate-model-owned-handles-root-selection-and-usable-focus.md
confirms the prior browser proof gap: Playwright can erase or miss the user's
prepared DOM selection unless root selection, usable focus, and model-owned
handles are separated.docs/solutions/developer-experience/2026-04-19-slate-public-single-op-writes-should-use-editor-apply-and-keep-onchange-behind-subscribers.md
confirms stale public fields and instance write callbacks must stay
classified as compatibility pressure, not primary extension or runtime law.Decision:
Next action:
/Users/zbeyens/git/slate-v2, read the current
public-surface and kernel-authority contracts, then add/update executable
allowlist gates.Actions:
/Users/zbeyens/git/slate-v2/packages/slate/test/escape-hatch-inventory-contract.ts.packages, site, playwright, and docs, excluding
generated Next output, dist, and node_modules.Commands:
rg -n "editor\\.(selection|children|marks|operations)|Transforms\\.|editor\\.apply|editor\\.onChange" packages site playwright docs --glob '!**/dist/**' --glob '!**/node_modules/**' --glob '!site/out/**' --glob '!site/.next/**'
rg -n "\\b(editor|Editor)\\.(insertText|delete|deleteBackward|deleteForward|deleteFragment|insertBreak|insertSoftBreak|insertNodes|insertFragment|setNodes|removeNodes|unwrapNodes|wrapNodes|select)\\(" packages site playwright docs --glob '!**/dist/**' --glob '!**/node_modules/**' --glob '!site/out/**' --glob '!site/.next/**'
rg -n "\\b(beginEditableEventFrame|recordEditableKernelTrace|syncEditorSelectionFromDOM|syncEditableDOMSelectionToEditor|requestRepair|applyEditableRepairRequest|repairDOMInput|domRepairQueue\\.repair|repairCaretAfterModelOperation|repairCaretAfterModelTextInsert)\\(" packages/slate-react/src packages/slate-react/test --glob '!**/dist/**'
bun test ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1
bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/public-field-hard-cut-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1
bun test ./packages/slate-react/test/kernel-authority-audit-contract.ts --bail 1
bun run lint:fix
bun run lint
Evidence:
bun test ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1:
3 pass.bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/public-field-hard-cut-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1:
48 pass.bun test ./packages/slate-react/test/kernel-authority-audit-contract.ts --bail 1:
3 pass, 12 expect calls.bun run lint:fix: no fixes applied.bun run lint: no fixes applied.Inventory summary:
Checkpoint:
bun test ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/public-field-hard-cut-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1bun test ./packages/slate-react/test/kernel-authority-audit-contract.ts --bail 1editor.update.tx.resolveTarget()Actions:
primitive means executable
primitive writes outside editor.update, not API headings or already-wrapped
docs snippets.editor.update.editor.update.Transforms.select from
/Users/zbeyens/git/slate-v2/packages/slate-history/src/with-history.ts;
undo/redo selection restore now uses the editor method inside the existing
history transaction.Transforms.* calls from core semantic helpers where editor
primitive methods can be used without recursion.editor.update remain compatibility auto-transactions that still produce
commit metadata.Changed files:
/Users/zbeyens/git/slate-v2/packages/slate/test/escape-hatch-inventory-contract.ts/Users/zbeyens/git/slate-v2/packages/slate/test/write-boundary-contract.ts/Users/zbeyens/git/slate-v2/packages/slate-history/src/with-history.ts/Users/zbeyens/git/slate-v2/packages/slate/src/editor/add-mark.ts/Users/zbeyens/git/slate-v2/packages/slate/src/editor/delete-backward.ts/Users/zbeyens/git/slate-v2/packages/slate/src/editor/delete-forward.ts/Users/zbeyens/git/slate-v2/packages/slate/src/editor/delete-fragment.ts/Users/zbeyens/git/slate-v2/packages/slate/src/editor/insert-node.ts/Users/zbeyens/git/slate-v2/packages/slate/src/editor/insert-soft-break.ts/Users/zbeyens/git/slate-v2/site/examples/**
and /Users/zbeyens/git/slate-v2/docs/walkthroughs/**Commands:
bun test ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1
bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/public-field-hard-cut-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts ./packages/slate/test/write-boundary-contract.ts --bail 1
bun test ./packages/slate/test/read-update-contract.ts ./packages/slate/test/primitive-method-runtime-contract.ts ./packages/slate/test/transaction-target-runtime-contract.ts ./packages/slate/test/commit-metadata-contract.ts --bail 1
bun test ./packages/slate-history --bail 1
bun run typecheck:site
bunx turbo build --filter=./packages/slate --filter=./packages/slate-history --force
bunx turbo typecheck --filter=./packages/slate --filter=./packages/slate-history --force
bun run lint:fix
bun run lint
Evidence:
escape-hatch-inventory-contract.ts.Transforms.* hits dropped from 9 to 2; remaining hits
are insertText low-level recursion-sensitive implementation.Transforms.* hits dropped from 2 to 0.bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/public-field-hard-cut-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts ./packages/slate/test/write-boundary-contract.ts --bail 1:
50 pass.bun test ./packages/slate/test/read-update-contract.ts ./packages/slate/test/primitive-method-runtime-contract.ts ./packages/slate/test/transaction-target-runtime-contract.ts ./packages/slate/test/commit-metadata-contract.ts --bail 1:
27 pass.bun test ./packages/slate-history --bail 1: 14 pass, 1 skip.bunx turbo build --filter=./packages/slate --filter=./packages/slate-history --force:
2 successful.bunx turbo typecheck --filter=./packages/slate --filter=./packages/slate-history --force:
4 successful.bun run typecheck:site: passed after fixing a TS narrowing issue in
review-comments.tsx.bun run lint:fix: no fixes applied after the final patch.bun run lint: no fixes applied.Failed probe:
bun run typecheck:site initially failed because wrapping
review-comments.tsx in editor.update lost the
firstAnnotation.range non-null narrowing inside the closure. Fixed by
capturing the path before the update.Decision:
editor.update remain compatibility
auto-transactions for now. Primary docs/examples do not teach them. Batch 2
should assert that mutation execution never bypasses a transaction, not that
every compatibility call site already disappeared.Checkpoint:
editor.update, history no longer uses
Transforms in runtime source, and direct primitive compatibility has a named
contract instead of an implicit shrug.e.select in history is not counted by the simple editor/Editor
AST matcher; Batch 2 assertions must catch actual mutation-boundary misuse
instead of relying only on text inventory.bun test ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1bun test ./packages/slate/test/write-boundary-contract.ts --bail 1bun run typecheck:siteeditor.updateActions:
editor.read rejects writes started
through:
Transforms.* callseditor.applywithTransaction and the raw operation application path.trace.transition.allowed === false
metadata.Transforms.* and editor.apply as blocked
compatibility paths.Changed files:
/Users/zbeyens/git/slate-v2/packages/slate/src/core/apply.ts/Users/zbeyens/git/slate-v2/packages/slate/src/core/public-state.ts/Users/zbeyens/git/slate-v2/packages/slate/test/read-update-contract.ts/Users/zbeyens/git/slate-v2/packages/slate/test/escape-hatch-inventory-contract.ts/Users/zbeyens/git/slate-v2/packages/slate-react/src/editable/editing-kernel.ts/Users/zbeyens/git/slate-v2/packages/slate-react/test/editing-kernel-contract.tsCommands:
bun test ./packages/slate-react/test/editing-kernel-contract.ts --bail 1
bun test ./packages/slate-react/test/editing-kernel-contract.ts ./packages/slate-react/test/selection-controller-contract.ts ./packages/slate-react/test/dom-repair-policy-contract.ts ./packages/slate-react/test/kernel-authority-audit-contract.ts --bail 1
bun test ./packages/slate/test/read-update-contract.ts --bail 1
bun test ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1
bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/public-field-hard-cut-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts ./packages/slate/test/read-update-contract.ts ./packages/slate/test/write-boundary-contract.ts ./packages/slate/test/primitive-method-runtime-contract.ts ./packages/slate/test/transaction-target-runtime-contract.ts ./packages/slate/test/commit-metadata-contract.ts --bail 1
bunx turbo build --filter=./packages/slate --filter=./packages/slate-history --filter=./packages/slate-dom --filter=./packages/slate-react --force
bunx turbo typecheck --filter=./packages/slate --filter=./packages/slate-history --filter=./packages/slate-dom --filter=./packages/slate-react --force
bun run lint:fix
bun run lint
Evidence:
bun test ./packages/slate/test/read-update-contract.ts --bail 1:
5 pass.bun test ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/public-field-hard-cut-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts ./packages/slate/test/read-update-contract.ts ./packages/slate/test/write-boundary-contract.ts ./packages/slate/test/primitive-method-runtime-contract.ts ./packages/slate/test/transaction-target-runtime-contract.ts ./packages/slate/test/commit-metadata-contract.ts --bail 1:
80 pass.bun test ./packages/slate-react/test/editing-kernel-contract.ts ./packages/slate-react/test/selection-controller-contract.ts ./packages/slate-react/test/dom-repair-policy-contract.ts ./packages/slate-react/test/kernel-authority-audit-contract.ts --bail 1:
27 pass, 64 expect calls.bunx turbo build --filter=./packages/slate --filter=./packages/slate-history --filter=./packages/slate-dom --filter=./packages/slate-react --force:
4 successful.bunx turbo typecheck --filter=./packages/slate --filter=./packages/slate-history --filter=./packages/slate-dom --filter=./packages/slate-react --force:
9 successful including dependency builds.bun run lint:fix: no fixes applied.bun run lint: no fixes applied.Failed probes:
kernel result creation rejects illegal transitions in test mode first failed
because illegal transitions were only metadata. Fixed by asserting in
createEditableKernelTraceEntry.rejects compatibility transform writes inside a plain read first failed
because Transforms.insertText could reach editor.apply without hitting
withTransaction. Fixed by guarding the raw operation application path.Transforms.* hit and two stale hits under
core contract tests. Updated the executable allowlist counts with the same
contract-test owner.Decision:
Transforms.*, or raw editor.apply
write can begin from editor.read.Checkpoint:
editor.update, and repair frames can no longer legally import DOM
selection.bun test ./packages/slate/test/read-update-contract.ts --bail 1bun test ./packages/slate-react/test/editing-kernel-contract.ts --bail 1bun test ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1Actions:
packages/slate-react/src/components/editable.tsx and
packages/slate-react/src/editable/**.kernel-authority-audit-contract.ts:
editable.tsx remains the central event owner for root event frames and
trace emission.input-controller.ts: it re-exports bridge helpers but does not run
them as a competing owner.slate-browser core gauntlet tests.Commands:
rg -n "\b(beginEditableEventFrame|recordEditableKernelTrace|syncEditorSelectionFromDOM|syncEditableDOMSelectionToEditor|requestRepair|applyEditableRepairRequest|repairDOMInput|domRepairQueue\.repair|repairCaretAfterModelOperation|repairCaretAfterModelTextInsert)\(" packages/slate-react/src/components/editable.tsx packages/slate-react/src/editable
rg -n "requestEditableRepair\(|requestRepair\(|applyEditableRepairRequest\(" packages/slate-react/src/components/editable.tsx packages/slate-react/src/editable
rg -n "syncEditorSelectionFromDOM|syncEditableDOMSelectionToEditor|executeEditableSelectionImport|selectionSourceTransition|setEditableModelSelectionPreference" packages/slate-react/src/components/editable.tsx packages/slate-react/src/editable
rg -n "recordKernelEventTrace|beginKernelEventFrame|createEditableKernelResult|recordEditableKernelTrace" packages/slate-react/src/components/editable.tsx packages/slate-react/src/editable
bunx turbo build --filter=./packages/slate-browser --filter=./packages/slate-dom --filter=./packages/slate-react --force
bun run test:slate-browser:core --bail 1
bunx playwright test ./playwright/integration/examples/richtext.test.ts --project=chromium --grep "keeps selected word expanded|warm toolbar|applies toolbar heading|keeps navigation and mutation|ArrowDown then ArrowRight" --workers=1 --retries=0
bunx playwright test ./playwright/integration/examples/richtext.test.ts --project=chromium --project=firefox --project=webkit --project=mobile --grep "keeps selected word expanded|warm toolbar|applies toolbar heading|keeps navigation and mutation|ArrowDown then ArrowRight" --workers=4 --retries=0
Evidence:
bun run test:slate-browser:core --bail 1: 21 tests, 44 expect calls.keeps selected word expanded after toggling toolbar bold offkeeps warm toolbar mark selection usable through arrows without reloadkeeps ArrowDown then ArrowRight in the browser-selected paragraphkeeps navigation and mutation chained through browser editing stateDecision:
Checkpoint:
bun test ./packages/slate-react/test/kernel-authority-audit-contract.ts --bail 1bun run test:slate-browser:core --bail 1Actions:
slate-browser mobile transport contract.slate-browser core proof tests after the audit.Files audited:
/Users/zbeyens/git/slate-v2/packages/slate-browser/src/transports/contracts.ts/Users/zbeyens/git/slate-v2/packages/slate-browser/src/transports/appium.ts/Users/zbeyens/git/slate-v2/packages/slate-browser/test/core/proof.test.ts/Users/zbeyens/git/slate-v2/packages/slate-browser/test/core/scenario.test.tsdocs/slate-v2/absolute-architecture-release-claim.mdCommands:
bun run test:slate-browser:core --bail 1
Evidence:
automated-direct,
release-gate-capable descriptor candidates for device-browser-text-input,
device-browser-ime-commit, and debug-snapshot.automated-proxy and explicitly not
release-gate-capable.native-mobile-clipboard as
unsupported.mobile-semantic-handle and synthetic composition as
mobile-synthetic-composition; it does not upgrade either to native proof.docs/slate-v2/absolute-architecture-release-claim.md already states that
native mobile clipboard, human soft keyboard behavior, glide typing, voice
input, and raw device rows are not claimed unless a device gate explicitly
runs.bun run test:slate-browser:core --bail 1: 21 pass, 44 expect calls.Decision:
Checkpoint:
bun run test:slate-browser:core --bail 1editor.extend, editor.update, and primitive
methods without monkeypatching or Transforms.*.Actions:
editor.extend, then
implement it with editor.update plus flexible primitive methods.editor.toggleTodo.Transforms.* out of the dogfood row.Changed files:
/Users/zbeyens/git/slate-v2/packages/slate/test/extension-methods-contract.tsCommands:
bun test ./packages/slate/test/extension-methods-contract.ts --bail 1
bun test ./packages/slate/test/extension-methods-contract.ts ./packages/slate/test/extension-contract.ts ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1
Evidence:
bun test ./packages/slate/test/extension-methods-contract.ts --bail 1:
5 pass.bun test ./packages/slate/test/extension-methods-contract.ts ./packages/slate/test/extension-contract.ts ./packages/slate/test/public-surface-contract.ts ./packages/slate/test/escape-hatch-inventory-contract.ts --bail 1:
57 pass.toggleTodo methodeditor.update as write boundaryunwrapNodes, setNodes, and wrapNodes compositionTransforms.* in the preferred extension method pathDecision:
editor.extend({ methods })
plus safe primitives under editor.update.Checkpoint:
editor.update are the power API.Transforms.*,
command policy objects, exposed tx.resolveTarget(), or method
monkeypatching as the preferred story.editor.extend.bun test ./packages/slate/test/extension-methods-contract.ts --bail 1bun test ./packages/slate/test/public-surface-contract.ts --bail 1tx.resolveTarget() to plugin authorsTransforms.* as the primary plugin mutation APIActions:
Enter/split-block keyboard input was classified as native-owned movement,
then dispatched an insert-break command. The stricter kernel correctly
rejected that illegal transition.beforeinput classification so split-block/line-break
input is owned by the model path before command dispatch.page.goto.bun test:integration-local workers at 2 by default, kept
PLAYWRIGHT_WORKERS as an explicit override, and raised the behavior-test
timeout to 30 seconds. CI keeps its existing worker policy.bun test:integration-local command to a clean pass with
no flaky section.Changed files:
/Users/zbeyens/git/slate-v2/packages/slate-react/src/editable/input-state.ts/Users/zbeyens/git/slate-v2/packages/slate-react/src/editable/input-controller.ts/Users/zbeyens/git/slate-v2/packages/slate-react/src/editable/editing-kernel.ts/Users/zbeyens/git/slate-v2/packages/slate-react/test/editing-kernel-contract.ts/Users/zbeyens/git/slate-v2/playwright.config.tsCommands:
bun test ./packages/slate-react/test/editing-kernel-contract.ts --bail 1
bunx turbo build --filter=./packages/slate-dom --filter=./packages/slate-react --filter=./packages/slate-browser --force
bunx playwright test ./playwright/integration/examples/shadow-dom.test.ts --project=chromium --project=firefox --project=webkit --project=mobile --grep "user can type add a new line" --workers=4 --retries=0
bun test ./packages/slate-react/test/editing-kernel-contract.ts ./packages/slate-react/test/selection-controller-contract.ts ./packages/slate-react/test/dom-repair-policy-contract.ts ./packages/slate-react/test/kernel-authority-audit-contract.ts ./packages/slate-react/test/target-runtime-contract.tsx ./packages/slate-react/test/dom-text-sync-contract.ts --bail 1
bunx turbo typecheck --filter=./packages/slate-dom --filter=./packages/slate-react --filter=./packages/slate-browser --force
bun test:integration-local
bun run lint:fix
bun run lint
Evidence:
bun test ./packages/slate-react/test/editing-kernel-contract.ts --bail 1:
12 pass, 20 expect calls after adding the structural Enter regression row.bunx turbo build --filter=./packages/slate-dom --filter=./packages/slate-react --filter=./packages/slate-browser --force:
3 successful tasks.bunx playwright test ./playwright/integration/examples/shadow-dom.test.ts --project=chromium --project=firefox --project=webkit --project=mobile --grep "user can type add a new line" --workers=4 --retries=0:
4 passed.bun test ./packages/slate-react/test/editing-kernel-contract.ts ./packages/slate-react/test/selection-controller-contract.ts ./packages/slate-react/test/dom-repair-policy-contract.ts ./packages/slate-react/test/kernel-authority-audit-contract.ts ./packages/slate-react/test/target-runtime-contract.tsx ./packages/slate-react/test/dom-text-sync-contract.ts --bail 1:
31 pass, 75 expect calls.bunx turbo typecheck --filter=./packages/slate-dom --filter=./packages/slate-react --filter=./packages/slate-browser --force:
9 successful tasks.bun test:integration-local with unrestricted local workers
timed out unrelated Chromium rows under full-suite load. The run was stopped
after enough evidence showed harness saturation, not a specific editor
behavior failure.bun test:integration-local with 4 workers and 30 second
timeout exited 0 but still reported 4 first-attempt Chromium flakes.bun test:integration-local: 528 passed in 3.1 minutes, with no flaky
section, using the committed local default of 2 workers.bun run lint:fix: checked 1582 files, no fixes applied.bun run lint: checked 1582 files, no fixes applied.bun run test:slate-browser:core --bail 1: 21 pass, 44 expect callsDecision:
Checkpoint:
bun test:integration-localbun run test:slate-browser:core --bail 1Actions:
docs/solutions.ce:compound mode because this runtime does not allow
subagent spawning without an explicit user request.Changed files:
docs/solutions/test-failures/2026-04-24-slate-v2-integration-local-should-cap-local-playwright-workers-before-debugging-editor-failures.mdEvidence:
page.goto
timeouts as editor failures.Decision: