Back to Plate

Slate v2 DOM Selection Boundary Proof Ralplan

docs/plans/2026-05-06-slate-v2-dom-selection-boundary-proof-ralplan.md

53.0.642.4 KB
Original Source

Slate v2 DOM Selection Boundary Proof Ralplan

1. Current Verdict

Next cluster: v2-dom-selection.

The next implementation slice should not chase Android IME, virtualization, or another clipboard fast path. The highest-leverage browser-replayable gap is central DOM selection import/export around tables, inline boundaries, voids, triple-click hanging ranges, nested editors, and outside-editor selections.

Do the strict runtime bridge first. Do not add a public normalizePoint API.

2. Intent And Boundary Record

Intent:

  • Turn the largest issue cluster, selection/focus/DOM bridge, from architecture pressure into replayable browser proof.

Desired outcome:

  • Slate v2 has one selection bridge that imports native selection, exports model selection, and fails closed with a reason instead of throwing raw Cannot resolve ... errors in the runtime path.

In scope:

  • slate-dom selection import/export result objects.
  • slate-react selection reconciler/runtime integration.
  • Browser scenario rows for table edge navigation, inline/void boundaries, triple-click hanging block ranges, outside-editor drag/import, and nested editor containment.
  • Issue-ledger sync for exact fixed, improved, related, and not-claimed rows.

Non-goals:

  • No Android/iOS device closure without raw device proof.
  • No public normalizePoint extension point.
  • No app-rendered arbitrary DOM support.
  • No new product-level Plate selection UX.
  • No virtualization convergence.

Decision boundaries:

  • The implementation may add internal DOM selection capability names.
  • The implementation may migrate runtime callsites away from raw throwing toSlatePoint / toSlateRange.
  • Public DOM helper names should not be expanded unless a test proves internal capability-only design is insufficient.

Unresolved user-decision points:

  • None for planning. User review is still required before ralph executes.

3. Decision Brief

Principles:

  • Selection import/export has one owner.
  • Runtime paths must prefer typed failure over exceptions.
  • Browser replay beats architecture confidence.
  • Slate core stays model-first and unopinionated.
  • Mobile claims need device proof, not desktop emulation.

Top drivers:

  • Issue corpus: selection/focus/DOM bridge is the biggest raw cluster at 172 issues; 118 of those are runtime-boundary owned.
  • Live source: DOMEditorCapability still exposes direct toSlatePoint / toSlateRange primitives, while selection-reconciler owns separate collapsed/select-all fallback logic.
  • Browser contracts already have first-party rows for inline void, block void, table boundary, and toolbar/mouse selection, but not enough exact issue rows for the open DOM-selection cluster.

Viable options:

OptionProsConsVerdict
A. Patch each failing exampleFast per bugRecreates legacy selection whack-a-molereject
B. Add public normalizePointGives apps an escape hatchLeaks browser DOM policy into app code; hard to provereject
C. Central internal selection bridge with result objectsOne owner, typed failures, browser-proofableRequires callsite migration and more contractschoose
D. Copy ProseMirror view modelProven DOM bridge disciplineToo schema/view-heavy for Slate's modelpartial

Chosen option:

  • Add a central internal DOM selection bridge and route slate-react runtime through it. Keep raw strict toSlatePoint / toSlateRange for low-level exact helpers, but runtime event paths should consume non-throwing result objects with failure reasons.

Consequences:

  • Some previously thrown runtime errors become repair/fail-closed traces.
  • Exact issue claims are allowed only when a browser row replays the original behavior.
  • Mobile rows stay Related until real device proof exists.

Follow-ups:

  • Android IME proof lane after this bridge is stable.
  • Public helper docs only after internal bridge naming survives the tests.

4. Confidence Scorecard

DimensionScoreEvidence
React 19.2 runtime performance0.91Runtime bridge centralizes native listener/import work instead of widening React subscriptions; current selectionchange path is throttled and traced in .tmp/slate-v2/packages/slate-react/src/editable/runtime-selection-engine.ts.
Slate-close unopinionated DX0.94Rejects public normalizePoint; keeps app renderers out of DOM bridge policy.
Plate and slate-yjs migration backbone0.89Selection bridge emits model selections and reasoned traces; no Plate API or Yjs adapter promised.
Regression-proof testing0.95Existing browser contract registry has inline void, block void, and table rows; plan adds exact replay rows before any Fixes claim.
Research evidence completeness0.93Uses Lexical lifecycle tags and dirty selection state, ProseMirror view DOM selection ownership, Tiptap node-view event boundary as evidence, plus live Slate v2 source.
shadcn-style composability0.91No product chrome; runtime result objects remain composable for examples and Plate.

