docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md
Pass 12 plus the cross-editor test-mining addendum are complete. The Slate
Ralplan is done.
The closure pass found no contradiction between the scorecard, issue-sync text,
PR reference, and final gates. All scheduled pass rows are complete, score is
0.95, no dimension is below 0.85, and the synced ledgers preserve the core
truth: this plan accepts the shared input-runtime owner model, but it does not
claim exact Android/iOS/IME fixes without matching proof.
The issue-sync accounting pass completed conservative durable sync without
inflating claims. The issue coverage matrix now backfills #5711, #3634,
and #4961 as related rows; the fork dossier aligns stale #6022, #5983,
#5183, and #5088 statuses down to related; the matrix, fork dossier, live
gitcrawl ledger, cluster ledger, and PR reference carry the Mobile/IME macro
sync counts. No exact Fixes #... or Improves #... Mobile/IME claim changed.
Score is now 0.95; closure and the requested cross-editor mining pass are
complete.
The correct direction is not a new public API blitz and not one Android patch per
issue. Slate v2 already has the right owner shape in live source: a shared
slate-react input runtime, a slate-dom DOM bridge, explicit composition
state, native beforeinput / input listeners, Android manager integration,
selection import/export, repair, and kernel traces.
The related issue discovery pass confirms the shape: the frozen R7 input runtime
surface is 149 rows, all cluster-synced, with 117 high-confidence rows and
32 medium-confidence rows. The live gitcrawl mirror adds 119 current keyword
candidates with the discovery filter. That sweep is candidate generation, not
claim proof.
The issue-ledger pass now gives the next accounting shape. Among the 123
frozen R7 rows missing from current dossier coverage, 44 need long-form
dossier/proof-route rows, 59 stay matrix-only future proof rows, and 20 are
matrix-only non-claim rows. Pass 11 backfilled the three existing dossier rows
into the matrix and aligned the four matrix/dossier drift rows down to
related.
The pass-5 refresh confirms the earlier architecture call. Current
.tmp/slate-v2 source still owns Mobile/IME through the shared input runtime, not
through one-off per-device patches: root runtime state and owners live in
runtime-root-engine.ts:136, :188, :199, :246, :253, :283, :289,
and :345; event-family routing lives in runtime-event-engine.ts:162, :194,
:215, and :252; composition is a first-class runtime path in
runtime-composition-events.ts:36, :71, and :106; Android is routed through
runtime-android-engine.ts:8; native beforeinput / input listeners stay in
input-router.ts:91; and slate-dom still exposes composing state plus Android
DOM offset handling in dom-editor.ts:82, :166, :811, :1207, and :1511.
The pass-5 refresh also confirms the proof boundary. Current browser tests give
desktop IME and synthetic mobile confidence, not exact device closure:
rendering-strategy-runtime.test.ts:401 covers browser IME commit,
:431 covers the generated composition gauntlet, and :477 labels mobile as
mobile-synthetic-composition; dom-coverage-boundaries.test.ts:248 explicitly
skips mobile for hidden-boundary IME; dom-coverage-boundaries.test.ts:283
covers mobile touch only; generated-editing.test.ts:1027 is synthetic
selection-repair IME stress; and dom-coverage.ts:347 is unit-level composition
boundary policy. The package.json scripts expose check, check:full,
test:mobile-device-proof, and test:mobile-device-proof:raw, so exact
Android/iOS claims have a route but still need matching artifacts.
The pass-4 boundary still stands: the 44 long-form rows are proof-route
backlog, not claim backlog. The 20 matrix-only non-claim rows stay out of PR
auto-close language. The former four drift rows now default to related until
exact proof says otherwise. The existing v2-input-runtime Ralplan is done as an
architecture bucket, and this macro plan has enough routing to drive follow-up
ledger work. It still cannot claim "all Mobile/IME issues". Desktop IME,
synthetic mobile, and Android helper tests are useful. They do not close Samsung
Keyboard, Android Firefox predictive typing, Hangul placeholder, Chinese
backspace, Android voice input, iOS Chinese input, or Windows Vietnamese rows
without matching proof.
Pass 6 adds the hard pressure test: the current runtime shape is still good, but
execution cannot start as a vague "make Mobile/IME better" effort. Performance
claims must name cohorts and repeated-unit budgets; native-behavior claims must
say which mode preserves browser find, selection, copy/paste, IME, mobile touch,
undo/history, and collaboration; migration claims must stay at the substrate
level; and tests must be vertical issue/proof rows, not a bulk dump of all 44
long-form rows. The current source is strong enough to keep the direction:
root/runtime refs and memoized owners in runtime-root-engine.ts:136, :188,
:214, :246, :266, and :345; root native listeners in
input-router.ts:91; source-scoped listeners in public-state.ts:2175 and
:2483; dirty runtime IDs and commit metadata in public-state.ts:367; and
render-budget stress rows in generated-editing.test.ts:221, :947, and
:1020. The missing part is release-grade budgets and exact device artifacts,
not a new public API.
Pass 7 turns the likely maintainer pushback into plan edits. The strongest
objections do not invalidate the direction; they tighten the stop rules. Raw
device proof is still mandatory for exact mobile closure, synthetic rows must be
labelled as synthetic in proof and PR text, performance claims need cohort plus
repeated-unit evidence, and issue-sync work must happen in proof-heavy batches
instead of trying to write all 44 long-form rows at once. The maintainer pass
also accepts that the runtime already has Android-specific ownership, so the
answer is to keep that ownership centralized in runtime-android-engine.ts:8
and runtime-root-engine.ts:246, not to scatter device policy through public
APIs.
Pass 8 turns the high-risk review into release stop rules. The highest-risk failure is not "the plan is too cautious"; it is shipping an input change that duplicates text, drops composition text, moves the caret, or over-claims a real keyboard from synthetic proof. The plan keeps the runtime owner graph, but every execution slice now needs an explicit failure-mode table: data loss, selection corruption, public API lock-in, false mobile claim, React hot-path regression, collab/history nondeterminism, and native behavior regression. Any one of those failing in proof downgrades the claim or splits the slice before ledger sync.
Pass 9 locks the ecosystem story. Extension authors get typed state / tx
namespaces, runtime registration, commit listeners, and narrow React hooks; they
do not get raw public command slots or a Mobile/IME product namespace. Plate gets
the primitive input runtime, composing/focus/selection hooks, schema/extension
backbone, and proof gates it can wrap into richer UX. slate-yjs gets deterministic
operation replay, commit metadata, and typed remote metadata; it does not get
browser event timing encoded into the collaboration API. PR text must say this
plainly, or maintainers will read the plan as a broad adapter promise.
Pass 10 folds the accepted pass-7, pass-8, and pass-9 revisions into one
execution contract. The plan now has a single conservative rule set for batching,
synthetic labels, raw-device proof, performance budgets, adapter ownership,
high-risk failure modes, and ecosystem language. No contradiction was found: the
shared input runtime remains the right owner, the public API stays primitive,
and issue sync must preserve conservative Related / Needs repro language
until matching proof exists.
Current owner: slate-ralplan, complete.
Next owner after user review: ralph execution planning.
Intent:
Desired outcome:
Fixes, Improves, Related,
Not claimed, Needs repro, Stale, or Invalid;44 long-form rows are prepared for proof and dossier work without
implying they are fixed or improved;20 matrix-only non-claim rows remain visible as pressure, not execution
work.In scope:
slate-react-v2 event/runtime ownership for beforeinput, input, keydown,
composition, focus, selection import, Android integration, and repair;slate-dom-v2 DOM point/range translation, composing state, Android zero-width
handling, and browser-facing input bridges;Non-goals:
#6022, #5983, #5183, or #5088 from
ledger drift alone.Decision boundaries:
done until the scheduled passes are complete and the
score reaches the Slate Ralplan threshold;pending, not blocked, while local
issue discovery and plan hardening remain runnable;Unresolved user-decision points:
Pass-4 pressure test:
| Risk | Boundary answer | Stop rule |
|---|---|---|
The 44 long-form rows get treated as fixes | They are proof-route backlog only. | No Fixes or Improves text without exact repro proof. |
| Product behavior leaks into raw Slate | Raw Slate owns primitives; Plate/app code owns product policy. | Reject APIs that encode autocomplete, mention, slash-command, toolbar, or spellcheck policy. |
| Drift rows get promoted because one file is optimistic | Drift is accounting debt, not proof. | Use the conservative matrix claim until exact proof exists. |
| Synthetic mobile proof is used for real keyboards | Synthetic rows only show architecture confidence. | Android/iOS/Samsung/Firefox Android/voice claims need matching environment proof. |
| Browser-specific IME rows become generic unit tests | Unit tests can guard contracts, not close browser reports. | Browser/device report closure requires a browser/device artifact. |
No user question asked: the repo evidence gives enough authority to keep moving.
Principles:
Top drivers:
129
issues, priority 21.37.slate-react-v2 plus slate-dom-v2, with 124
of 129 rows in runtime ownership.149 R7 input-runtime rows: 44 long-form proof rows, 59
future proof rows, 20 non-claim rows, 3 matrix backfills, and 4 drift
rows.Viable options:
| Option | Verdict | Reason |
|---|---|---|
| Patch one issue/browser at a time | reject | Recreates legacy special-case sprawl and makes corpus claims impossible to audit. |
| Move Mobile/IME into pure core model code | reject | The failures are browser/runtime timing, DOM, selection, and composition problems. |
| Treat desktop Playwright IME as enough | reject | It would lie about Android/iOS keyboard behavior. |
| Keep the shared input runtime and harden proof/accounting | choose | It matches live source, package ownership, and issue pressure. |
Write all 44 long-form rows before research/proof mapping | reject | It would create polished dossier text before proof ownership is tight. |
| Expose product-level input policy in raw Slate | reject | Raw Slate should expose stable hooks and runtime rules, not editor-app UX. |
Chosen shape:
native browser event
-> input controller intent
-> runtime ownership decision
-> selection import/export policy
-> composition / Android / model / app handling
-> repair and kernel trace
-> proof artifact
-> issue claim or non-claim
Consequences:
Related or Needs repro even if the architecture is
correct.v2-input-runtime decisions should be inherited unless the
Mobile/IME-specific issue pass invalidates them.Follow-ups:
Decision locks from pass 4:
| Decision | Lock | Reason |
|---|---|---|
| Public API | keep current composition API until a routed row proves a missing primitive | Avoid freezing device-specific product policy into raw Slate. |
| Dossier batching | start with proof-heavy long-form rows, not all 44 at once | Dossier text without proof routes becomes audit theater. |
| Drift handling | sync to conservative claim by default | Exact proof, not optimism, promotes a row. |
| Device proof | match the reported environment | The bug is the keyboard/browser behavior, not just the abstract input event. |
| Implementation | no implementation from this Ralplan until closure or user acceptance | This skill is planning/review only. |
| Revision bundle | use the pass-10 execution contract during issue sync | It prevents accepted objections from being lost when claim rows are written. |
Total score: 0.95.
| Dimension | Weight | Score | Evidence |
|---|---|---|---|
| React 19.2 runtime performance | 0.20 | 0.92 | Pass 6 applies the performance rules: root runtime uses refs/memoized owners for transient hot state in runtime-root-engine.ts:136, :188, :214, :246, :266, and :345; native input listeners attach once at the root in input-router.ts:91; source listeners are scoped in public-state.ts:2175 and :2483; render-budget stress rows exist at generated-editing.test.ts:221, :947, and :1020; pass 11 keeps performance-sensitive Mobile/IME rows out of exact claims until cohort/device proof exists. |
| Slate-close unopinionated DX | 0.20 | 0.95 | Pass 10 consolidates the primitive-owned API rule: typed extension state / tx groups, runtime registration, commit listeners, composing state, native input hooks, input rules, and internal-control classification are enough unless a routed red proof row shows otherwise. Pass 11 synced the issue text without adding a product-specific Mobile/IME namespace. |
| Plate and slate-yjs migration backbone | 0.15 | 0.95 | Pass 10 consolidates adapter ownership: migration-backbone-contract.ts:33 proves extension state/tx namespaces and rejects adapter-shaped api/tf/plate/yjs fields; :171 proves deterministic replay with commit tags; collab-history-runtime-contract.ts:30, :114, and :155 prove one commit truth, remote replay, and typed remote metadata. |
| Regression-proof testing strategy | 0.20 | 0.95 | Pass 10 binds proof tiers to issue-sync claim language: unit/runtime, browser integration, raw mobile/manual, stress/performance, migration/adoption, and docs/PR tiers must match the reported environment before any exact claim. Pass 11 made that claim policy durable in the matrix, dossier, live-ledger notes, and PR reference. |
| Research evidence completeness | 0.15 | 0.95 | Compiled ProseMirror, Lexical, Tiptap, EditContext/IME, performance-rule, live-source evidence, the pass-7 objection ledger, the pass-8 high-risk source refresh, the pass-9 ecosystem owner review, the pass-10 revision bundle, and pass-11 ledger sync now cover architecture, runtime perf, migration substrate, regression proof, simplicity pressure, maintainer adoption, failure modes, and issue accounting. |
| shadcn-style composability and hook/component minimalism | 0.10 | 0.95 | Pass 10 keeps richer product DX above raw Slate, rejects broad public commands and Mobile/IME product API, and makes narrow hooks plus typed extension groups the execution contract. Pass 11 preserves that boundary in the PR-facing issue text. |
Why not higher:
done versus
another concrete revision.44 long-form dossier/proof rows are routed, but individual execution-batch
sections still need exact repro/proof before any claim promotion.The north star is already visible in live source.
isComposing, input controller state, Android manager ref,
selection reconciler, repair runtime, kernel trace runtime, event runtime, and
event bindings in
.tmp/slate-v2/packages/slate-react/src/editable/runtime-root-engine.ts:136,
:188, :199, :246, :253, :283, :289, and :345..tmp/slate-v2/packages/slate-react/src/editable/runtime-event-engine.ts:162
and :194..tmp/slate-v2/packages/slate-react/src/editable/input-controller.ts:121,
:170, and :246.prepareEditableCompositionKernel, trace
ownership, and apply start/update/end in
.tmp/slate-v2/packages/slate-react/src/editable/runtime-composition-events.ts:36,
:71, and :106.useAndroidInputManager in
.tmp/slate-v2/packages/slate-react/src/editable/runtime-android-engine.ts:8.beforeinput and input are attached outside React's polyfill in
.tmp/slate-v2/packages/slate-react/src/editable/input-router.ts:91.slate-dom exposes composing state, Android flush hooks, and Android
zero-width handling in
.tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts:82,
:166, :811, :1207, and :1511.Decision: keep this owner model. The Ralplan work is to make it issue-grade and proof-grade, not to replace it.
| System | Source | Mechanism | Avoids | Steal | Reject | Slate target | Verdict |
|---|---|---|---|---|---|---|---|
| ProseMirror | docs/research/sources/editor-architecture/prosemirror-transaction-view-dom-runtime.md:73 | One view owner for DOM selection import/export and composition mode | App commands reading DOM selection directly | Centralize DOM import/export and composition ownership | ProseMirror's full plugin/view tree | slate-dom + slate-react input runtime bridge | agree |
| Lexical | docs/research/sources/editor-architecture/lexical-read-update-extension-runtime.md:108 | Lifecycle tags for history, paste, collaboration, scroll, DOM selection, focus, composition | Anonymous update side effects | Typed commit metadata for composition and DOM selection policy | Class nodes, $ helpers, command-first app API | kernel trace / commit metadata for Mobile/IME proofs | partial |
| Tiptap | docs/research/sources/editor-architecture/tiptap-extension-command-react-dx.md:71 | Selector posture and composable UI around an editor engine | Transaction-wide React rerenders | Selector hooks for shell UI, not editor-body churn | Product command chains as raw Slate's required UX | minimal Slate hook surface, richer Plate layer | partial |
| EditContext / layout research | docs/research/sources/editor-architecture/layout-measurement-and-ime-lanes.md:50 | Text input services, selection, geometry, and format feedback are explicit platform work | Treating IME formatting like ordinary decorations | Keep IME/platform formatting distinct from product overlays | Browser API lock-in before support matures | dedicated Mobile/IME runtime proof lane | agree |
| Existing Slate v2 recovery audit | docs/research/decisions/slate-v2-editing-epoch-legacy-timing-recovery-audit.md:36 | Native beforeinput, Android manager, Safari/Chrome composition recovery, device proof boundary | Losing hard-earned legacy timing rules | Preserve recovered timing rules and proof boundaries | Literal legacy monolithic Editable | current runtime owners plus new issue proof | agree |
Research/source refresh status: complete for pass 5. No docs/research write
was required because the compiled layer already covers the current architecture
question and the remaining gap is issue/device proof, not missing ecosystem
research.
Pass-5 evidence ledger:
| Evidence class | Files refreshed | Disposition | Decision effect |
|---|---|---|---|
| Current Slate v2 source | runtime-root-engine.ts, runtime-event-engine.ts, input-controller.ts, runtime-composition-events.ts, runtime-android-engine.ts, input-router.ts, dom-editor.ts | evidenced | Keep the shared input-runtime owner model. |
| Current Slate v2 proof | rendering-strategy-runtime.test.ts, dom-coverage-boundaries.test.ts, generated-editing.test.ts, dom-coverage.ts, package.json proof scripts | partial | Current proof supports architecture confidence, not broad device closure. |
| Compiled editor architecture | ProseMirror transaction/view runtime, Lexical read/update runtime, Tiptap extension/DX, layout/IME lane, editing-epoch recovery audit | evidenced | Keep DOM import/export centralized, composition explicit, commit metadata typed, product policy above raw Slate. |
| Issue dossiers and public test rows | 5994-5918.md, 5129-5066.md, 4541-4392.md, plus the existing test-candidate maps | evidenced | Prioritize proof-heavy Android empty-state, Chinese IME, autocorrect, heading Enter, and onChange rows first. |
| Raw-device proof | package.json:59, :60, :63 provide scripts but no fresh artifacts in this pass | gap | Android/iOS/Samsung/Firefox Android/voice claims stay non-claims until matching artifacts exist. |
User-requested cross-editor IME/mobile mining addendum:
| Source | Local evidence read | What to steal | Slate v2 gap / target |
|---|---|---|---|
| Lexical composition E2E | ../lexical/packages/lexical-playground/__tests__/e2e/Composition.spec.mjs:173, :174, :258, :371, :445, :636, :746, :852, :920, :1078, :1211, :1276, :1325 | CDP Input.imeSetComposition staged Japanese/Hiragana tests across line breaks, new formatting, emojis, mentions, hashtags, cancel/delete, overlay behavior, and Korean multi-format replacement | Slate v2 has a basic Japanese composition gauntlet; add translated rows for inline void/mention boundaries, formatting/decorations, cancellation, and UI overlay non-interference before any exact issue claim. |
| Lexical history / Safari regressions | ../lexical/packages/lexical-playground/__tests__/e2e/History.spec.mjs:508, :510, :781, :889; ../lexical/packages/lexical-playground/__tests__/regression/8153-safari-ime-delete-selection.spec.mjs:39, :73 | Undo grouping after composition, canceled composition not entering history, retained selection after IME undo, Safari delete-selection after composition end | Slate v2 needs history/collab commit-metadata proof for composed DOM input and Safari post-composition deletion rows, not just final text assertions. |
| Lexical mobile/native input source | ../lexical/packages/lexical/src/LexicalEvents.ts:655, :710, :1018, :1029, :1168; ../lexical/packages/lexical/src/__tests__/unit/HTMLCopyAndPaste.test.ts:135; ../lexical/packages/lexical-plain-text/src/index.ts:286; ../lexical/packages/lexical-rich-text/src/index.ts:893 | Android deleteContentBackward composition-key reset/delay, Firefox composition-end timing, Safari compositionend-before-keydown, iOS word prediction/autocorrect plain-text handling, iOS Korean backspace native fallback | Translate into raw-device/manual rows for Android backspace/autocorrect, iOS prediction/Korean backspace, and Safari timing before promoting related Mobile/IME issues. |
| ProseMirror DOM-change/runtime | ../prosemirror/state/src/transaction.ts:36, :38, :39; ../prosemirror/view/src/domchange.ts:82, :96, :124, :198, :204, :228, :239; ../prosemirror/view/src/viewdesc.ts:769, :792, :808, :839 | Composition transaction metadata, protected local composition DOM, Chrome wrong-selection guards, Chrome delete/reinsert detection, Android virtual-keyboard fallback, iOS Enter/mobile DOM hacks | Slate v2 already has kernel traces and composition-owned selection; execution should add composition commit IDs/metadata assertions and DOM-change-style wrong-selection/Android fallback proof where missing. |
| ProseMirror web tests | ../prosemirror/view/test/webtest-domchange.ts:190, :198, :205, :211, :219 | Read DOM composition changes, text deletion/typing inside markup, ambiguous text replacement, and no repaint of active text node | Add low-level DOM sync tests around mark/decorator boundaries and active text-node preservation, especially for hidden-boundary and inline-void cases. |
Pass-9 ecosystem maintainer ledger:
| Audience | Likely reading | Accepted wording | Must not imply | Evidence | Verdict |
|---|---|---|---|---|---|
| Raw Slate extension authors | "Can I extend input behavior without monkeypatching the editor?" | Use typed state / tx extension groups, runtime registration, commit listeners, and narrow input hooks. | Public command slots, Mobile/IME product policy, or device flags. | .tmp/slate-v2/packages/slate/src/interfaces/editor.ts:433, :480, :804, :859, :872, :886, :1589, :1594; generic-extension-namespace-contract.ts:22, :56, :118, :160, :187 | keep |
| Plate maintainers | "Can Plate build richer UX on this without raw Slate becoming Plate-shaped?" | Plate wraps primitive composition/focus/selection/input hooks and state / tx substrate. | Current-version Plate adapter compatibility or api / tf fields on raw Slate. | migration-backbone-contract.ts:33, :41, :52, :73, :162; hooks.md:7, :25 | keep |
| slate-yjs / collaboration maintainers | "Will IME/runtime fixes replay deterministically?" | Rely on commit metadata, operation replay, commit listeners, and typed remote metadata; browser event timing stays local. | yjs-specific fields on raw Slate, remote inference of DOM timing, or exact adapter closure. | collab-history-runtime-contract.ts:30, :114, :155; migration-backbone-contract.ts:171; editor.ts:700, :1217 | keep |
| React shell authors | "Can toolbar/shell UI observe state without rerendering the editor body?" | Use selector hooks and editor.read; keep composition/focus/selection reads out of large node trees. | Per-node subscriptions or product controls stealing composition/input ownership. | hooks.md:7, :13, :25, :37; runtime-root-engine.ts:136, :188, :266 | keep |
| Release / PR reviewers | "Does this close all Mobile/IME issues?" | It routes Mobile/IME architecture and proof tiers; exact issue claims require matching proof and later ledger sync. | Fixes / Improves promotion from synthetic mobile, architecture coverage, or dossier text alone. | Section 12 issue routing; Section 14 proof tiers; Section 18 objection ledger; Section 16 high-risk stop rules | revise |
| Product plugin authors | "Can raw Slate ship autocomplete, suggestions, mentions, or text limits?" | Raw Slate exposes primitives; product UX belongs above it, likely in Plate/app packages. | Built-in product input policy in the raw Slate Mobile/IME runtime. | Section 7 public API target; input-controller.ts:75, :170, :230, :246 | keep |
Pass-9 decision:
Keep:
editor.dom.isComposing(): boolean;useEditorComposing(): boolean;onDOMBeforeInput?: (event: InputEvent) => boolean | void;Do not add yet:
Decision: the public API is not the current blocker. The issue pass may propose new narrow extension points only if a concrete row proves existing hooks cannot express the behavior without DOM/model drift.
Target:
Already done in live source:
runtime-root-engine.ts, runtime-event-engine.ts,
input-controller.ts, runtime-composition-events.ts,
runtime-android-engine.ts, runtime-input-events.ts, and input-router.ts.Gap:
Target:
Evidence:
.tmp/slate-v2/packages/slate-react/src/editable/input-controller.ts:89;useEditorComposing is public docs surface in
.tmp/slate-v2/docs/libraries/slate-react/hooks.md:7.Gap:
Plate should inherit:
Plate should not get:
Pass-9 status: backbone and adoption wording reviewed; adapters still out of scope.
Evidence:
.tmp/slate-v2/packages/slate/test/migration-backbone-contract.ts:33 proves
extension state / tx namespaces and schema specs without adapter-shaped
api, tf, plate, yjs, or feature fields on the editor surface..tmp/slate-v2/packages/slate/src/core/editor-runtime.ts:97 exposes snapshot,
runtime-id, selection, subscribe, read, and update runtime groups behind one
internal runtime..tmp/slate-v2/packages/slate/test/commit-metadata-contract.ts:18 and :109
prove update tags, selection before/after, dirty runtime IDs, and typed
metadata.Decision: Plate migration pressure reinforces the current primitive substrate. Do not add Plate-shaped editor APIs to raw Slate from this Mobile/IME plan. PR/adoption language should say Plate can wrap the substrate, not that this plan ships current-version Plate integration.
Yjs/collab cares about deterministic local commits, selection metadata, and composition lifecycle boundaries.
Target:
Status: ecosystem wording reviewed; current-version yjs adapter work remains out of scope.
Evidence:
.tmp/slate-v2/packages/slate/test/migration-backbone-contract.ts:171 replays
deterministic operations with commit tags and local-only runtime targets..tmp/slate-v2/packages/slate/test/collab-history-runtime-contract.ts:30
publishes one commit truth for collab subscribers, extension listeners, and
history..tmp/slate-v2/packages/slate/test/collab-history-runtime-contract.ts:155
uses typed remote collaboration metadata to skip local undo history.Decision: yjs/collab needs deterministic operations, commit metadata, and local-only target semantics. It does not need Mobile/IME product policy or browser-event timing encoded into raw collaboration APIs.
Current corpus facts:
682 rows in
docs/slate-issues/open-issues-ledger.md:18.630 open issues in
docs/slate-issues/gitcrawl-live-open-ledger.md:12.129 issues, cluster-synced, no per-device closure
without device proof in docs/slate-issues/open-issues-ledger.md:84.21.37 in
docs/slate-issues/issue-clusters.md:46.slate-react-v2
plus slate-dom-v2 in
docs/slate-issues/requirements-from-issues.md:247.slate-react-v2 + slate-dom-v2, with
124 runtime rows in docs/slate-issues/package-impact-matrix.md:75.ClawSweeper related-issue pass:
gitcrawl doctor --json reports 659 open Slate threads, 617
clusters, last_sync_at: 2026-05-04T14:58:11.123944Z,
api_supported: false, and no GitHub token;149 rows, all cluster-synced;117 high, 32 medium;80 ready-with-minor-setup, 45 ready-now,
24 not-a-test-candidate;119 current keyword rows with the pass-2
filter; treat this as candidate generation because keyword matching includes
adjacent selection, placeholder, spellcheck, and false-positive rows;28 current input-runtime/input-related rows found;26 existing v2-input-runtime sections found;Fixes or Improves additions;Dossier output:
#6022, #5983, #4400, #5883,
#6051, #3777, #5095, #5096, #5603, #5669, #4994, #5026,
#4001, #5989, #5984, #5931, #5830, #5643, #5130, #5050,
#5014, #4348, #4223, #4067, #3568, and #3470;related;44 of the 123 R7 rows missing from current dossier
coverage need long-form dossier/proof-route sections, while 79 stay
matrix-only for now.Issue-ledger pass:
149;23 R7 rows;3;44;59;20;Fixes or Improves additions from this pass.Pass-3 routing matrix:
| Route | Count | Rows | Durable follow-up |
|---|---|---|---|
| Existing matrix and dossier | 23 | #6022, #5989, #5984, #5983, #5931, #5883, #5830, #5643, #5281, #5183, #5130, #3777, #3497, #3478, #3150, #5088, #5050, #5014, #4994, #4400, #4223, #4067, #4001 | Drift-check only; do not promote claims without proof. |
| Existing dossier, matrix backfill needed | 3 | #5711, #3634, #4961 | Done in pass 11 as related matrix rows. |
| Needs long-form dossier and proof route | 44 | #5891, #5836, #5805, #5680, #5666, #5653, #5493, #5375, #5371, #5291, #5175, #5173, #5167, #3873, #3695, #3611, #3587, #5099, #5083, #5078, #5034, #5023, #4959, #4861, #4770, #4719, #4693, #4640, #4602, #4543, #4531, #4521, #4372, #4354, #4353, #4269, #4232, #4136, #4085, #4031, #4030, #3943, #3942, #3882 | Write dossier sections before any PR claim; most require browser/device proof. |
| Matrix-only future proof | 59 | #5697, #5639, #5611, #5569, #5487, #5484, #5481, #5433, #5430, #5420, #5398, #5380, #5274, #5213, #5181, #5152, #3878, #3858, #3821, #3742, #3696, #3601, #3582, #3432, #3412, #3354, #3325, #3317, #3162, #5117, #5010, #5004, #4795, #4738, #4721, #4712, #4704, #4696, #4681, #4673, #4560, #4541, #4495, #4466, #4323, #4317, #4316, #4309, #4094, #4046, #4010, #3947, #3929, #3926, #3917, #3911, #3909, #3893, #1498 | Keep matrix accounting; promote only if a later proof slice targets the row. |
| Matrix-only non-claim | 20 | #5418, #5207, #3781, #3780, #3760, #3618, #3460, #3304, #3303, #3222, #3177, #4621, #4457, #4426, #4233, #4165, #4089, #4081, #2564, #2465 | Keep out of PR auto-close language; use as policy/API pressure only. |
Claim-level drift found:
| Issue | Matrix claim | Dossier status | Decision |
|---|---|---|---|
#6022 | Related | related | Aligned in pass 11; current plan does not promote Android mark-toggle without device proof. |
#5983 | Related | related | Aligned in pass 11; current plan does not promote Android voice input without device proof. |
#5183 | Related | related | Aligned in pass 11; Android keyboard activation still needs exact device proof for Mobile/IME claim. |
#5088 | Related | related | Aligned in pass 11; not a Mobile/IME exact claim in this plan. |
Pass-11 drift result: all four dossier statuses now align down to related.
No row was promoted.
Research/source refresh effect on issue-ledger accounting:
44 long-form rows remain long-form proof-route rows. Pass 5 proves
routing and owner fit; it does not prove issue closure.#5989,
#5983, #5891, #5883), Android Chinese delete / duplicate insertion
(#5984, #5083, #5078, #5034, #5023), Android autocorrect /
suggestion replacement (#4531, #5653), Android heading Enter / block type
rows (#4521, #5175), inline-boundary IME rows (#4693, #4136), and
empty-editor IME rows (#4030, #3943, #3882).related until exact proof
decides whether to promote.Fixed issues:
Materially improved issues:
Related but not fixed initial seed:
| Issue | Cluster | Initial claim | Why | Proof route | Live ledger sync | PR line |
|---|---|---|---|---|---|---|
#6051 | singleton | Related | Firefox Android + Samsung Keyboard live issue, no exact proof yet | raw Android Firefox/Samsung keyboard proof | synced macro note | related matrix only |
#6022 | 9 | Related | Android mark-toggle keyboard/caret failure, linked PR cluster | Android mark-toggle + typing proof | synced macro note | related matrix only |
#5989 | singleton | Related | Hangul placeholder composition, ready-with-minor-setup | Android Hangul placeholder composition proof | synced macro note | related matrix only |
#5984 | singleton | Related | Android Chinese backspace and one-change expectation | Android Chinese IME deletion proof | synced macro note | related matrix only |
#5983 | 11 | Related | Android voice input duplication in empty editor | Android voice input proof or explicit tooling gap | synced macro note | related matrix only |
#5974 | singleton | Related | Chrome iPhone emulator Chinese input is blocked-on-repro | emulator-specific repro decision | synced macro note | related matrix only |
#5931 | singleton | Related | Windows suggestions append instead of replace | Windows text suggestion acceptance proof | synced macro note | related matrix only |
#5918 | singleton | Needs repro | Vietnamese Windows IME row is blocked-on-repro | Windows Vietnamese repro first | synced macro note | related matrix only |
#5891 | singleton | Related | Android first-line autocorrect | Android autocorrect proof | synced macro note | related matrix only |
#5183 | 12 | Related | Android inline void keyboard summon | raw Android inline void keyboard proof | synced macro note | related matrix only |
#5130 | singleton | Related | Android Firefox predictive typing | Android Firefox predictive typing proof | synced macro note | related matrix only |
#4400 / #5883 | 13 | Related | Android empty-node composition family | Android empty-node composition proof | synced macro note | related matrix only |
#5603 / #5669 | 16 | Related | Native input event missing at boundaries | native input event parity proof | synced macro note | related matrix only |
#4994 / #5026 | 18 | Related | Android readOnly change/input ops | Android readOnly transition proof | synced macro note | related matrix only |
Primary R7 families discovered in pass 2:
| Family | Rows | Issues |
|---|---|---|
| Focus/external DOM ownership | 16 | #3821, #3742, #3696, #3634, #3601, #3582, #3497, #3412, #4010, #3947, #3929, #3926, #3917, #3911, #3909, #3893 |
| Mobile selection/input sync | 10 | #6022, #5836, #5805, #5493, #5371, #5130, #3587, #5083, #4030, #3943 |
| Controlled/external value updates | 9 | #5418, #5281, #5207, #3878, #3858, #3478, #3325, #4323, #4094 |
| Mobile text composition | 6 | #5023, #4693, #4353, #4316, #4269, #4223 |
| Placeholder/empty-editor IME | 6 | #3777, #4067, #4031, #4001, #3942, #3882 |
| Mobile empty-state input | 5 | #5983, #5891, #5883, #5711, #5099 |
| Android input manager regressions | 4 | #5175, #5167, #4621, #4400 |
| Composition/focus lifecycle | 3 | #5830, #5653, #4232 |
| Upstream browser/React event gaps | 3 | #3304, #3303, #3150 |
Two-row R7 families:
#5034, #4994;#5152, #5010;#5213, #4696;#5004, #4560;#5050, #4795;#4531, #4354;#5984, #4959;#5989, #4136;#5481, #4640;#5420, #4673;#3222, #3177;#3354, #3162;#5433, #5398;#2564, #2465;#5430, #5380.One-row R7 families:
57 one-row families remain. Do not explode them into claims in discovery
pass. Pass 3 routed them as matrix rows, dossier rows, or explicit
non-claims.Current live high-signal rows not fully claimable yet:
| Group | Rows |
|---|---|
| Existing related matrix anchors | #6051, #6022, #5989, #5984, #5983, #5974, #5931, #5918, #5891, #5183, #5130, #4400, #5883, #5603, #5669, #4994, #5026 |
| Newly surfaced live rows for issue-ledger routing | #5805, #5836, #5680, #5666, #5493, #5643, #5639, #5398, #5391, #5175, #5178, #5173, #5099, #5078, #5034, #5023, #4693, #4521, #4354, #4232, #4136, #4030, #3943, #3882, #4466, #4372 |
Live gitcrawl ledger sync:
149 routed rows, 44
long-form proof-route rows, 59 matrix-only future-proof rows, 20
matrix-only non-claim rows, 3 matrix backfills, and 4 drift rows aligned
down to related.Fork issue dossier sync:
#6022, #5983, #5183, and #5088 now align with the
conservative related matrix claim.Issue coverage matrix sync:
#5711, #3634, and #4961 were added as related
matrix rows; a Mobile/IME macro planning sync table records the `23 + 3 + 44
PR description:
154 related issue matrix rows,
the Mobile/IME macro counts, and 0 new exact fixed/improved Mobile/IME
claims from this plan.| Class | Current evidence | Gap | Claim rule |
|---|---|---|---|
| Desktop IME commit | .tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts:401 composes Japanese text and asserts model text at :428 | Does not prove Android/iOS | Desktop IME only |
| Generated composition trace | .tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts:431 runs composition gauntlet; mobile claim is explicitly mobile-synthetic-composition at :477 | Needs raw-device promotion | Architecture confidence only for mobile |
| Selection repair during composition | .tmp/slate-v2/playwright/stress/generated-editing.test.ts:1027 synthetic stress row | Needs language/device rows | Stress confidence only |
| DOM coverage + composition | .tmp/slate-v2/playwright/integration/examples/dom-coverage-boundaries.test.ts:248 skips mobile for IME; .tmp/slate-v2/packages/slate-dom/test/dom-coverage.ts:347 blocks boundary materialization while composing | Mobile hidden-boundary IME proof | Desktop/unit proof only |
| Mobile touch around hidden boundaries | .tmp/slate-v2/playwright/integration/examples/dom-coverage-boundaries.test.ts:283 is mobile touch proof, not IME proof | Needs IME/device input rows | Touch usability only |
| Android zero-width / composition | .tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts:1207 carries Android zero-width composition handling | Needs issue exactness | Source evidence, not closure |
| Android manager | .tmp/slate-v2/packages/slate-react/src/editable/runtime-android-engine.ts:8 delegates to Android input manager | Needs feature-specific rows | Owner evidence, not closure |
Proof tiers:
No exact issue closure may skip the tier matching the reported environment.
Pass-5 proof inventory conclusion:
Cross-editor tests to steal before execution:
../lexical/packages/lexical-playground/__tests__/e2e/Composition.spec.mjs
into Slate browser scenarios where the current editor.ime.compose helper is
too coarse.8153-safari-ime-delete-selection.spec.mjs as WebKit regression gates; both
translated richtext rows landed in slice 24.Pass-6 performance and native-behavior contract:
| Surface | Budget / contract | Evidence | Remaining gap |
|---|---|---|---|
| Cohorts | normal 0-500, medium 500-2000, large 2000-10000, stress 10000-50000, plus complexity tags for custom renderers, decorations, hidden boundaries, inline voids, collaboration, mobile/IME | performance/rules/cohort-segmentation.md | Attach cohort tags to each implementation slice. |
| Repeated unit | hot unit is top-level block/root group; avoid per-block input listeners and broad React subscriptions | runtime-root-engine.ts:136, :188, :214, :246, input-router.ts:91, public-state.ts:2483 | Record DOM/component/listener/memory tags in large/stress proof. |
| React runtime | use refs for transient state, selector-scoped updates, and root-level native listeners; keep typing/selection/IME urgent | runtime-root-engine.ts:136, :188, :266, root-selector-sources.ts:110, :196, :208 | React Performance Tracks only if React work breadth becomes suspicious. |
| Render budgets | stress rows already assert no broad editable rerender for mention movement, projection selection, and mouse selection toolbar | generated-editing.test.ts:221, :947, :1020 | Add exact Mobile/IME rows before issue closure. |
| Native behavior | faster modes must classify browser find, screen-reader traversal, native selection, copy/paste, select-all, IME, mobile touch, undo/history, collaboration, and follow-up typing | performance/rules/editor-native-behavior-proof.md | This contract is not yet attached to every routed issue family. |
| Degradation | optimize DOM-present normal/medium path first; shell/virtualized behavior is explicit large/stress policy, not default Mobile/IME proof | performance/rules/degradation-contract.md, root-selector-sources.ts:228 | Need per-mode behavior table before implementation. |
| Migration | commit metadata and deterministic operation replay are the substrate proof | commit-metadata-contract.ts:18, migration-backbone-contract.ts:171, collab-history-runtime-contract.ts:30 | No current-version Plate/yjs adapter promise from this plan. |
Pass-10 execution contract for issue sync:
| Accepted revision | Final rule for issue-sync text | Claim effect |
|---|---|---|
| Proof-heavy batching | Sync the strongest proof-routed rows first; do not write all 44 long-form rows as if they are fixes. | Keeps unproven rows Related, Needs repro, or matrix-only. |
| Synthetic labels | Preserve synthetic in proof labels and PR text. | Synthetic mobile never becomes exact Android/iOS closure. |
| Raw-device proof | Match Samsung Keyboard, Android Firefox, voice input, iOS Chinese, Windows IME, or other reported environments before exact closure. | Device-specific rows stay non-claims without matching artifacts. |
| Performance evidence | Attach cohort, repeated-unit, listener, DOM/component, memory, and native-behavior evidence to large/stress claims. | Blocks broad performance language from narrow repro proof. |
| Adapter ownership | Say Plate/yjs can wrap the raw Slate substrate; do not say current adapters are complete. | Keeps adapter work out of raw Slate issue claims. |
| High-risk failure modes | Require per-slice checks for data loss, duplicate input, caret corruption, public API lock-in, false mobile claim, React hot-path regression, collab/history nondeterminism, and native behavior regression. | Any failure downgrades or splits the issue claim. |
| Ecosystem wording | Use typed state / tx, runtime registration, commit listeners, selector hooks, and composition primitives as the adoption story. | Rejects public command slots and Mobile/IME product policy. |
| Ledger order | Sync matrix/dossier/PR reference after proof boundaries and revision decisions settle. | Prevents optimistic durable claim text. |
| Lens | Applicability | Reason | Current finding | Plan delta |
|---|---|---|---|---|
vercel-react-best-practices | applied pass 6 | React runtime, subscriptions, event listeners, and performance are in scope | Relevant rules are client-event-listeners, rerender-use-ref-transient-values, rerender-defer-reads, and advanced-event-handler-refs; current source mostly follows them with root native listeners and ref-owned transient state | Keep runtime outside per-node React state; do not add per-row listeners or broad subscriptions. |
performance-oracle | applied pass 6 | Hot input path, repair, selection, large docs | Main risk is not obvious O(n^2) code in the current input runtime; risk is unbounded repeated-unit DOM/subscription/memory growth during proof and issue-specific fixes | Every implementation slice needs cohort, repeated-unit, memory/DOM, and interaction tags. |
performance | applied pass 6 | Mobile/IME and rendering strategy claims need cohorting, repeated-unit budgets, native behavior contracts, and degradation rules | Existing render-budget stress rows are useful, but no full Mobile/IME cohort/INP/memory table exists yet | Add the pass-6 performance/native behavior contract as execution acceptance criteria. |
tdd | applied pass 6 | Behavior/regression classes need tests before fixes | Use vertical public proof rows; do not write all 44 tests first | First implementation batch should start with one high-signal issue class and one failing/characterization proof row. |
regression-lock-pass | applied pass 6 | Browser input and migration behavior are high regression risk | Existing contracts lock commit metadata, migration backbone, collab/history, target runtime, render budgets, and synthetic/mobile proof classes | Missing exact device/browser rows stay non-claims. |
code-simplicity-reviewer | applied pass 6 | The plan could overgrow into a Mobile/IME framework | Simpler answer is keep the shared input runtime, add proof/budget contracts, and reject a new public namespace | Do not add new abstraction until a routed issue proves the existing primitive hooks cannot express the behavior. |
build-web-apps:shadcn | skipped | No UI/editor chrome change | N/A | Keep UI out unless examples/debug chrome change |
react-useeffect | applied pass 6 | Effects/listeners/browser APIs are in scope | Native listeners attach/detach through root ref; source subscriptions are centralized | Future edits must not add derived-state effects or repeated-unit subscriptions. |
Status: complete for pass 8.
Trigger: yes. This plan touches selection, focus, IME, DOM repair, browser runtime behavior, React runtime strategy, migration substrate, collaboration metadata, public proof claims, issue ledgers, and release gates.
Current high-risk source owners refreshed in pass 8:
.tmp/slate-v2/packages/slate-react/src/editable/runtime-root-engine.ts:136,
:188, :199, :214, :246, :253, :283, :289, and :345;.tmp/slate-v2/packages/slate-react/src/editable/runtime-input-events.ts:52,
:79, :89, :106, and :135;.tmp/slate-v2/packages/slate-react/src/editable/runtime-composition-events.ts:36,
:71, and :106;.tmp/slate-v2/packages/slate-react/src/editable/input-controller.ts:75,
:121, :170, :230, and :246;.tmp/slate-v2/packages/slate-dom/src/plugin/dom-editor.ts:82, :161,
:811, :1207, :1227, :1440, and :1511;.tmp/slate-v2/package.json:58, :59, :60, and :63;.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts:401,
:431, and :477;.tmp/slate-v2/playwright/integration/examples/dom-coverage-boundaries.test.ts:248
and :283;.tmp/slate-v2/packages/slate/test/commit-metadata-contract.ts:18, :84,
:109, and :144;
.tmp/slate-v2/packages/slate/test/migration-backbone-contract.ts:33 and
:171;
.tmp/slate-v2/packages/slate/test/collab-history-runtime-contract.ts:30,
:114, and :155.Blast radius:
| Area | Files / owners | Users or consumers | Affected behavior | Required stop rule |
|---|---|---|---|---|
| Input runtime | slate-react/src/editable/*, input-router.ts, input-controller.ts, runtime-input-events.ts, runtime-composition-events.ts | end users typing on desktop/mobile, app authors using raw Slate | beforeinput/input, composition, delete, history, format, internal controls | Any text duplication, dropped input, or untraced ownership transition blocks a claim. |
| Selection / DOM bridge | slate-dom/src/plugin/dom-editor.ts, selection import/export, repair runtime | end users, screen-reader/native selection users, browser integrations | caret, range translation, copy/paste, select-all, browser find, IME offsets | Exact issue claim needs browser/device proof for the reported environment. |
| Android / mobile | Android input manager, runtime-android-engine.ts, mobile proof scripts | Android/iOS/Samsung/Firefox Android/voice-input users | keyboard summon, predictive typing, voice input, zero-width composition | Raw-device or matching manual artifact required before exact closure. |
| React performance | root runtime refs, selector sources, render-budget stress rows | large-document users, Plate adopters, shell/virtualized consumers | rerenders, listener count, DOM churn, memory, INP-like interaction cost | Large/stress claim needs cohort plus repeated-unit evidence. |
| Collaboration / migration | commit metadata, operation replay, collab/history contracts | Plate, slate-yjs, collaboration adapters, extension authors | deterministic commits, undo/history, remote metadata, local-only target semantics | No adapter-shaped raw API; downgrade if a runtime fix creates nondeterministic commits. |
| Ledgers and PR text | issue matrix, fork dossier, live gitcrawl ledger, PR reference | maintainers, reviewers, issue reporters | Fixes / Improves / Related language and release proof | Sync after proof boundaries settle; no optimistic claim promotion. |
Pre-mortem:
| Scenario | What breaks | Why it is plausible | Guard | Verdict |
|---|---|---|---|---|
| Data loss or duplicate text during composition | IME commits twice, deletes the wrong span, or drops the final text | beforeinput, DOM input, React input, Android pending diffs, and repair can all observe the same user action | Kernel trace plus unit/browser proof around runtime-input-events.ts:52, :79, :89, and composition rows | keep, but any duplicate/drop blocks claim |
| Caret jump or wrong range import | Selection moves after composition, hidden boundaries, inline voids, or Android zero-width text | DOM range translation has browser and Android compatibility paths | Browser/device rows must cover toSlatePoint/toSlateRange paths and visible caret/model selection | keep, with exact environment gate |
| Wrong public API gets frozen | A device-specific hook solves one bug and becomes permanent raw Slate policy | Mobile/IME bugs are emotionally urgent and app authors want an escape hatch | No new public namespace; new primitive only after a routed red proof row proves existing hooks fail | keep, API additions require revision pass |
| False mobile closure | Synthetic mobile composition passes but Samsung Keyboard, Android Firefox, voice input, or iOS Chinese still fails | Existing tests explicitly label mobile synthetic proof | PR and ledger text must preserve synthetic labels and raw-device gates | keep, no exact mobile claim |
| React hot-path regression | Fix adds per-block listeners, broad subscriptions, or repeated DOM scans | Input bugs often tempt local event handlers near the failing node | Cohort, repeated-unit, listener, DOM, memory, and render-budget evidence before large/stress claims | revise execution acceptance |
| Collab/history nondeterminism | Composition or repair produces commits remote replay cannot reproduce | DOM-derived timing can leak into model writes | Commit metadata, deterministic replay, and collab/history tests gate any runtime fix | keep substrate, block adapter claims |
| Native behavior regression | Model-owned input breaks browser find, copy/paste, select-all, screen-reader traversal, undo/history, or follow-up typing | Faster modes and repair can steal browser ownership | Native-behavior matrix must travel with each implementation slice | revise execution acceptance |
Expanded proof plan:
| Proof tier | Required rows | Existing evidence | Gap before claim |
|---|---|---|---|
| Unit/runtime | input intent, internal-control classification, composing state, Android manager decisions, DOM bridge offsets, commit metadata, collab replay | input-controller.ts:75, :121, :170, :230, :246; commit-metadata-contract.ts:18, :109; collab-history-runtime-contract.ts:30, :114, :155 | Add issue-specific red/characterization rows before a fix. |
| Browser integration | native beforeinput/input/composition, selection import/export, hidden boundaries, copy/paste, undo/history, internal controls | rendering-strategy-runtime.test.ts:401, :431; dom-coverage-boundaries.test.ts:248 | Cross-browser rows for exact issue classes, not only generic IME. |
| Raw mobile / manual | Android/iOS, Samsung Keyboard, Android Firefox predictive typing, Gboard/autocorrect/voice, iOS Safari Chinese, Windows IME when relevant | package.json:59, :60, :63 provide proof lanes | Real artifact required before exact device closure. |
| Stress/performance | normal/medium/large/stress cohorts, repeated top-level unit, listener/DOM/memory/render budgets | generated-editing.test.ts:221, :947, :1020; Section 14 pass-6 performance contract | Attach the budget to each implementation slice that claims large/stress safety. |
| Migration/adoption | deterministic operations, commit tags, local-only runtime targets, typed remote metadata, no adapter-shaped raw fields | migration-backbone-contract.ts:33, :171; collab-history-runtime-contract.ts:30, :155 | Plate/yjs adapter fixtures remain later work. |
| Docs/examples/PR | proof labels, supported claim text, proof-harness docs, non-claim rows | Section 12 issue routing, Section 18 objection ledger, Section 24 handoff outline | Sync only after proof boundaries and revision decisions settle. |
Rollback / hard-cut / remediation answer:
Related / Needs repro;
do not sync optimistic claim text.High-risk verdict:
Hard cuts:
Editable restoration;Rejected:
| Change / decision | Who feels pain | Likely objection | Steelman antithesis | Tradeoff | Answer | Evidence | Verdict |
|---|---|---|---|---|---|---|---|
| Keep exact mobile closures gated on raw-device proof | Maintainers, users waiting on Android/iOS fixes | "This slows closure." | Desktop proof catches many bugs faster. | Some rows stay pending longer. | Better slow than dishonest. Mobile keyboard behavior is the bug. | docs/research/decisions/slate-v2-post-closure-architecture-review.md:58 | keep |
| Keep product input policy out of raw Slate | App authors | "I need autocomplete/text-limit/slash command behavior." | Product hooks are useful. | Apps must compose behavior above Slate. | Raw Slate should expose safe runtime primitives; Plate can package product UX. | docs/research/sources/editor-architecture/tiptap-extension-command-react-dx.md:80 | keep |
| Use current runtime owner graph rather than restart architecture | Browser/runtime maintainers | "Existing runtime may still have holes." | A cleaner rewrite could be tempting. | We inherit current source constraints. | The live graph already matches the issue pressure; proof/accounting is weaker than architecture direction. | runtime-root-engine.ts:136, runtime-event-engine.ts:162 | keep |
| Keep raw-device proof as the closure gate | Release maintainers | "Device proof is too slow for a plan with 44 long-form rows." | Synthetic mobile and desktop IME proof would let the team ship faster. | Real device rows need hardware, tooling, or lab work. | Synthetic rows can route architecture, but PR text must not claim Android/iOS/Samsung/Firefox Android/voice closure until raw-device or matching manual artifacts exist. | .tmp/slate-v2/package.json:59, :60, :63; rendering-strategy-runtime.test.ts:477 | keep |
Stop after proof-heavy batches instead of all 44 rows | Plan/execution maintainers | "The dossier will drown the implementation before code starts." | Full accounting up front sounds safer. | Some related rows stay matrix-only longer. | Batch the highest-proof rows first, then sync claim text. Long-form text without proof routes is theater. | Section 12 pass-3 routing matrix; Section 14 proof tiers | revise |
| Keep Android-specific ownership centralized | Browser/runtime maintainers | "The architecture already has Android special casing, so it is not clean." | A generic runtime with no platform owner sounds purer. | Android remains a named runtime owner. | The honest architecture has a small Android owner wired through the root runtime, not scattered public device APIs. | .tmp/slate-v2/packages/slate-react/src/editable/runtime-android-engine.ts:8; runtime-root-engine.ts:246 | keep |
| Reject a broad Mobile/IME public namespace | API maintainers, app authors | "Without a public namespace, authors cannot solve local input bugs." | More public hooks can feel more empowering. | Some app escape hatches stay lower-level. | Add a new primitive only when a routed issue proves onDOMBeforeInput, composing state, input rules, and internal-control classification cannot express the behavior. | Section 7 public API target; input-router.ts:91; input-controller.ts:89 | keep |
| Require cohort plus repeated-unit performance evidence | Performance reviewers | "This is too much process for input bugs." | A targeted browser repro can catch the visible bug. | More evidence work before large/stress claims. | Input fixes can silently add repeated listeners, subscriptions, or DOM churn; large/stress claims need cohort, DOM/component/listener/memory, and native-behavior rows. | Section 14 pass-6 performance contract; runtime-root-engine.ts:136, :188, :266 | revise |
| Keep Plate/yjs adapters out of raw Slate closure | Plate/yjs maintainers | "Migration talk without adapters is evasive." | Adapter fixtures would make adoption feel real. | Raw Slate cannot prove current Plate/yjs integration end-to-end from this plan. | This plan owns the substrate: state / tx, deterministic commits, local-only targets, commit metadata, and typed remote metadata. Adapter work is a later owner. | migration-backbone-contract.ts:33, :171; collab-history-runtime-contract.ts:30, :155 | keep |
| Keep issue-sync after proof boundaries settle | Release maintainers | "Ledger sync should happen immediately so the plan looks current." | Early sync gives an audit trail sooner. | Sync waits until claim text is stable. | Pass 11 synced after high-risk/revision passes so the durable files do not encode claims that proof later downgrades. | Section 12 drift rows; Section 25 final gates | revise |
| Label synthetic mobile proof explicitly | PR reviewers | "A mobile test name will be read as real mobile proof." | Shorter labels are easier to scan. | More verbose proof labels and PR text. | Any viewport or synthetic event row must say synthetic; exact device language is reserved for raw-device/manual artifacts. | rendering-strategy-runtime.test.ts:477; Section 14 proof tiers | revise |
| Keep fork dossier private until claims are exact | Maintainers reading upstream PRs | "A giant fork-local dossier is not a substitute for upstream comments." | Upstream issue comments create visible accountability. | Less immediate upstream signaling. | The fork dossier is planning/accounting, not upstream comment spam. PR text should link exact claims and proof, not dump every related row. | Required artifacts in slate-ralplan; Section 24 handoff outline | keep |
| Stop the review loop after scheduled gates | User, execution owner | "This can become infinite planning." | More review can always find another caveat. | Remaining risk must be handled by proof during execution. | After high-risk, ecosystem, revision, issue-sync, and closure gates, hand to ralph; do not add more broad review passes unless a gate finds a concrete contradiction. | Section 19 pass schedule; Section 22 owners | revise |
Pass-7 revisions accepted:
44 long-form rows
before code;ralph unless a concrete contradiction appears.Status: complete for pass 7. No objection invalidated the shared input-runtime owner model, but several objections tightened claim labels, batching, performance proof, and adapter ownership.
| Pass | Status | Evidence added | Plan delta | Open issues | Next owner |
|---|---|---|---|---|---|
| 1. Current-state read and initial score | complete | live source, issue ledgers, test proof, research pages | created this macro plan and set score 0.77 | all issue classifications pending | clawsweeper |
| 2. Related issue discovery | complete | gitcrawl doctor, frozen R7 extraction, live keyword sweep, existing matrix/dossier counts | score to 0.80; added 149-row R7 family map and high-signal live row set | durable per-row matrix/dossier routing | slate-ralplan |
| 3. Issue-ledger pass | complete | 149-row routing, 44 long-form rows, 79 matrix-only rows, 3 matrix backfills, 4 drift rows | score to 0.84; added durable routing table | durable file sync completed in pass 11 | slate-ralplan |
| 4. Intent/boundary and decision brief | complete | pass-3 routing pressure test, stop rules, decision locks | score to 0.87; hardened intent, non-goals, decision boundaries, and decision brief | research/source evidence was routed to pass 5 | slate-ralplan |
| 5. Research/source refresh | complete | current source/test/proof-script refresh, compiled research refresh, representative issue dossier refresh | score to 0.89; ecosystem table now has a pass-5 evidence ledger | exact device/browser artifacts still missing for claims | slate-ralplan |
| 6. Performance/DX/migration/regression/simplicity passes | complete | live runtime perf source, Vercel/performance rules, migration/collab/commit contracts, render-budget stress rows, simplicity review | score to 0.91; added cohort/repeated-unit/native-behavior contract and migration proof boundaries | maintainer objection rows routed to pass 7 | slate-ralplan |
| 7. Maintainer objection ledger | complete | steelman rows for device proof, batching, public API, Android ownership, performance proof, adapter ownership, issue sync, synthetic labels, fork dossier, and review-loop stop | score to 0.92; accepted revisions for batching, synthetic labels, performance evidence, adapter ownership, and scheduled-gate stop | high-risk proof failures routed to pass 8 | high-risk-deliberate-pass |
| 8. High-risk deliberate pass | complete | refreshed runtime/proof source owners, blast-radius table, seven-scenario pre-mortem, expanded proof plan, rollback/remediation rules | score stays 0.92; regression and research dimensions strengthened; execution slices now require failure-mode tables | ecosystem adoption language routed to pass 9 | slate-ralplan |
| 9. Ecosystem maintainer pass | complete | extension author, Plate, slate-yjs/collab, React shell, release/PR, and product-plugin adoption rows | score to 0.93; adoption language now says substrate/proof gates, not adapter completion or product policy | accepted revisions routed to pass 10 | slate-ralplan |
| 10. Revision pass | complete | consolidated accepted pass-7/pass-8/pass-9 revisions into the execution contract, decision locks, hard cuts, scorecard, and phase order | score to 0.94; issue-sync now has one conservative claim contract | ledger/dossier/PR sync completed in pass 11 | slate-ralplan |
| 11. Issue sync accounting | complete | matrix backfills for #5711, #3634, #4961; dossier macro sync; live ledger and cluster sync notes; PR reference summary update | score to 0.95; conservative claim text is durable across matrix, dossier, live ledgers, and PR reference | closure score/final gates only | slate-ralplan |
| 12. Closure score and final gates | complete | final gate reread, synced-file consistency check, pass ledger check, PR reference check, completion-check rerun | completion state set to done; plan ready for user review and later ralph execution planning | none for Ralplan | user review |
| 13. Cross-editor IME/mobile test mining | complete | local ../lexical and ../prosemirror IME/mobile source and tests | added stolen-test backlog for execution; score stays 0.95 | none for Ralplan; execution must translate missing rows before claiming fixes | user review |
Added in pass 1:
v2-input-runtime bucket plan;0.77;Dropped in pass 1:
No-change defense:
Added in pass 2:
gitcrawl doctor freshness and the local live keyword candidate
count;149 rows, all
cluster-synced;28 input-runtime matrix rows and 26
dossier sections;0.80.Dropped in pass 2:
Added in pass 3:
149 frozen R7 input-runtime rows;44 missing-dossier rows need long-form dossier/proof-route sections;59 rows stay matrix-only future proof rows;20 rows stay matrix-only non-claim rows;3 existing dossier rows that need matrix backfill;4 matrix/dossier claim-level drift rows;0.84.Dropped in pass 3:
Fixes or Improves claims;Added in pass 4:
44 long-form rows proof-route backlog, not claim backlog;20 matrix-only non-claim rows explicit non-execution pressure;0.87.Dropped in pass 4:
Added in pass 5:
slate-dom composing/Android offset handling;44
long-form proof backlog;0.89.Dropped in pass 5:
Added in pass 6:
state / tx namespaces, deterministic operation replay, commit metadata,
and local-only runtime targets;44 long-form rows;0.91.Dropped in pass 6:
Added in pass 7:
3 seed rows to 13 reviewed
decisions;0.92.Dropped in pass 7:
Added in pass 8:
.tmp/slate-v2 source and proof files;0.92.Dropped in pass 8:
Added in pass 9:
state / tx groups, runtime registration,
commit listeners, commit metadata, selector hooks, and composition primitives
without public command slots or Mobile/IME product policy;0.93.Dropped in pass 9:
Added in pass 10:
0.94.Dropped in pass 10:
Fixes or Improves claim promotion from revision cleanup.Added in pass 11:
#5711,
#3634, and #4961;#6022, #5983, #5183, and #5088
down to related;0 new exact fixed/improved Mobile/IME claims;0.95.Dropped in pass 11:
Fixes #... or Improves #... claims;44 proof-backlog rows into fake closure text;Added in pass 12:
ralph owner;Dropped in pass 12:
Added in pass 13:
../lexical IME/mobile composition E2E, history, Safari
regression, Android/iOS timing, autocorrect, and Korean backspace evidence;../prosemirror transaction metadata, DOM-change, composition
viewdesc, and DOM-change webtest evidence;.tmp/slate-v2 composition proof and added a
stolen-test execution backlog for missing rows.Dropped in pass 13:
Open questions:
44 long-form rows can be closed with existing browser/unit
proof after exact repro mapping, and which need new raw-device proof?4 drift rows should be promoted in a later execution batch if
exact proof appears?ralph execute first after user acceptance?What would change the decision:
No implementation starts from this pass.
Draft phase order after plan closure:
ralph execution planning after acceptance.Owners:
slate-ralplan;clawsweeper for pass 2, complete;ralph continuation;slate-react-v2 and
slate-dom-v2 packages in .tmp/slate-v2.Use focused gates after implementation slices, not during this planning pass:
cd /Users/zbeyens/git/slate-v2
bun test ./packages/slate-dom/test/dom-coverage.ts
bun test:stress
bun test:integration-local --project=chromium --grep "composition|IME|input"
bun test:mobile-device-proof
Closure gates may require:
cd /Users/zbeyens/git/slate-v2
bun check
bun check:full
bun test:mobile-device-proof:raw
Use bun test:mobile-device-proof:raw only on a machine/device lane that can
provide real Android/iOS artifacts.
Accepted runtime owner model:
slate-react input runtime plus slate-dom bridge as
the owner for Mobile/IME/input behavior.runtime-android-engine.ts
through the root runtime.Public API:
state / tx extension
groups.Issue accounting:
0.0.149.23.3 (#5711, #3634, #4961).44.59.20.related: 4 (#6022, #5983, #5183,
#5088).Proof gates:
Synced artifacts:
docs/slate-v2/ledgers/issue-coverage-matrix.md.docs/slate-v2/ledgers/fork-issue-dossier.md.docs/slate-issues/gitcrawl-live-open-ledger.md.docs/slate-issues/gitcrawl-clusters.md.docs/slate-v2/references/pr-description.md.Implementation handoff:
ralph.44 long-form rows
before code.Slate Ralplan closure status: done.
Closure gate results:
0.92: pass, score 0.95;0.85: pass, lowest dimension 0.92;Status: pending.
Activation:
ralph accepted the completed Slate Ralplan for execution on
2026-05-07T12:45:37+08:00.pending because runnable proof and execution
backlog remains.slice-57-mobile-ime-next-proof-route-selection.Slice 1 owner:
.tmp/slate-v2/playwright/integration/examples/mentions.test.ts..tmp/slate-v2/packages/slate-browser/src/playwright/ime.ts only if the
existing IME helper cannot express the translated Lexical row.Slice 1 target:
Slice 1 claim policy:
Fixes #... or Improves #... claim from this slice by default.#4693, #4136) and broader
Mobile/IME proof backlog.Slice 1 required evidence:
docs/slate-v2/references/pr-description.md,
docs/slate-v2/ledgers/issue-coverage-matrix.md,
docs/slate-v2/ledgers/fork-issue-dossier.md,
docs/slate-issues/gitcrawl-live-open-ledger.md, and
docs/slate-issues/gitcrawl-clusters.md.reference docs: no change here with the
reason.Slice 1 result:
commits staged IME composition before a markable inline mention to
.tmp/slate-v2/playwright/integration/examples/mentions.test.ts.compositionend kernel trace.Fixes #... or Improves #... claim.bun playwright test playwright/integration/examples/mentions.test.ts --project=chromium --grep "commits staged IME composition before a markable inline mention".bun run lint:fix playwright/integration/examples/mentions.test.ts.bun run completion-check reports status: pending,
which is expected because more Mobile/IME proof batches remain.Next slice:
slice-2-lexical-ime-history-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.Slice 2 result:
undoes committed IME composition as one history step to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.compositionend
remains an allowed kernel transition.Fixes #... or Improves #... claim.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "undoes committed IME composition as one history step".bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun run completion-check reports status: pending,
which is expected because slice 3 is still runnable.Next slice:
slice-3-lexical-ime-cancel-history-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.Slice 3 result:
does not push canceled IME composition onto history to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.cancelNativeComposition CDP helper because the shared
editor.ime.compose helper only expresses committed composition.a as a sentinel and failed because the full model
text already contains a; corrected the sentinel to ! and reran the same
focused proof.Fixes #... or Improves #... claim.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "does not push canceled IME composition onto history".bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun run completion-check reports status: pending,
which is expected because slice 4 is still runnable.Next slice:
slice-4-lexical-safari-ime-delete-selection-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts
or a narrower WebKit/Safari-capable example test.8153-safari-ime-delete-selection so a
selection can be deleted after composition ends without extra deletion or
stale selection behavior.Slice 4 result:
deletes shell-backed selection after WebKit compositionend to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.dispatchCompositionEnd helper to mirror Lexical regression
8153-safari-ime-delete-selection: WebKit fires compositionend, browser
select-all creates shell-backed selection, then Backspace deletes the selected
content and leaves a collapsed Slate selection at the document start.Fixes #... or Improves #... claim.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=webkit --grep "deletes shell-backed selection after WebKit compositionend".bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports status: pending,
which is expected because slice 5 is still runnable.Next slice:
slice-5-prosemirror-dom-change-markup-proof..tmp/slate-v2/playwright/integration/examples/richtext.test.ts or a narrower
low-level Slate DOM/browser test.Slice 5 result:
syncs browser text mutations inside bold markup to
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.rich produces riZch, preserves the bold
markup, advances Slate selection inside the marked text, then Backspace
returns to rich with selection restored.Fixes #... or Improves #... claim.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "syncs browser text mutations inside bold markup".bun run lint:fix playwright/integration/examples/richtext.test.ts.bun typecheck:root.bun run completion-check reports status: pending,
which is expected because slice 6 is still runnable.Next slice:
slice-6-prosemirror-ambiguous-replacement-proof..tmp/slate-v2/playwright/integration/examples/richtext.test.ts.Slice 6 result:
resolves ambiguous browser insertion at a mark boundary to
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.rich before
the adjacent unmarked space keeps the inserted character inside the bold leaf,
advances selection inside that marked leaf, and Backspace restores the
original marked text.Fixes #... or Improves #... claim.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "resolves ambiguous browser insertion at a mark boundary".bun run lint:fix playwright/integration/examples/richtext.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 7 is still runnable.Next slice:
slice-7-lexical-ios-autocorrect-plain-text-proof..tmp/slate-v2/playwright/integration/examples/richtext.test.ts or a narrower
clipboard/native-input test.text/html and text/plain prediction payloads do not inject HTML
or break selection formatting.Slice 7 result:
treats iOS prediction payload as plain text inside formatted selection
to .tmp/slate-v2/playwright/integration/examples/paste-html.test.ts..tmp/slate-v2/site/examples/ts/paste-html.tsx so the HTML-paste
example detects real identical text/html + text/plain payloads and routes
them through text insertion, preserving current selection formatting instead
of parsing plain prediction text as an HTML fragment.text/plain data type before comparing payloads,
so HTML-only paste events still use the rich HTML path.TypeError: Cannot read properties of undefined (reading 'length'), proving
the old handler misrouted the prediction-shaped payload.bun playwright test playwright/integration/examples/paste-html.test.ts --project=chromium --grep "treats iOS prediction payload as plain text inside formatted selection".bun playwright test playwright/integration/examples/paste-html.test.ts --project=chromium --grep "pasted bold text uses|treats iOS prediction payload".bun run lint:fix playwright/integration/examples/paste-html.test.ts site/examples/ts/paste-html.tsx.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 8 is still runnable.Next slice:
slice-8-prosemirror-composition-commit-metadata-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts
or the narrowest existing commit/kernel metadata contract.Slice 8 result:
records runtime metadata for committed IME composition to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.compositionstart, compositionupdate, and
compositionend kernel trace entries with intent: composition,
ownership: native-allowed, nativeAllowed: true, editor target ownership,
frame IDs, and allowed transitions.Fixes #... or Improves #... claim.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "records runtime metadata for committed IME composition".bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.Next slice:
slice-9-prosemirror-android-virtual-keyboard-fallback-proof..tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts,
.tmp/slate-v2/packages/slate-react/test/editing-kernel-contract.ts, or the
narrowest existing Android input-manager contract.insertReplacementText /
deleteContentBackward routing through the centralized Android/input runtime.
This is architecture proof only, not exact Android device closure.Slice 9 result:
.tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts.insertReplacementText replaces
the current selection through the beforeinput command path, and
deleteContentBackward routes through a model-owned delete with explicit
caret repair.bun test packages/slate-react/test/model-input-strategy-contract.test.ts
attempt was the wrong runner because root Bun ignores *.test.*; the package
Vitest runner is the correct focused gate.bun test:vitest test/model-input-strategy-contract.test.ts from
.tmp/slate-v2/packages/slate-react.bun run lint:fix packages/slate-react/test/model-input-strategy-contract.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 10 is still runnable.Next slice:
slice-10-lexical-ime-formatting-boundary-proof..tmp/slate-v2/playwright/integration/examples/richtext.test.ts.Slice 10 result:
commits IME composition inside bold markup to
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.handles composition inside marks pressure
into Slate's marked-text contract: DOM composition inside bold rich at
offset 2 produces riすしch, preserves the bold mark, advances selection
inside the marked leaf, records composition trace ownership, and two
Backspaces restore the original marked text and caret.richすし) instead of inside
the marked text. A follow-up replacementStart / replacementEnd experiment
also failed by targeting the wrong document offset. That route is not an
honest proof for mid-mark composition in this harness.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "commits IME composition inside bold markup" --retries=0.bun run lint:fix playwright/integration/examples/richtext.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 11 is still runnable.docs/solutions/developer-experience/2026-05-07-slate-browser-ime-proof-rows-need-honest-dom-composition.md.Next slice:
slice-11-prosemirror-ime-decoration-boundary-proof..tmp/slate-v2/playwright/integration/examples/highlighted-text.test.ts.Slice 11 result:
commits IME composition inside decorated text to
.tmp/slate-v2/playwright/integration/examples/highlighted-text.test.ts.lph
inserts すし at the selected offset, preserves data-tone="warm",
advances selection after the committed text, records allowed composition trace
ownership, and two Backspaces restore the original text and caret.bun playwright test playwright/integration/examples/highlighted-text.test.ts --project=chromium --grep "commits IME composition inside decorated text" --retries=0.bun run lint:fix playwright/integration/examples/highlighted-text.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 12 is still runnable.Next slice:
slice-12-prosemirror-ime-spanning-nodes-proof..tmp/slate-v2/playwright/integration/examples/highlighted-text.test.ts or the
narrowest existing browser example that exposes adjacent decorated text
nodes.Slice 12 result:
commits IME composition spanning decorated text nodes to
.tmp/slate-v2/playwright/integration/examples/highlighted-text.test.ts.alすしbeta, received alすしすしbeta.alすしbeta;
the duplicate was a stale unmanaged browser text node outside
[data-slate-string="true"] in the projected text host..tmp/slate-v2/packages/slate-react/src/editable/composition-state.ts so
the Chrome composition-end fallback removes unmanaged composition text nodes
after writing the committed text into the model.bun playwright test playwright/integration/examples/highlighted-text.test.ts --project=chromium --grep "commits IME composition spanning decorated text nodes" --retries=0.bun playwright test playwright/integration/examples/highlighted-text.test.ts --project=chromium --grep "commits IME composition inside decorated text|commits IME composition spanning decorated text nodes" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "commits IME composition inside bold markup" --retries=0.bun run lint:fix packages/slate-react/src/editable/composition-state.ts playwright/integration/examples/highlighted-text.test.ts.bun typecheck:root.docs/solutions/ui-bugs/2026-05-07-slate-react-chrome-composition-fallback-must-clean-unmanaged-projection-dom-text.md.bun run completion-check reports
status: pending, which is expected because slice 13 is still runnable.Next slice:
slice-13-prosemirror-ime-widget-adjacent-proof..tmp/slate-v2/playwright/integration/examples/mentions.test.ts or the
narrowest existing inline-void/widget browser example.doesn't overwrite widgets next to the composition row so IME composition next to an inline widget/void preserves
the widget and committed text without exact Android/iOS device closure.Slice 13 result:
commits IME composition between inline mentions without overwriting them to .tmp/slate-v2/playwright/integration/examples/mentions.test.ts.すし, preserves both mention
widgets, advances selection in the text node, and records allowed composition
trace ownership.or すし!) instead of the selected offset. The row was
switched to the DOM-composition proof shape instead of treating CDP offsets as
equivalent.bun playwright test playwright/integration/examples/mentions.test.ts --project=chromium --grep "commits IME composition between inline mentions without overwriting them" --retries=0.bun playwright test playwright/integration/examples/mentions.test.ts --project=chromium --grep "commits staged IME composition before a markable inline mention|commits IME composition between inline mentions without overwriting them" --retries=0.bun run lint:fix playwright/integration/examples/mentions.test.ts packages/slate-react/src/editable/composition-state.ts playwright/integration/examples/highlighted-text.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 14 is still runnable.Next slice:
slice-14-prosemirror-ime-overlap-cancel-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts
or the narrowest existing browser/runtime test that can apply a model change
during composition.Slice 14 result:
drops active IME composition when a model change overlaps it to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.cancels composition when a change fully overlaps with it pressure into Slate's input-runtime contract: a real DOM
composition starts inside default block 1, a model-owned replacement
overlaps that active composition range, and the later compositionend must
not append stale committed composition text.---すし, proving Chrome's composition-end
fallback still wrote the stale composition payload after the overlapping
model change had already replaced the range..tmp/slate-v2/packages/slate-react/src/editable/composition-state.ts
and .tmp/slate-v2/packages/slate-react/src/editable/runtime-composition-events.ts
so the Chrome composition-end fallback skips model insertion when the active
composition has been superseded by a model-owned command, while still cleaning
unmanaged composition DOM text.albeta; narrowed the
cancellation test to the actual model-owned command signal.inputController to
composition-end handling.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "drops active IME composition when a model change overlaps it" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through the browser editing path|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "commits IME composition inside bold markup" --retries=0.bun playwright test playwright/integration/examples/highlighted-text.test.ts --project=chromium --grep "commits IME composition inside decorated text|commits IME composition spanning decorated text nodes" --retries=0.bun playwright test playwright/integration/examples/mentions.test.ts --project=chromium --grep "commits staged IME composition before a markable inline mention|commits IME composition between inline mentions without overwriting them" --retries=0.bun run lint:fix packages/slate-react/src/editable/composition-state.ts packages/slate-react/src/editable/runtime-composition-events.ts playwright/integration/examples/rendering-strategy-runtime.test.ts playwright/integration/examples/highlighted-text.test.ts playwright/integration/examples/mentions.test.ts.bun typecheck:root.docs/solutions/ui-bugs/2026-05-07-slate-react-chrome-composition-fallback-must-cancel-model-owned-overlap.md.bun run completion-check reports
status: pending, which is expected because slice 15 is still runnable.Next slice:
slice-15-prosemirror-ime-non-overlap-change-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.doesn't cancel composition when a change happens elsewhere row so a non-overlapping model change during composition
does not cancel, duplicate, or misplace the committed composition text. This
is browser proof only, not exact Android/iOS device closure.Slice 15 result:
keeps active IME composition when a model change happens elsewhere to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.doesn't cancel composition when a change happens elsewhere pressure into Slate's runtime contract: a real DOM
composition starts inside default block 1, a non-overlapping model operation
inserts ! into default block 2, and compositionend still commits すし
at the original composition point.model-owned cancellation guard does not over-cancel non-overlapping model
operations.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "keeps active IME composition when a model change happens elsewhere" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through the browser editing path|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it|keeps active IME composition when a model change happens elsewhere" --retries=0.bun run lint:fix packages/slate-react/src/editable/composition-state.ts packages/slate-react/src/editable/runtime-composition-events.ts playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "drops active IME composition when a model change overlaps it|keeps active IME composition when a model change happens elsewhere" --retries=0.bun run completion-check reports
status: pending, which is expected because slice 16 is still runnable.Next slice:
slice-16-prosemirror-ime-partial-overlap-cancel-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.Slice 16 result:
drops active IME composition when a model change partially overlaps it
to .tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.default block 1, a nearby model-owned
replacement intersects only part of the active composition neighborhood, and
the later compositionend must not append stale すし.compositionstart, so the row was tightened to a
collapsed composition point plus a partial model-owned replacement.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "drops active IME composition when a model change partially overlaps it" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|keeps active IME composition when a model change happens elsewhere" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through the browser editing path|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|keeps active IME composition when a model change happens elsewhere" --retries=0.bun run lint:fix packages/slate-react/src/editable/composition-state.ts packages/slate-react/src/editable/runtime-composition-events.ts playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 17 is still runnable.Next slice:
slice-17-prosemirror-ime-inside-change-cancel-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.cancels composition when a change happens inside of it row so an inside-range model-owned change cancels the stale
Chrome compositionend payload without exact Android/iOS device closure.Slice 17 result:
drops active IME composition when a model change happens at its insertion point to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.default block 1
insertion point, a model-owned insert happens at that same point, and the
later compositionend must not append stale すし.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "drops active IME composition when a model change happens at its insertion point" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through the browser editing path|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere" --retries=0.bun run lint:fix packages/slate-react/src/editable/composition-state.ts packages/slate-react/src/editable/runtime-composition-events.ts playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 18 is still runnable.Next slice:
slice-18-prosemirror-ime-rapid-following-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.handles compositions rapidly following each other row so two back-to-back DOM compositions in separate text blocks commit
without stale composing state, text loss, or caret drift. This is browser
proof only, not exact Android/iOS device closure.Slice 18 result:
commits rapidly following IME compositions in separate text blocks to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.default block 1, immediately followed by another native composition at
the end of default block 2, with both model text and final caret preserved.assert.blockTexts; the
harness only reports the mounted visible block list for this surface, so the
row now asserts the two visible edited blocks and separately checks model text
still contains default block 6.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits rapidly following IME compositions in separate text blocks" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through the browser editing path|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks" --retries=0.bun run lint:fix packages/slate-react/src/editable/composition-state.ts packages/slate-react/src/editable/runtime-composition-events.ts playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 19 is still runnable.Next slice:
slice-19-prosemirror-ime-cross-paragraph-proof..tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.can handle cross-paragraph compositions row
into a Slate browser proof for composition spanning block boundaries without
text loss, duplicated committed text, or exact Android/iOS device closure.Slice 19 result:
commits cross-paragraph IME composition as one replacement plus a
local selectDOMTextRange helper to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.default block 1
into default block 2 replaces the selected block range, merges the remaining
suffix into the first block, preserves later model text, and leaves both
model selection and DOM caret after the committed composition text.default block 3, but that default example region is
wrapped by the document-section control and the generic DOM selection
assertion returned null. The final proof uses the first two editable text
blocks and an explicit DOM range while syncing Slate's model selection through
the browser handle.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits cross-paragraph IME composition as one replacement" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.Next slice:
slice-20-lexical-ios-korean-backspace-native-proof..tmp/slate-v2/packages/slate-react/src/editable/keyboard-input-strategy.ts.ko-KR + Backspace should defer to native input
instead of becoming model-owned from keydown. This is runtime proof only, not
exact raw-device iOS closure.Slice 20 result:
shouldDeferBackspaceToNativeInput to
.tmp/slate-v2/packages/slate-react/src/editable/keyboard-input-strategy.ts..tmp/slate-v2/packages/slate-react/test/keyboard-input-strategy-contract.test.ts.../lexical/packages/lexical-plain-text/src/index.ts:286 and
../lexical/packages/lexical-rich-text/src/index.ts:893 into Slate's runtime
contract.TypeError: shouldDeferBackspaceToNativeInput is not a function.keyDownUnhandled() before destructive Backspace is
model-owned when the narrow predicate is true: iOS, navigator.language === 'ko-KR', and backward delete.bun test:vitest test/keyboard-input-strategy-contract.test.ts.bun test:vitest test/keyboard-input-strategy-contract.test.ts test/model-input-strategy-contract.test.ts test/editing-kernel-contract.test.ts.bun run lint:fix packages/slate-react/src/editable/keyboard-input-strategy.ts packages/slate-react/test/keyboard-input-strategy-contract.test.ts.bun test:vitest test/keyboard-input-strategy-contract.test.ts test/model-input-strategy-contract.test.ts test/editing-kernel-contract.test.ts.bun typecheck:root.docs/solutions/ui-bugs/2026-05-07-slate-react-ios-korean-backspace-must-stay-native-owned.md.Next slice:
slice-21-lexical-ime-typeahead-menu-proof..tmp/slate-v2/playwright/integration/examples/mentions.test.ts.Typeahead menu should not close during IME composition row so the mentions portal stays visible while Chromium IME
composition is active. This is desktop Chromium overlay proof only, not exact
mobile-device closure.Slice 21 result:
keeps mention portal open during IME composition to
.tmp/slate-v2/playwright/integration/examples/mentions.test.ts.@ma opens the portal, active Chromium IME composition
must not close it while composition text is still in progress.bun playwright test playwright/integration/examples/mentions.test.ts --project=chromium --grep "keeps mention portal open during IME composition" --retries=0.bun playwright test playwright/integration/examples/mentions.test.ts --project=chromium --grep "keeps mention portal open during IME composition|commits staged IME composition before a markable inline mention|commits IME composition between inline mentions without overwriting them" --retries=0.bun run lint:fix playwright/integration/examples/mentions.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 22 is still runnable.Slice 22 result:
replaces multiple formatted text nodes with Korean IME composition to
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.Can replace multiple formatted text nodes with IME composition (Korean)
into a Slate rich-text proof using Chromium CDP Input.imeSetComposition..tmp/slate-v2/packages/slate-react/src/editable/composition-state.ts now
gates expanded-selection pre-delete on trusted native composition, captures
composition marks synchronously, tracks latest composition text, and repairs
stale composition text left inside managed DOM strings..tmp/slate-v2/packages/slate-react/src/editable/mutation-controller.ts now
requests a render after model-owned text insertion during composition.<strong> output.docs/solutions/ui-bugs/2026-05-07-slate-react-ime-formatted-selection-needs-native-owned-cleanup.md.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "replaces multiple formatted text nodes with Korean IME composition" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "syncs browser text mutations inside bold markup|commits IME composition inside bold markup|replaces multiple formatted text nodes with Korean IME composition" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix packages/slate-react/src/editable/composition-state.ts packages/slate-react/src/editable/mutation-controller.ts playwright/integration/examples/richtext.test.ts.bun typecheck:root.Next slice:
slice-23-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
cross-editor backlog.Slice 23 result:
../lexical/packages/lexical-playground/__tests__/regression/8153-safari-ime-delete-selection.spec.mjs.compositionend, and Shift+ArrowUp range deletion after compositionend.Slice 24 result:
dispatchWebKitCompositionEnd to
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.deletes rich text selection after WebKit compositionend.deletes rich text line selection after WebKit compositionend.compositionend must not leave stale composition state
that prevents select-all deletion or native line-selection deletion.Enter some rich text… as visible placeholder text
while Slate model text is empty.bun playwright test playwright/integration/examples/richtext.test.ts --project=webkit --grep "deletes rich text (selection|line selection) after WebKit compositionend" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=webkit --grep "deletes rich text (selection|line selection) after WebKit compositionend|keeps caret editable after browser Backspace deletes selected range|removes the current block after browser triple click and Backspace" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=webkit --grep "deletes shell-backed selection after WebKit compositionend" --retries=0.bun run lint:fix playwright/integration/examples/richtext.test.ts.bun typecheck:root.bun playwright test playwright/integration/examples/richtext.test.ts --project=webkit --grep "deletes rich text (selection|line selection) after WebKit compositionend" --retries=0.bun run completion-check reports
status: pending, which is expected because slice 25 is still runnable.Next slice:
slice-25-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 25 result:
RangeSelection should be retained when undo IME.../lexical/packages/lexical-playground/__tests__/e2e/History.spec.mjs.Slice 26 result:
restores expanded selection after undoing IME replacement to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.b in ab with IME text yields aす, and
one undo restores both ab and the original backward selection.a, proving trusted native composition
pre-delete and the Chrome composition-end fallback insert were separate
history batches..tmp/slate-v2/packages/slate-react/src/editable/composition-state.ts now
tracks trusted native expanded-selection pre-delete and merges the following
Chrome composition-end fallback insert into that history batch.docs/solutions/ui-bugs/2026-05-07-slate-react-ime-replacement-undo-must-merge-native-predelete.md.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|restores expanded selection after undoing IME replacement|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "syncs browser text mutations inside bold markup|commits IME composition inside bold markup|replaces multiple formatted text nodes with Korean IME composition" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=webkit --grep "deletes shell-backed selection after WebKit compositionend" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=webkit --grep "deletes rich text (selection|line selection) after WebKit compositionend" --retries=0.bun run lint:fix packages/slate-react/src/editable/composition-state.ts playwright/integration/examples/rendering-strategy-runtime.test.ts playwright/integration/examples/richtext.test.ts.bun typecheck:root.Next slice:
slice-27-lexical-floating-toolbar-ime-proof..tmp/slate-v2/playwright/integration/examples/hovering-toolbar.test.ts.Floating toolbar should not be displayed when using IME row so the hovering toolbar stays hidden while Chromium IME
composition is active, then appears for a real expanded selection after commit.
This is desktop Chromium overlay proof only, not exact mobile-device closure.Slice 27 result:
../lexical/packages/lexical-playground/__tests__/e2e/Composition.spec.mjs.hovering-toolbar example because it has the same
selection-driven overlay behavior and an existing Playwright owner.Slice 28 result:
keeps hovering toolbar hidden during IME composition to
.tmp/slate-v2/playwright/integration/examples/hovering-toolbar.test.ts.bun playwright test playwright/integration/examples/hovering-toolbar.test.ts --project=chromium --grep "keeps hovering toolbar hidden during IME composition" --retries=0.bun playwright test playwright/integration/examples/hovering-toolbar.test.ts --project=chromium --grep "hovering toolbar" --retries=0.bun run lint:fix playwright/integration/examples/hovering-toolbar.test.ts.bun typecheck:root.bun playwright test playwright/integration/examples/hovering-toolbar.test.ts --project=chromium --retries=0 expanded to the broader Chromium examples suite and failed on unrelated check-list, persistent-annotation, table, and huge-document rows. The targeted hovering-toolbar grep above is the relevant proof.bun run completion-check reports
status: pending, which is expected because slice 29 is still runnable.Next slice:
slice-29-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 29 result:
Merge IME input when less delay from
../lexical/packages/lexical-playground/__tests__/e2e/History.spec.mjs.Slice 30 result:
undoes native text and immediately following IME composition together
to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.Input.insertText("a") followed by
Chromium IME composition す becomes one undoable action, restoring the
original text and caret after a single undo.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "undoes native text and immediately following IME composition together" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|undoes native text and immediately following IME composition together|restores expanded selection after undoing IME replacement|does not push canceled IME composition onto history|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 31 is still runnable.Next slice:
slice-31-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 31 result:
can deal with Android-style newline-after-composition
row from ../prosemirror/view/test/webtest-composition.ts.Can type, delete and cancel Hiragana via IME row from
../lexical/packages/lexical-playground/__tests__/e2e/Composition.spec.mjs
instead.Slice 32 result:
keeps text stable after type-delete-cancel IME composition to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "keeps text stable after type-delete-cancel IME composition" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|undoes native text and immediately following IME composition together|restores expanded selection after undoing IME replacement|does not push canceled IME composition onto history|keeps text stable after type-delete-cancel IME composition|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 33 is still runnable.Next slice:
slice-33-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 33 result:
handles replacement of existing words row from
../prosemirror/view/test/webtest-composition.ts.Slice 34 result:
replaces an existing word with IME composition to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.two in one two three and committing IME text
replaces only that word, preserves surrounding text, advances selection after
the committed text, and records an allowed compositionend trace.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "replaces an existing word with IME composition" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|undoes native text and immediately following IME composition together|restores expanded selection after undoing IME replacement|replaces an existing word with IME composition|does not push canceled IME composition onto history|keeps text stable after type-delete-cancel IME composition|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 35 is still runnable.Next slice:
slice-35-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 35 result:
supports composition in a cursor wrapper row from
../prosemirror/view/test/webtest-composition.ts.Slice 36 result:
commits IME composition through an active mark in an empty block to
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.abc, renders the committed text as <strong>,
advances selection after the committed text, and records an allowed
compositionend trace.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "commits IME composition through an active mark in an empty block" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "syncs browser text mutations inside bold markup|commits IME composition inside bold markup|commits IME composition through an active mark in an empty block|replaces multiple formatted text nodes with Korean IME composition" --retries=0.bun run lint:fix playwright/integration/examples/richtext.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 37 is still runnable.Next slice:
slice-37-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 37 result:
handles composition in a multi-child mark with a cursor wrapper row from
../prosemirror/view/test/webtest-composition.ts.Slice 38 result:
commits IME composition through an active mark before a formatted sibling
to .tmp/slate-v2/playwright/integration/examples/richtext.test.ts.code.
The test was corrected to make the active italic+code mark set explicit
before composition.oow with active
italic+code marks before the bold-italic three sibling, preserves the
formatted sibling, advances selection after the committed text, and records an
allowed compositionend trace.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "commits IME composition through an active mark before a formatted sibling" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "syncs browser text mutations inside bold markup|commits IME composition inside bold markup|commits IME composition through an active mark in an empty block|commits IME composition through an active mark before a formatted sibling|replaces multiple formatted text nodes with Korean IME composition" --retries=0.bun run lint:fix playwright/integration/examples/richtext.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 39 is still runnable.Next slice:
slice-39-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 39 result:
supports composition at start of block in a new node
row from ../prosemirror/view/test/webtest-composition.ts.Slice 40 result:
commits IME composition at the start of a text block to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.0 inserts !? before
foo, preserves the following text, advances both model and DOM caret after
the committed prefix, and records an allowed compositionend trace.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition at the start of a text block" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|undoes native text and immediately following IME composition together|restores expanded selection after undoing IME replacement|replaces an existing word with IME composition|commits IME composition at the start of a text block|does not push canceled IME composition onto history|keeps text stable after type-delete-cancel IME composition|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix playwright/integration/examples/richtext.test.ts playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 41 is still runnable.Next slice:
slice-41-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 41 result:
supports composition inside existing text row from
../prosemirror/view/test/webtest-composition.ts.Slice 42 result:
commits IME composition inside existing text to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.1 in foo inserts xyz,
yields fxyzoo, advances both model and DOM caret after the committed
composition, and records an allowed compositionend trace.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition inside existing text" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|undoes native text and immediately following IME composition together|restores expanded selection after undoing IME replacement|replaces an existing word with IME composition|commits IME composition at the start of a text block|commits IME composition inside existing text|does not push canceled IME composition onto history|keeps text stable after type-delete-cancel IME composition|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 43 is still runnable.Next slice:
slice-43-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 43 result:
supports composition at end of block in a new node
row from ../prosemirror/view/test/webtest-composition.ts.Slice 44 result:
commits IME composition at the end of a text block to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.foo inserts !?,
yields foo!?, advances both model and DOM caret after the committed text,
and records an allowed compositionend trace.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition at the end of a text block" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|undoes native text and immediately following IME composition together|restores expanded selection after undoing IME replacement|replaces an existing word with IME composition|commits IME composition at the start of a text block|commits IME composition inside existing text|commits IME composition at the end of a text block|does not push canceled IME composition onto history|keeps text stable after type-delete-cancel IME composition|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 45 is still runnable.Next slice:
slice-45-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 45 result:
supports composition in an empty block row from
../prosemirror/view/test/webtest-composition.ts.custom-placeholder example so an
empty placeholder-backed editor accepts native Chromium IME composition and
hides the placeholder after commit.Slice 46 result:
commits IME composition from the custom placeholder empty state to
.tmp/slate-v2/playwright/integration/examples/placeholder.test.ts.abc, yields
model text abc, advances selection to offset 3, hides the placeholder,
and records an allowed compositionend trace.bun playwright test playwright/integration/examples/placeholder.test.ts --project=chromium --grep "commits IME composition from the custom placeholder empty state" --retries=0.bun run lint:fix playwright/integration/examples/placeholder.test.ts.bun typecheck:root.bun playwright test playwright/integration/examples/placeholder.test.ts --project=chromium --retries=0
unexpectedly expanded to the full examples/stress suite; it failed unrelated
checklist, annotation, table, and huge-document rows after 218 passing tests.
This broad run is not used as slice evidence.bun run completion-check reports
status: pending, which is expected because slice 47 is still runnable.Next slice:
slice-47-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 47 result:
Can undo composed Hirigana via IME after composition ends (#2479) row from
../lexical/packages/lexical-playground/__tests__/e2e/History.spec.mjs.Slice 48 result:
undoes delayed Hiragana IME compositions as separate history steps to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.すし もじあ, one undo returned to the
initial document instead of stopping at すし . Root cause:
browser-native text imports reached slate-history only as adjacent
insert_text operations, so the generic adjacent-text merge heuristic had no
user-pause boundary..tmp/slate-v2/packages/slate-react/src/editable/input-history.ts and applies
delayed native-text history: { mode: 'push' } metadata from
composition-state.ts and dom-repair-queue.ts. Immediate native text plus
immediate IME composition still merges.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "undoes delayed Hiragana IME compositions as separate history steps" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|undoes native text and immediately following IME composition together|undoes delayed Hiragana IME compositions as separate history steps|restores expanded selection after undoing IME replacement|replaces an existing word with IME composition|commits IME composition at the start of a text block|commits IME composition inside existing text|commits IME composition at the end of a text block|does not push canceled IME composition onto history|keeps text stable after type-delete-cancel IME composition|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix packages/slate-react/src/editable/input-history.ts packages/slate-react/src/editable/composition-state.ts packages/slate-react/src/editable/dom-repair-queue.ts playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.docs/solutions/ui-bugs/2026-05-07-slate-react-native-ime-history-boundaries-need-explicit-push-metadata.md.bun run completion-check reports
status: pending, which is expected because slice 49 is still runnable.Next slice:
slice-49-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 49 result:
Can type Hiragana via IME between emojis row from
../lexical/packages/lexical-playground/__tests__/e2e/Composition.spec.mjs.Slice 50 result:
commits IME composition between emoji text to
.tmp/slate-v2/playwright/integration/examples/rendering-strategy-runtime.test.ts.すし between two 🙂 characters yields
🙂すし🙂, preserves the second emoji, advances the selection after the
committed text at the correct UTF-16 offset, and records an allowed
compositionend trace.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition between emoji text" --retries=0.bun playwright test playwright/integration/examples/rendering-strategy-runtime.test.ts --project=chromium --grep "commits IME composition through|records runtime metadata for committed IME composition|undoes committed IME composition as one history step|undoes native text and immediately following IME composition together|undoes delayed Hiragana IME compositions as separate history steps|restores expanded selection after undoing IME replacement|replaces an existing word with IME composition|commits IME composition at the start of a text block|commits IME composition inside existing text|commits IME composition at the end of a text block|commits IME composition between emoji text|does not push canceled IME composition onto history|keeps text stable after type-delete-cancel IME composition|drops active IME composition when a model change overlaps it|drops active IME composition when a model change partially overlaps it|drops active IME composition when a model change happens at its insertion point|keeps active IME composition when a model change happens elsewhere|commits rapidly following IME compositions in separate text blocks|commits cross-paragraph IME composition as one replacement" --retries=0.bun run lint:fix playwright/integration/examples/rendering-strategy-runtime.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 51 is still runnable.Next slice:
slice-51-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 51 result:
../lexical/packages/lexical-playground/__tests__/e2e/Composition.spec.mjs,
focusing on the still-missing "at the end of a mention" shape.Slice 52 result:
commits IME composition immediately after an inline mention to
.tmp/slate-v2/playwright/integration/examples/mentions.test.ts.すし immediately after the first mention preserves
both inline mentions, inserts into the following text node, advances selection
after the committed text, and records an allowed compositionend trace.bun playwright test playwright/integration/examples/mentions.test.ts --project=chromium --grep "commits IME composition immediately after an inline mention" --retries=0.bun playwright test playwright/integration/examples/mentions.test.ts --project=chromium --grep "keeps mention portal open during IME composition|commits staged IME composition before a markable inline mention|commits IME composition between inline mentions without overwriting them|commits IME composition immediately after an inline mention" --retries=0.bun run lint:fix playwright/integration/examples/mentions.test.ts.bun typecheck:root.bun run completion-check reports
status: pending, which is expected because slice 53 is still runnable.Next slice:
slice-53-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Slice 53 result:
../lexical/packages/lexical-playground/__tests__/e2e/Composition.spec.mjs
rows after the new emoji and inline-mention proof.insertSoftBreak still aliases block split; hashtag rows are
product/plugin-specific and need a Slate hashtag surface before they can
become raw Slate proof. These remain backlog pressure, not exact claims.Slice 54 result:
bun run completion-check reports
status: pending, which is expected because slice 55 is still runnable.Next slice:
slice-55-mobile-ime-next-proof-route-selection.docs/plans/2026-05-07-slate-v2-mobile-ime-input-runtime-ralplan.md plus
the narrowest matching .tmp/slate-v2 source/test owner selected from the
remaining Lexical/ProseMirror Mobile/IME backlog.Composition.spec.mjs rows, Lexical iOS Korean native-backspace contract,
Lexical history rows, Lexical type/delete/cancel row, and Lexical Safari
delete-after-composition rows, preserving raw-device and product-plugin
boundaries.Slice 55 result:
../lexical/packages/lexical-playground/__tests__/e2e/History.spec.mjs IME
rows after the delayed Hiragana history fix.Cancel composition not push undo stack is covered by
does not push canceled IME composition onto history; Merge IME input when less delay is covered by undoes native text and immediately following IME composition together plus the delayed split row; RangeSelection should be retained when undo IME is covered by restores expanded selection after undoing IME replacement.Slice 56 result:
bun run completion-check reports
status: pending, which is expected because slice 57 is still runnable.Slice 57 result:
../lexical/packages/lexical-playground/__tests__/regression/8153-safari-ime-delete-selection.spec.mjs.Can delete all text selected with Cmd+A after IME composition end on Safari is covered by Slate's WebKit deletes rich text selection after WebKit compositionend row and the shell-backed deletes shell-backed selection after WebKit compositionend row; Can delete multi-paragraph selection with Shift+ArrowUp after IME composition end on Safari is covered
by deletes rich text line selection after WebKit compositionend.Slice 58 result:
bun run completion-check reports
status: pending, which is expected because slice 59 is still runnable.Slice 59 result:
#5891, [Android] The autocorrect doesn't work when creating the first line, from
docs/slate-issues/open-issues-dossiers/5912-5771.md and
docs/slate-issues/test-candidate-map/5912-5771.md.insertReplacementText /
autocorrect architecture coverage first, not exact raw Android keyboard
closure.Slice 60 result:
routes Android-style first-line autocorrect through empty-state replacement text to
.tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts.insertReplacementText at an empty first-line selection
inserts the replacement text, advances model selection after the inserted
text, and returns no repair request.#5891 raw-device closure.bun test packages/slate-react/test/model-input-strategy-contract.test.ts... is wrong
for this file because bunfig.toml ignores *.test.*; the correct focused
runner is package Vitest.bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "routes Android-style first-line autocorrect through empty-state replacement text".bun run lint:fix packages/slate-react/test/model-input-strategy-contract.test.ts.bun --filter slate-react typecheck.*.test.* runner boundary.bun run completion-check reports
status: pending, which is expected because slice 61 is still runnable.Slice 61 result:
#5099, Android empty placeholder backspace behavior, from
docs/slate-issues/open-issues-dossiers/5129-5066.md and
docs/slate-issues/test-candidate-map/5129-5066.md.deleteContentBackward
architecture coverage first, not exact raw Android Chrome keyboard closure.Slice 62 result:
keeps Android-style empty-state backspace from mutating placeholder text to
.tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts.deleteContentBackward leaves editor
text empty, keeps selection at [0,0]/0, and requests only caret repair.#5099 raw-device closure.bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "keeps Android-style empty-state backspace from mutating placeholder text".bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "routes Android-style first-line autocorrect through empty-state replacement text|keeps Android-style empty-state backspace from mutating placeholder text".bun run lint:fix packages/slate-react/test/model-input-strategy-contract.test.ts.bun --filter slate-react typecheck.bun run completion-check reports
status: pending, which is expected because slice 63 is still runnable.Slice 63 result:
#5984 from
docs/slate-issues/open-issues-dossiers/5994-5918.md, issue #5083 from
docs/slate-issues/open-issues-dossiers/5129-5066.md, and issue #5023
from docs/slate-issues/open-issues-dossiers/5064-4971.md.Slice 64 result:
replaces expanded CJK composition selection once and
deletes expanded CJK composition selection once to
.tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts.insertFromComposition over an expanded CJK selection inserts
one replacement string without duplicate text, and deleteByComposition over
an expanded CJK selection deletes one selected unit without requiring a second
delete.#5984, #5083, or #5023 device/browser closure.bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "replaces expanded CJK composition selection once|deletes expanded CJK composition selection once".bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "Android-style first-line autocorrect|Android-style empty-state backspace|expanded CJK composition selection once".bun run lint:fix packages/slate-react/test/model-input-strategy-contract.test.ts.bun --filter slate-react typecheck.bun run completion-check reports
status: pending, which is expected because slice 65 is still runnable.Slice 65 result:
#5078,
#5034, and #5026.#5078 is not an inline-boundary CJK row; it is Android
composition/onChange freshness. #5034 and #5026 are Android readOnly
lifecycle rows. None are honestly closed by the model-input unit rows.Slice 66 result:
bun run completion-check reports
status: pending, which is expected because slice 67 is still runnable.Slice 67 result:
#5653 is Microsoft IME blur duplication, while
Android autocomplete prefix replacement is #5643; #4531 remains a broader
Android suggestion-flicker row.../lexical/packages/lexical-playground/__tests__/e2e/Events.spec.mjs,
which dispatches insertText followed by insertReplacementText over a
target range. The local ProseMirror sibling check did not expose a matching
autocomplete/replacement row.#5653
focus/blur lifecycle closure.Slice 68 result:
replaces an autocorrect prefix without appending after it to
.tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts.IS, not an appended duplicate, and
leaves model selection after the replacement prefix.#5643 /
#4531 replacement-pressure route only.bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "autocorrect prefix|first-line autocorrect|empty-state backspace|expanded CJK".bun run lint:fix packages/slate-react/test/model-input-strategy-contract.test.ts.bun --filter slate-react typecheck.bun run completion-check reports status: pending,
which is expected because slice 69 is still runnable.Slice 69 result:
#5653, Microsoft IME blur duplication, because its dossier names a
concrete event sequence: compositionend, then beforeinput deleteContentBackward, then beforeinput insertText.imports expanded delete target ranges from blur-time IME cleanup events to
.tmp/slate-v2/packages/slate-react/test/selection-reconciler-contract.ts.syncSelectionForBeforeInput
ignored expanded target ranges for deleteContentBackward and kept the old
collapsed model selection.Slice 70 result:
.tmp/slate-v2/packages/slate-react/src/editable/selection-reconciler.ts so
expanded beforeinput delete target ranges are imported even for
forward/backward delete cleanup events. Collapsed delete target ranges still
fall back to command-derived behavior.#5653 Windows/Microsoft IME closure was
promoted. The fix covers the event-level runtime owner when the browser
supplies an expanded delete target range during blur cleanup; exact
Windows/IME closure still needs platform proof.bun test ./packages/slate-react/test/selection-reconciler-contract.ts -t "imports expanded delete target ranges".bun test ./packages/slate-react/test/selection-reconciler-contract.ts -t "imports expanded delete target ranges".bun test ./packages/slate-react/test/selection-reconciler-contract.ts.bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "autocorrect prefix|first-line autocorrect|empty-state backspace|expanded CJK".bun run lint:fix packages/slate-react/src/editable/selection-reconciler.ts packages/slate-react/test/selection-reconciler-contract.ts packages/slate-react/test/model-input-strategy-contract.test.ts.bun --filter slate-react typecheck.bun run completion-check reports status: pending,
which is expected because slice 71 is still runnable.Slice 71 result:
#4521 and
#5175.../prosemirror-commands/test/test-commands.ts splitBlock heading rows and
Lexical's
../lexical/packages/lexical-playground/__tests__/e2e/Headings/HeadingsEnterAtEnd.spec.mjs
/ HeadingsEnterInMiddle.spec.mjs.Slice 72 result:
splits a custom block on Enter without dropping follow-up text to
.tmp/slate-v2/packages/slate-react/test/model-input-strategy-contract.test.ts.insertParagraph splits a custom block, moves
selection into the inserted block, and preserves the first follow-up inserted
character. It intentionally does not force heading-to-paragraph product
semantics.#4521 /
#5175 raw runtime route, not exact Android heading DOM or last inserted
element closure.bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "splits a custom block".bun --filter slate-react test:vitest -- model-input-strategy-contract.test.ts -t "custom block|autocorrect prefix|first-line autocorrect|empty-state backspace|expanded CJK".bun test ./packages/slate-react/test/selection-reconciler-contract.ts.bun run lint:fix packages/slate-react/src/editable/selection-reconciler.ts packages/slate-react/test/selection-reconciler-contract.ts packages/slate-react/test/model-input-strategy-contract.test.ts.bun --filter slate-react typecheck.bun run completion-check reports status: pending,
which is expected because slice 73 is still runnable.Slice 73 result:
#4693 and
#4136.docs/slate-issues/open-issues-dossiers/4741-4643.md keeps #4693 as
Android Korean/Japanese composition architecture pressure, while
docs/slate-issues/open-issues-dossiers/4160-4074.md keeps #4136 as
multibyte composition after clearing placeholder or near inline boundaries.docs/slate-issues/test-candidate-map/4741-4643.md asks for Android Korean
composition in the richtext example, and
docs/slate-issues/test-candidate-map/4160-4074.md asks for multibyte IME
input after clearing placeholder or after an inline boundary.webtest-composition.ts covers composition inside marks,
multi-child marks, cursor wrappers, highlighted/decorated text,
multi-node composition, and widgets next to composition; Lexical's
Composition.spec.mjs covers Hiragana near mentions, IME after mentions,
hashtags, typeahead stability, and Korean replacement across multiple
formatted nodes.Slice 74 result:
#4693 / #4136 in this
slice. The architecture route is already represented by existing Slate v2
browser rows:
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts covers active
mark cursor-wrapper composition and Korean replacement across formatted
nodes; .tmp/slate-v2/playwright/integration/examples/mentions.test.ts covers
composition before, between, and after inline mentions;
.tmp/slate-v2/playwright/integration/examples/highlighted-text.test.ts
covers decorated-text and spanning-decorator composition; and
.tmp/slate-v2/playwright/integration/examples/placeholder.test.ts covers
custom-placeholder empty-state composition.bun run completion-check reports status: pending,
which is expected because slice 75 is still runnable.Slice 75 result:
#4030, #3943, and #3882.docs/slate-issues/open-issues-dossiers/3948-3881.md keeps #3943 as a
Safari Chinese composition caret-reset row and #3882 as an empty richtext
IME crash row. docs/slate-issues/open-issues-dossiers/4067-3949.md keeps
#4030 as a Safari list-item IME caret-reset row.docs/slate-issues/test-candidate-map/3948-3881.md asks for Safari Chinese
composition caret stability and empty richtext IME typing without a crash;
docs/slate-issues/test-candidate-map/4067-3949.md asks for Safari list
item IME composition to keep caret position.../prosemirror/view/test/webtest-composition.ts. The existing Slate v2
custom-placeholder row was close, but it did not prove the richtext example
empty-block route named by #3882.docs/solutions/logic-errors/2026-04-11-webkit-playwright-inserttext-is-a-direct-input-ceiling-not-a-direct-composition-lane.md
still applies. Desktop WebKit Playwright insertText is useful direct-input
evidence, not honest composition evidence, so #4030 and #3943 stay
deferred to Safari composition proof.Slice 76 result:
commits IME composition in an empty rich text block to
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.すし,
selection after the committed text, and an allowed compositionend trace.#3882
empty-richtext route, not exact old Korean/Chinese crash closure. #4030 and
#3943 remain Safari-specific deferred rows.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "commits IME composition in an empty rich text block" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "empty rich text block|active mark in an empty block|replaces multiple formatted text nodes with Korean" --retries=0.bun run lint:fix playwright/integration/examples/richtext.test.ts.bun run typecheck:root.bun run completion-check reports status: pending,
which is expected because slice 77 is still runnable.Slice 77 result:
#4067,
#4031, and #4353.docs/slate-issues/open-issues-dossiers/4067-3949.md keeps #4067 as
select-all then composition crash/desync, and #4031 as empty-editor
Japanese composition confirm crash. docs/slate-issues/open-issues-dossiers/4390-4269.md
keeps #4353 as select-all then Japanese composition wedging after the first
character.docs/slate-issues/test-candidate-map/4067-3949.md asks for select-all then
composition and empty-editor Japanese confirm rows; docs/slate-issues/test-candidate-map/4390-4269.md
asks for select-all then start Japanese IME input.Slice 78 result:
replaces select-all rich text with IME composition to
.tmp/slate-v2/playwright/integration/examples/richtext.test.ts.すし, and asserts the full selection is replaced by one
text node with selection after the committed text and an allowed
compositionend trace.#4067/#4353 select-all composition route and complements the #4031
empty-editor route, not exact old Japanese/Chinese crash closure.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "replaces select-all rich text with IME composition" --retries=0.bun playwright test playwright/integration/examples/richtext.test.ts --project=chromium --grep "empty rich text block|select-all rich text|active mark in an empty block|replaces multiple formatted text nodes with Korean" --retries=0.bun run lint:fix playwright/integration/examples/richtext.test.ts.bun run typecheck:root.bun run completion-check reports status: pending,
which is expected because slice 79 is still runnable.Slice 79 result:
#5830 and #4232.docs/slate-issues/open-issues-dossiers/5912-5771.md keeps #5830 as
onBlur not firing while Japanese/Korean composition is active in an empty
editor. docs/slate-issues/open-issues-dossiers/4268-4162.md keeps #4232
as select-all/delete plus composition corrupting text or pasting page text on
blur.docs/slate-issues/test-candidate-map/5912-5771.md asks for composition
onBlur on an empty editor when focus moves away mid-composition.
docs/slate-issues/test-candidate-map/4268-4162.md asks for a broader
Cmd+A/delete/composition/blur corruption row.../prosemirror/view/src/input.ts. Lexical
registers blur as a root event in ../lexical/packages/lexical/src/LexicalEvents.ts;
the only local Lexical blur special case found was plugin-specific focus
restoration in LexicalDraggableBlockPlugin, not a composition-blur proof
row.Slice 80 result:
fires blur when focus leaves during placeholder IME composition to
.tmp/slate-v2/playwright/integration/examples/placeholder.test.ts.Editable.onBlur counter to
.tmp/slate-v2/site/examples/ts/custom-placeholder.tsx so the browser row
proves the user callback route, not only a native DOM blur listener.onBlur callback fired exactly once,
and asserts the Slate kernel recorded an allowed blur event.#5830 is upgraded from "no exact composition-blur
proof" to related architecture proof for Chromium empty-placeholder
composition blur. No exact Japanese/Korean raw IME closure is claimed.
#4232 remains only partially represented by adjacent select-all and blur
lifecycle rows; exact reverse-input/page-text-paste closure is not claimed.docs/slate-v2/ledgers/issue-coverage-matrix.md for the #5830 related
row. PR fixed/improved counts stay unchanged because this is not a
Fixes #... or Improves #... claim.bun playwright test playwright/integration/examples/placeholder.test.ts --project=chromium --grep "fires blur when focus leaves during placeholder IME composition" --retries=0.bun playwright test playwright/integration/examples/placeholder.test.ts --project=chromium --grep "custom placeholder empty state|focus leaves during placeholder IME|undoes typing from the custom placeholder" --retries=0.bun run lint:fix site/examples/ts/custom-placeholder.tsx playwright/integration/examples/placeholder.test.ts.bun run typecheck:root.Slice 81 result:
#6051, #6022, #5983, #5989, #5883, #4400, #5680, #5493,
#5130, #5836, #5805, #5666, #5291, #5371, #5167, #4959,
#4861, #4602, #4354, #4372, #5183, #5391. Existing Slate v2
architecture covers the shared runtime pressure; exact closure still needs
the reported Android/iOS/Samsung/Firefox Android/voice environment.#4030, #3943, #4640, #4543, #4085. The local WebKit direct-input
rows and Chromium IME rows do not honestly prove these Safari composition or
autocorrect reports.#5078, #5034, #5026, #4994. The earlier slice preserved these as
Android manager/readOnly integration rows because exact proof must observe
emitted operations, onChange freshness, and readOnly transitions under the
relevant Android path.#5928, #4532, #4223, #3573, #4621, and the plugin/render
composition rows such as #3222/#3177. These inform runtime/event policy
but are not raw Slate exact bug closures.#3873 is covered by the existing keyboard-composition kernel contract;
#5173, #4232, and #4269 are represented by the focus-lifecycle,
select-all, composition-cancel, and composition-keydown proof families, but
their exact historical repros remain non-claims; #3695, #5375, #4770,
and #3611 are represented by active-mark, inline-boundary, emoji-boundary,
and void/zero-width architecture proof families, not exact old browser/device
closures.#5830 related row was already synced in slice 80, and PR fixed/improved
counts remain unchanged.lint:fix, and root TypeScript check.Closure:
#5830 related
proof text, and explicitly preserved raw-device, Safari/WebKit, integration,
and product/plugin non-claims.