Total: 0.93.

5. Source-Backed North Star

Current live source:

  • .tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts:57 exposes toDOMPoint, toDOMRange, toSlatePoint, and toSlateRange as direct DOM capabilities.
  • .tmp/slate-v2/packages/slate-react/src/editable/selection-reconciler.ts:46 has a separate collapsed DOM-selection importer and select-all fallback.
  • .tmp/slate-v2/packages/slate-react/src/editable/runtime-selection-engine.ts:46 owns throttled native selectionchange handling and kernel traces.
  • .tmp/slate-v2/packages/slate-browser/test/core/scenario.test.ts:137 locks first-party parity families, including inline void and table boundary rows.

Target:

txt
native selection event
  -> DOM selection bridge
  -> SelectionImportResult | SelectionExportResult
  -> selection controller policy
  -> model selection / repair trace / fail-closed reason

Raw runtime code should stop blindly calling strict DOM-to-Slate conversion in places where the browser may hand us foreign, nested, void, table, or temporarily stale DOM.

6. Ecosystem Strategy Synthesis

SystemSourceMechanismAvoidsStealRejectSlate targetVerdict
Lexicaldocs/research/sources/editor-architecture/lexical-read-update-extension-runtime.md; ../lexical/packages/lexical/src/LexicalUpdateTags.tsUpdate tags for skip-dom-selection, focus, and composition; dirty selection stateDOM selection side effects leaking into every updateCommit/trace metadata for selection ownership and skip/repair policyClass nodes and $ APISelection import/export records reason/policy in runtime tracepartial
ProseMirrordocs/research/sources/editor-architecture/prosemirror-transaction-view-dom-runtime.mdView owns selectionFromDOM, selectionToDOM, DOM observer, compositionApp commands reading DOM directlyOne DOM selection bridge ownerInteger document positions and schema-first coreslate-dom bridge owns DOM import/export, React consumes resultagree
Tiptap../tiptap/packages/core/src/NodeView.tsNodeView stopEvent / ignoreMutation boundaries over ProseMirror viewNode views corrupting editor selection/mutationsBoundary policy as product-extension pressureProseMirror NodeView as Slate APIRuntime can classify internal/foreign DOM targets without exposing node viewspartial
Slate v2 live source.tmp/slate-v2/packages/slate-react/src/editable/selection-reconciler.ts; .tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.tsSplit direct DOM helpers plus runtime fallback importSome current crashes, but not enough issue proofExisting kernel trace and browser scenario infrastructureScattered fallback logicCentral result object bridgerevise

7. Public API Target

Status: keep-private.

  • No new public normalizePoint.
  • No public app-authored DOM selection policy.
  • No public DOMSelectionBridge export in this slice.
  • Keep strict helper behavior for direct low-level use.
  • Runtime event paths use internal non-throwing result objects.

Candidate internal shape:

ts
type DOMSelectionImportResult =
  | { type: "ok"; selection: Range | null; source: "native" | "fallback" }
  | { type: "ignored"; reason: "foreign-target" | "nested-editor" | "readonly" }
  | { type: "repair"; reason: "missing-dom" | "boundary" | "stale-dom" }
  | { type: "error"; reason: string };

This is not a final API proposal. It is the proof seam.

8. Internal Runtime Target

  • Move collapsed selection fallback and select-all fallback behind one import bridge.
  • Add explicit failure reasons for:
    • outside editor target;
    • nested editor target;
    • table non-cell structural DOM;
    • inline boundary padding / adjacent spacer target;
    • void boundary target;
    • stale or missing DOM;
    • DOM coverage boundary.
  • Make selection controller consume result type, not exception control flow.
  • Trace every non-ok decision through the existing kernel trace.
  • Preserve strict toSlatePoint tests; add runtime tests proving it is no longer called blindly from selectionchange.

9. Hook / Component / Render DX Target

  • No app renderer receives extra selection props.
  • Void and inline examples should only prove behavior, not own policy.
  • Existing browser examples become proof routes:
    • mentions: inline void boundary navigation.
    • tables: table edge arrow navigation.
    • richtext: triple-click + destructive edit.
    • nested/iframe route if needed for cross-root containment.

10. Plate Migration Backbone

Plate should get a cleaner substrate:

  • one internal bridge for native selection;
  • reasoned traces for plugin/UI debugging;
  • browser contracts for table, inline void, and toolbar selection;
  • no need for Plate to wrap raw DOM conversion helpers.

No current Plate adapter compatibility is promised.

11. slate-yjs Migration Backbone

Collab relevance:

  • Selection import/export must produce deterministic model selections or explicit ignored/repair states.
  • No remote operation semantics change in this slice.
  • Future awareness/cursor adapters can consume the same model selection and failure reason, but this plan does not implement slate-yjs support.

12. Issue-Ledger Accounting

ClawSweeper pass: applied.

Gitcrawl evidence:

  • gitcrawl doctor --json green with 617 clusters and 659 open threads.
  • gitcrawl cluster-detail reviewed clusters 1, 5, 12, 17, and 23.
  • Existing recluster map marks table selection, inline boundary, inline/void, mobile/browser selection quirks, triple-click, and DOM point crashes under v2-dom-selection.

Current issue matrix:

IssueClusterClaimWhyProof routeLive ledger syncPR line
#6034table-selection-and-arrow-navigationFixesExact table-end ArrowDown browser repro is covered: remove the trailing paragraph, keep the table as the last node, press ArrowDown at the last cell, then type..tmp/slate-v2/playwright/integration/examples/tables.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#5355table-selection-and-arrow-navigationNot claimedExact repro depends on colgroup / col renderer shapes that omit editable descendants; raw app-rendered missing DOM remains unsupported without a Slate-owned coverage boundary.No exact browser row in this slice.keep issue-reviewed / not-claimed; live gitcrawl ledger remains upstream-current onlyno fixed line
#4658table-selection-and-arrow-navigationImprovesCustom text outside table should fail closed, but exact custom table repro is not in scope.DOM import unit + table browser row.keep related unless exact repro addedrelated matrix only
#3871triple-click-and-block-selectionFixesExact desktop browser triple-click proof imports the clicked richtext paragraph as one block range only..tmp/slate-v2/playwright/integration/examples/richtext.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#5847triple-click-and-block-selectionFixesExact desktop browser triple-click + Backspace proof removes the selected block instead of emptying it..tmp/slate-v2/playwright/integration/examples/richtext.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#3991inline-void-and-void-selectionFixesExact block-void Backspace browser repro is covered: empty paragraph after the void is removed and the void is selected instead of deleted..tmp/slate-v2/playwright/integration/examples/images.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#4301inline-void-and-void-selectionFixesExact clicked-selected block-void Enter repro is covered: Enter inserts an editable paragraph after the void..tmp/slate-v2/playwright/integration/examples/images.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#4074inline-boundary-cursor-movementFixesExact Chromium browser row proves text can be inserted at an editable inline edge without being pushed outside the inline..tmp/slate-v2/playwright/integration/examples/inlines.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#4618inline-boundary-cursor-movementNot claimedPublic normalizePoint is rejected; bridge policy is the answer.Plan decision.existing cluster-syncedrelated matrix only
#3429inline-boundary-cursor-movementFixesExact Chromium browser row proves the caret target before a padded editable inline stays outside the padded inline..tmp/slate-v2/playwright/integration/examples/inlines.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#3148inline-boundary-cursor-movementFixesExact Chromium and WebKit browser rows prove inline-end and following-text-start selections stay distinct before text insertion..tmp/slate-v2/playwright/integration/examples/inlines.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#3150inline-boundary-cursor-movementRelatedTracker-like row; do not close.None.existing Relatedrelated matrix only
#4564dom-point-resolution-crashesImprovesProgrammatic removal stale-DOM crash class should fail closed, but exact repro not in this slice unless added.DOM unit + browser row optional.existing Improvesrelated matrix only
#4789dom-point-resolution-crashesFixesExact Chromium browser row creates a native selection that starts outside Slate and ends inside the editor, then verifies no DOM point crash and normal refocus usability..tmp/slate-v2/playwright/integration/examples/richtext.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#4984dom-point-resolution-crashesFixesExact Chromium browser row creates a parent-editor native selection that crosses into a nested editor, then verifies no DOM point crash and focused-editor input ownership..tmp/slate-v2/playwright/integration/examples/editable-voids.test.tsfixes-claimed in the fork ledger; live gitcrawl ledger remains upstream-current onlyfixed line allowed
#3723, #3834, #3836, #5711dom-point-resolution-crashesRelatedSame DOM import crash family; exact browser/device repro varies.DOM bridge contracts.existing cluster-syncedrelated matrix only
#5183, #5391inline-void-and-void-selectionRelatedAndroid/iOS keyboard/handle behavior requires device proof.No desktop auto-close.existing Relatedrelated matrix only

Live ledger sync status:

  • docs/slate-issues/open-issues-ledger.md, docs/slate-v2/ledgers/issue-coverage-matrix.md, docs/slate-v2/ledgers/fork-issue-dossier.md, and docs/slate-v2/references/pr-description.md are synced for #6034, #5355, #3871, #5847, #3991, #4301, #4074, #3148, #3429, #4618, #4789, and #4984.
  • The live gitcrawl corpus files remain upstream-current discovery inputs, not fork-local claim ledgers.

PR description status:

  • pr-description includes exact Fixes #6034, Fixes #3871, Fixes #5847, Fixes #3991, Fixes #4301, Fixes #4074, Fixes #3148, Fixes #3429, Fixes #4789, and Fixes #4984 lines, with #5355 and #4618 intentionally omitted.

13. Legacy Regression Proof Matrix

FamilyRouteRequired proof
table edge ArrowDowntablesmodel and DOM selection agree at table-last-node boundary; no throw
table colgroup/coltablesnon-cell table DOM cannot resolve into invalid Slate point
triple-click hanging rangerichtexttriple-click range imports as intended block range; Backspace/Cut removes block as browser parity expects
inline void selectionmentionsarrow keys enter/select/leave mention; Delete/Backspace deterministic
block void selectionimages / embedsselection enters/leaves block void with no hidden-anchor gap
outside-editor dragdedicated browser rowforeign DOM point ignored/fail-closed; no model corruption
nested editor boundarynested/iframe routeparent cannot import child editor DOM point
zero-width fallbackexisting zero-width browser testsno regression

14. Browser Stress / Parity Strategy

Use generated browser scenario rows, not one-off manual examples.

Minimum execution gate:

bash
bun test .tmp/slate-v2/packages/slate-dom/test/bridge.test.ts \
  .tmp/slate-v2/packages/slate-react/test/selection-controller-contract.test.ts \
  .tmp/slate-v2/packages/slate-react/test/selection-reconciler-contract.ts

STRESS_FAMILIES=table-cell-boundary-navigation,inline-void-boundary-navigation,block-void-navigation,triple-click-block-selection \
PLAYWRIGHT_RETRIES=0 \
bunx playwright test playwright/stress/generated-editing.test.ts --project=chromium

Exact commands may need adjustment to current package scripts during execution.

15. Applicable Implementation-Skill Review Matrix

LensApplicabilityFindingsPlan delta
vercel-react-best-practicesappliedRuntime listener and selection import must stay outside broad React renders.Use bridge result objects and existing kernel trace.
performance-oracleappliedSelection import must avoid full DOM/tree scans on every selectionchange.Require bounded lookup and no document-scan fallback.
performanceskippedNo large repeated-unit performance claim in this slice.Browser parity proof is the gate.
tddappliedBehavior must start with red DOM/unit and browser rows.Execution phase starts with failing contracts.
build-web-apps:shadcnskippedNo UI chrome.None.
react-useeffectappliedSelection listeners are external sync; effects must stay subscription-only.No derived state reset effects.

16. High-Risk Deliberate Mode

Triggered: yes. This touches selection, focus, DOM repair, browser runtime, and issue claims.

Pre-mortem:

  1. Non-throwing bridge hides a real selection corruption bug.
  2. Table/inline special cases leak product policy into raw Slate.
  3. Browser proof passes on desktop but mobile issues are accidentally claimed.

Proof response:

  • Every ignored/repair result must trace a reason.
  • Exact Fixes claims require replayable browser row.
  • Mobile rows stay related until raw device proof exists.

Blast radius:

  • .tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts
  • .tmp/slate-v2/packages/slate-react/src/editable/selection-reconciler.ts
  • .tmp/slate-v2/packages/slate-react/src/editable/runtime-selection-engine.ts
  • .tmp/slate-v2/packages/slate-browser/**
  • Issue ledgers and PR reference.

Rollback / hard-cut answer:

  • This is worth doing because the current debt is scattered exception-driven selection repair. If the bridge result shape is wrong, keep the tests and revise the internal result naming, not the public API.

17. Hard Cuts And Rejected Alternatives

  • Cut: public normalizePoint as the first answer to #4618.
  • Cut: app renderer-owned DOM point repair.
  • Cut: claiming mobile inline void issues from desktop browser proof.
  • Cut: table-specific hacks inside examples.
  • Cut: swallowing errors without trace reason.
  • Keep: strict low-level toSlatePoint / toSlateRange for exact helper use.
  • Keep: DOMCoverage as missing-DOM substrate when boundaries are involved.

18. Slate Maintainer Objection Ledger

ChangePainObjectionSteelman antithesisTradeoffAnswerEvidenceRejected alternativeMigrationDocs/exampleProofEcosystemVerdict
Internal result-object DOM selection bridgeRuntime maintainers"This sounds like hiding real errors."Throwing exposes broken assumptions quickly.More result plumbing.Runtime paths need policy; strict helpers can still throw in exact tests.DOM crash cluster and live strict helpers.Catch-and-ignore exceptions.No public migration.Browser scenario rows explain behavior.Unit + browser rows.Plate gets trace reasons; collab gets deterministic model selection/no-op.keep
Reject public normalizePointApp authors needing custom caret behavior"Apps need a hook."A hook is flexible.Less immediate app escape.First fix the raw selection bridge; public hooks without proof fossilize browser quirks.#4618 cluster context.Public one-off hook.Document no public API in this slice.Inline examples prove default.Browser row.Plate can layer UX later.keep
Candidate fixed claims only after browser proofPR narrative"Why not claim the cluster?"The architecture clearly targets it.Slower issue count increase.Exact issue closure without replay is bullshit.ClawSweeper rules.Broad "Fixes DOM selection" claim.N/A.Ledger matrix.Browser rows.Maintainer-safe.keep

19. Pass Schedule And Pass-State Ledger

PassStatusEvidence addedPlan deltaOpen issuesNext owner
current-state readcompleteLive source, research, issue ledgersSelected v2-dom-selectionnonecurrent pass
related issue discoverycompleteGitcrawl clusters 1, 5, 12, 17, 23Issue matrix addedexact Fixes pending proofcurrent pass
intent/boundary briefcompleteSections 2-3Public API non-goals clarifiednonecurrent pass
ecosystem synthesiscompleteSection 6ProseMirror/Lexical/Tiptap decisions addednonecurrent pass
high-risk / maintainer passcompleteSections 16-18Fixed-claim bar tightenednonecurrent pass
user reviewpendingThis planUser may approve ralph executionnot starteduser
#6034 table ArrowDown proofcomplete.tmp/slate-v2/playwright/integration/examples/tables.test.ts; .tmp/slate-v2/packages/slate-dom/test/bridge.ts; gitcrawl threads ianstormtaylor/slate --numbers 6034 --include-closed --json; focused table Playwright green#6034 moved to fixes-claimed; non-exact DOM point offsets clamp to model text bounds.broader DOM-selection plan still pending#5355 table colgroup/col proof
#5355 colgroup/col proofcompletegitcrawl threads ianstormtaylor/slate --numbers 5355 --include-closed --json; issue ledgersReclassified from candidate to not-claimed: raw app-rendered missing DOM stays unsupported without DOM coverage boundaries.broader DOM-selection plan still pendingtriple-click block selection proof
#3871/#5847 triple-click block selection proofcompletegitcrawl threads ianstormtaylor/slate --numbers 3871,5847 --include-closed --json; .tmp/slate-v2/playwright/integration/examples/richtext.test.ts; focused richtext Playwright green#3871 and #5847 moved to fixes-claimed; React destructive command handling recognizes full-block browser/hanging ranges.broader DOM-selection plan still pendinginline void selection proof
#3991/#4301 block-void delete and Enter proofcompletegitcrawl threads ianstormtaylor/slate --numbers 3991,4301 --include-closed --json; .tmp/slate-v2/playwright/integration/examples/images.test.ts; .tmp/slate-v2/packages/slate-react/src/editable/mutation-controller.ts; focused images Playwright green#3991 and #4301 moved to fixes-claimed; React model-owned mutation path handles block-void Backspace and Enter parity.broader DOM-selection plan still pendinginline boundary cursor movement proof
#4074/#3148/#3429 inline boundary cursor movement proofcompletegitcrawl threads ianstormtaylor/slate --numbers 4074,3429,3148,4618 --include-closed --json; .tmp/slate-v2/playwright/integration/examples/inlines.test.ts; focused Chromium and WebKit Playwright rows green#4074, #3148, and #3429 moved to fixes-claimed; #4618 moved to not-claimed because public normalizePoint remains rejected.broader DOM-selection plan still pendingoutside-editor and nested-editor DOM point proof
#4789/#4984 outside and nested editor DOM point proofcompletegitcrawl threads ianstormtaylor/slate --numbers 4789,4984,4564,3723,3834,3836,5711 --include-closed --json; .tmp/slate-v2/playwright/integration/examples/richtext.test.ts; .tmp/slate-v2/playwright/integration/examples/editable-voids.test.ts; focused Chromium rows green#4789 and #4984 moved to fixes-claimed; #4564 remains Improves; #3723/#3834/#3836/#5711 remain related because exact repros differ or require iOS/IME proof.broader DOM-selection plan still pendingremaining DOM point crash variants and full selection-family verification

20. Plan Deltas From Review

  • Added next cluster decision: v2-dom-selection.
  • Dropped mobile IME as next executable slice.
  • Dropped public normalizePoint.
  • Strengthened exact issue claim bar.
  • Added browser-first proof matrix.
  • Preserved existing issue-ledger statuses until execution produces proof.

21. Open Questions And What Would Change The Decision

  • If selection-reconciler already has a central result object hidden in live source, execution should harden that instead of adding a new one.
  • If table rows already pass exact #6034/#5355 proof, execution should switch to ledger sync and missing browser rows only.
  • If a public app hook is still required after central bridge proof, create a separate API bake-off; do not smuggle it into this slice.

22. Implementation Phases

Phase 1: Red Contracts

Owner: .tmp/slate-v2/packages/slate-dom and .tmp/slate-v2/packages/slate-react.

  • Add result-object tests for selection import/export.
  • Add fail-closed tests for outside/nested/stale/missing DOM.
  • Add table/inline/void/triple-click browser rows as failing contracts.

Phase 2: Internal Bridge

Owner: slate-dom.

  • Add internal DOM selection bridge capability.
  • Preserve strict helper behavior.
  • Add bounded lookup and reasoned failure results.

Phase 3: Runtime Integration

Owner: slate-react.

  • Route selectionchange and keydown selection import through the bridge.
  • Record kernel traces for ignored/repair/error decisions.
  • Remove duplicate fallback logic from reconciler callsites where the bridge owns it.

Phase 4: Browser Proof

Owner: slate-browser.

  • Run table, inline void, block void, triple-click, outside selection, and nested editor rows.
  • Record exact issue claim outcomes.

Phase 5: Ledger And PR Sync

Owner: plate-2 docs.

  • Update live ledger, issue coverage matrix, fork dossier, PR reference, and completion file.

23. Fast Driver Gates

  • bun test focused DOM/react selection contract files.
  • bun --filter slate-dom typecheck.
  • bun --filter slate-react typecheck.
  • bun lint:fix.
  • Focused Playwright stress rows by family.
  • bun run completion-check in /Users/zbeyens/git/plate-2.

24. Final User-Review Handoff Outline

When executed, report:

  • fixed vs improved vs related issue rows;
  • exact browser families passed;
  • public API unchanged unless proof forces a change;
  • strict helper behavior kept;
  • mobile claims not made without device proof.

25. Final Completion Gates

Completion requires:

  • all red contracts green;
  • no runtime path blindly throws on known foreign/nested/table/inline/void DOM target classes;
  • browser stress rows green;
  • issue ledgers synced;
  • PR description synced or explicitly unchanged;
  • completion file done.