docs/plans/2026-04-11-slate-v2-ime-mobile-browser-file-ledger.md
Historical batch/review note. Live browser/input scenario-proof truth now lives in true-slate-rc-proof-ledger.md. Live legacy-file closure truth now lives in release-file-review-ledger.md. Keep this file for archaeology and batch history, not as the active proof authority.
Historical batch/review record for the reopened IME/mobile/browser RC lane.
Use the same blunt rule as the other ledgers:
[x] reviewed[ ] still needs deep reviewDo not use this file as passive archaeology. Every behavior-bearing legacy file must map to one or more scenario rows.
Pinned slate-v2 diff command result:
git -C /Users/zbeyens/git/slate-v2 diff --name-status --diff-filter=ACDMRTUXB origin/main...HEAD -- \
packages/slate-react \
packages/slate-dom \
packages/slate-browser \
playwright/integration/examples \
site/examples/ts
Current result:
EMPTYRead:
origin/main...HEAD diff for those target directories| Review | Scenario | Legacy file(s) | Current owner / equivalent | Proof lane | Browser scope | Expected outcome | Actual outcome | Artifact links | Owner | Status |
|---|---|---|---|---|---|---|---|---|---|---|
| [x] | placeholder IME | packages/slate-react/src/components/editable.tsx, packages/slate-react/src/components/string.tsx | Editable, EditableText, placeholder example | placeholder-ime.test.ts, firefox-direct-ime.test.ts, webkit-direct-ime-ceiling.test.ts, ime-proxy.test.ts, proof:agent-browser:ios:placeholder-input:local, proof:appium:ios:placeholder-input:local, proof:appium:android:placeholder-input:local | automated-direct: chromium + firefox + Android Chrome emulator, automated-proxy: webkit-desktop, plus setup-green / behavior-red: iOS Simulator Safari | empty placeholder composition behaves safely enough to support the strong RC claim | Chromium direct proof is green on the FEFF-backed placeholder path, Firefox now has a stronger direct composition lane via Playwright keyboard.insertText, desktop WebKit has an explicit direct-input ceiling probe showing that insertText commits cleanly but does not expose composition-specific input events there, Android direct typing proof is green, and direct Appium iOS Safari setup is green. Current iOS behavior proof remains red through Appium/XCUITest value (blockTexts: "", repeated input:undefined:[null], `slateSelection: 0.0:0 | 0.0:0), and native-context coordinate tapping still fails to surface an iPhone keyboard. The current agent-browser` iOS provider is also not trustworthy on these routes because it often exposes only the Next shell without the editor node | placeholder-ime.test.ts, firefox-direct-ime.test.ts, webkit-direct-ime-ceiling.test.ts, ime-proxy.test.ts, 2026-04-03-jsdom-contenteditable-composition-is-not-a-trustworthy-ime-proof.md, 2026-04-12-appium-ios-safari-loads-local-slate-routes-but-xcuitest-value-does-not-drive-contenteditable.md, package.json | playwright + site/examples + browser-mobile transports |
| [x] | no-FEFF placeholder IME | packages/slate-react/src/components/editable.tsx, packages/slate-react/src/components/string.tsx | Editable, EditableText, placeholder-no-feff example | placeholder-ime.test.ts, firefox-direct-ime.test.ts, ime-proxy.test.ts, proof:agent-browser:ios:placeholder-no-feff-input:local, proof:appium:ios:placeholder-no-feff-input:local, proof:appium:android:placeholder-no-feff-input:local | automated-direct: chromium + firefox + Android Chrome emulator, automated-proxy: webkit-desktop, plus setup-green / behavior-red: iOS Simulator Safari | no-FEFF empty placeholder path composes like the relied-on legacy path or is explicitly justified as a changed contract | Chromium composition proof is green on the line-break no-FEFF path, Chromium delayed per-key typing is now also green, Firefox has direct composition proof on the same surface via Playwright keyboard.insertText, desktop WebKit keeps the proxy lane, and Android direct no-FEFF typing proof is green. Direct Appium iOS Safari setup is green on the route, but typing remains red with the same XCUITest value no-op shape as FEFF (blockTexts: "", repeated input:undefined:[null], `slateSelection: 0.0:0 | 0.0:0). The current agent-browser` iOS provider is route-shell-broken here, so it should not be treated as behavior evidence | placeholder-ime.test.ts, firefox-direct-ime.test.ts, ime-proxy.test.ts, 2026-04-12-appium-ios-safari-loads-local-slate-routes-but-xcuitest-value-does-not-drive-contenteditable.md, package.json | playwright + site/examples + browser-mobile transports |
| [x] | inline-edge IME | packages/slate-react/src/components/editable.tsx, packages/slate-react/src/components/string.tsx | Editable, EditableText, inline-edge example | inline-edge-ime.test.ts, firefox-direct-ime.test.ts, webkit-direct-ime-ceiling.test.ts, ime-proxy.test.ts, proof:agent-browser:ios:inline-edge-input:local, proof:appium:android:inline-edge-input:local | automated-direct: chromium + firefox + iOS Simulator Safari + Android Chrome emulator, automated-proxy: webkit-desktop, plus direct-input ceiling: webkit-desktop | inline-edge composition lands on the intended text leaf with legacy-equivalent behavior | Chromium direct proof is green after semantic selection setup, Firefox now has a stronger direct composition lane via Playwright keyboard.insertText, desktop WebKit has an explicit direct-input ceiling probe showing that insertText commits cleanly but stays below composition-specific proof, and the packaged iOS Simulator/Appium edge-input lanes are green once the runner collapses DOM selection onto the leading zero-width text leaf before typing | inline-edge-ime.test.ts, firefox-direct-ime.test.ts, webkit-direct-ime-ceiling.test.ts, ime-proxy.test.ts, 2026-04-04-inline-edge-ime-proofs-should-set-selection-semantically-before-composition.md, package.json | playwright + site/examples + browser-mobile transports | open |
| [x] | void-edge IME | packages/slate-react/src/components/editable.tsx, packages/slate-react/src/components/string.tsx | Editable, EditableText, void-edge example | void-edge-ime.test.ts, firefox-direct-ime.test.ts, webkit-direct-ime-ceiling.test.ts, ime-proxy.test.ts, proof:agent-browser:ios:void-edge-input:local, proof:appium:android:void-edge-input:local | automated-direct: chromium + firefox + iOS Simulator Safari + Android Chrome emulator, automated-proxy: webkit-desktop, plus direct-input ceiling: webkit-desktop | void-like IME behavior matches the relied-on spacer semantics | Chromium direct proof is green on the real spacer structure, Firefox now has a stronger direct composition lane via Playwright keyboard.insertText, desktop WebKit keeps an explicit direct-input ceiling probe instead of fake direct composition proof, and the packaged iOS Simulator/Appium edge-input lanes are green with the same zero-width selection-collapse primitive used before typing | void-edge-ime.test.ts, firefox-direct-ime.test.ts, webkit-direct-ime-ceiling.test.ts, ime-proxy.test.ts, 2026-04-04-void-like-zero-width-ime-proofs-need-the-real-void-spacer-structure.md, package.json | playwright + site/examples + browser-mobile transports | open |
| [x] | blur/focus selection recovery | packages/slate-react/src/components/editable.tsx, packages/slate-react/test/react-editor.spec.tsx | Editable, ReactEditor, rich-inline reset/refocus flow | surface-contract.tsx, rich-inline.test.ts, test:slate-browser:desktop-parity:local | headless + automated-direct: chromium, firefox, webkit-desktop | focus restore behaves at least as safely as legacy across the required browser matrix | current focus init and mid-transform safety are green in headless proof, and the rich-inline blur/focus reset row is now green on Chromium, Firefox, and desktop WebKit; real iOS Safari remains unproved | surface-contract.tsx, rich-inline.test.ts, package.json | packages/slate-react + playwright | open |
| [x] | transient DOM-point gap / mutation-repair / fail-closed focus restore | packages/slate-react/src/components/restore-dom/restore-dom.tsx, packages/slate-react/src/components/restore-dom/restore-dom-manager.ts, packages/slate-react/src/components/editable.tsx | mounted Editable, ReactEditor, DOMBridge | surface-contract.tsx, main IME/browser rows, structural split/join row | headless, automated-direct: chromium, firefox, android emulator, plus automated-proxy: webkit-desktop | transient DOM bridge gaps fail closed without hidden runtime errors and without regressing user-visible behavior | current focus-time transient DOM-point failure is covered and fails closed; main IME rows are green without restore-dom; structural Enter/Backspace churn is now green on Chromium and Android through editor-owned keydown paths; the deleted restore-dom family is now treated as a rerender-era guard that is no longer a standalone current blocker | surface-contract.tsx, 2026-04-09-slate-react-focus-restore-must-fail-closed-on-transient-dom-point-gaps.md, 2026-04-12-restore-dom-was-a-rerender-era-guard-not-a-current-v2-runtime-need.md, 2026-04-12-structured-enter-and-backspace-need-editor-owned-keydown-paths.md | packages/slate-react + packages/slate-dom | closed |
| [x] | zero-width selection normalization | packages/slate-react/src/components/string.tsx, packages/slate-react/src/components/editable.tsx | DOMBridge, slate-browser selection helpers, zero-width matrix example | zero-width-matrix.test.ts, bridge.ts tests, test:slate-browser:desktop-parity:local | automated-direct: chromium, firefox, webkit-desktop plus headless bridge proof | DOM/Slate round-trip around zero-width leaves stays normalized instead of leaking sentinel offsets | current bridge proof is green, and the zero-width matrix row is now green on Chromium, Firefox, and desktop WebKit; real iOS Safari remains unproved | zero-width-matrix.test.ts, 2026-04-03-zero-width-dom-selection-bridges-must-normalize-both-directions.md, 2026-04-04-slate-browser-playwright-helpers-must-normalize-zero-width-selection-and-wait-for-selection-sync.md, package.json | packages/slate-dom + slate-browser | open |
| [x] | post-composition undo / redo | packages/slate-react/src/components/editable.tsx | withHistory(createEditor()), browser/history proof stack, IME proof surfaces | placeholder-ime.test.ts, inline-edge-ime.test.ts, void-edge-ime.test.ts, test:slate-browser:ime:local | automated-direct: chromium | undo and redo immediately after composition are directly proved on the placeholder/inline-edge/void-edge rows | dedicated IME history proof now exists on the FEFF placeholder path, no-FEFF placeholder path, inline-edge path, and void-edge path in Chromium; broader platform/browser IME parity is still blocked elsewhere | placeholder-ime.test.ts, inline-edge-ime.test.ts, void-edge-ime.test.ts, package.json | packages/slate-history + playwright | open |
| [x] | Android composition / diff / flush | packages/slate-react/src/hooks/android-input-manager/android-input-manager.ts, packages/slate-react/src/hooks/android-input-manager/use-android-input-manager.ts, packages/slate-react/src/components/editable.tsx | missing direct equivalent; current owner hypothesis is mounted Editable plus browser proof lanes | android-tests.test.ts, test:slate-browser:android-proxy:local, proof:appium:android:local, proof:appium:android:placeholder-input:local, proof:appium:android:inline-edge-input:local, proof:appium:android:void-edge-input:local, proof:appium:android:split-join:local, proof:appium:android:empty-rebuild:local, proof:appium:android:remove-range:local, android-split-join.test.ts, android-empty-rebuild.test.ts, android-remove-range.test.ts, android-special-structural.test.ts | automated-proxy: mobile Chromium, automated-direct: Android Chrome emulator IME rows plus split/join, empty/delete-rebuild, remove-range, and special structural rows, plus remaining-android-specific: autocorrect / glide / voice | Android-specific composition/diff/flush behavior is directly proved or explicitly justified as engine-internal | the Android hub exists, the mobile Playwright proxy lane is green on placeholder/inline-edge/void-edge plus IME undo/redo, Appium now has direct green packaged rows for placeholder, inline-edge, void-edge, split/join, empty/delete-rebuild, and remove-range on Android Chrome emulator, and the matching Chromium rows for split/join, empty, remove, and the structural special subcases are also green. The remaining Android-specific open slice is now the keyboard-feature lane only. Direct local probes can show keyboardShown: true and switch to NATIVE_APP, but expose zero Gboard candidate nodes, and hardware keycodes only yield literal cant insertion, so autocorrect / glide / voice are explicitly tooling-blocked on the current local stack | android-tests.test.ts, android-split-join.test.ts, android-empty-rebuild.test.ts, android-remove-range.test.ts, android-special-structural.test.ts, package.json, 2026-04-11-appium-android-setup-proof.md, 2026-04-12-structured-enter-and-backspace-need-editor-owned-keydown-paths.md, 2026-04-12-structural-break-proof-rows-need-selection-sync-before-follow-up-typing.md, 2026-04-12-appium-android-chrome-can-show-keyboard-state-without-exposing-gboard-candidates.md, packages/slate-react/src/hooks/android-input-manager/android-input-manager.ts | platform parity lane | tooling-blocked / external |
| [x] | iOS Safari / WebKit composition / focus | packages/slate-react/src/components/editable.tsx | Editable, ReactEditor, DOMBridge | desktop parity lane, explicit WebKit direct-input ceiling lane, composition proxy lane, proof:agent-browser:ios:local, proof:agent-browser:ios:placeholder-input:local, proof:agent-browser:ios:inline-edge-input:local, proof:agent-browser:ios:void-edge-input:local, plus missing real-device lane | automated-direct: webkit-desktop for focus/selection, direct-input ceiling: webkit-desktop, automated-proxy: webkit-desktop for composition, automated-direct: mixed iOS Simulator Safari rows, tooling-blocked: broader iOS Safari composition/focus | iOS Safari / WebKit composition and focus behavior is directly proved or explicitly justified as non-behavioral | desktop WebKit has direct proof for zero-width normalization and blur/focus recovery, an explicit direct-input ceiling probe showing that Playwright insertText does not expose composition-specific input events there, and a green browser-level proxy composition lane on the IME surfaces. On iOS Simulator Safari, direct Appium route/setup is green, inline-edge and void-edge have direct green packaged rows, but placeholder and no-FEFF placeholder typing remain behavior-red through XCUITest value. Broader iOS Safari composition/focus remains tooling-blocked, and the external plan now lives in 2026-04-12-ios-safari-broader-composition-focus-external-evidence-plan.md | rich-inline.test.ts, zero-width-matrix.test.ts, webkit-direct-ime-ceiling.test.ts, ime-proxy.test.ts, 2026-04-11-slate-browser-agent-browser-ios-setup-proof.md, 2026-04-12-appium-ios-safari-loads-local-slate-routes-but-xcuitest-value-does-not-drive-contenteditable.md, package.json | platform parity lane | tooling-blocked / non-RC |
| [x] | Firefox composition / selection recovery | packages/slate-react/src/components/editable.tsx | Editable, EditableBlocks, ReactEditor, DOMBridge, drag/drop cleanup example, table multi-range example, nested-editable focus example | desktop parity lane plus direct composition lane plus proxy backstop plus dedicated drag/drop, table multi-range, and nested-editable lanes | automated-direct: firefox for selection recovery, IME composition, dragged-node-unmount cleanup, table multi-range preservation, and nested-editable focus bounce, automated-proxy: firefox + webkit-desktop backstop | Firefox composition, selection recovery, dragged-node-unmount cleanup, table multi-range preservation, and nested-editable focus bounce are directly proved or explicitly justified as non-behavioral | Firefox now has direct browser proof for blur/focus selection recovery, zero-width normalization, direct composition on placeholder, no-FEFF placeholder, inline-edge, and void-edge via Playwright keyboard.insertText, plus dedicated drag/drop, multi-range table, and nested-editable focus lanes. Local Firefox/browser parity is exhausted; the remaining work is external Android keyboard-feature evidence and broader iOS evidence, not another Firefox hole | rich-inline.test.ts, zero-width-matrix.test.ts, firefox-direct-ime.test.ts, drag-drop-cleanup.test.ts, table-multi-range-firefox.test.ts, firefox-nested-editable-focus.test.ts, ime-proxy.test.ts, package.json, 2026-04-12-firefox-drag-drop-proof-needs-example-owned-drop-mutation-and-document-level-drag-cleanup.md, 2026-04-12-firefox-table-multi-range-proof-needs-native-table-selection-and-a-multi-range-sync-guard.md, 2026-04-12-firefox-nested-editable-focus-proof-needs-a-real-nested-contenteditable-surface.md | platform parity lane | local-closed |
compositionstart/compositionend plus DOM-commit seam.?debug=1.firefox-direct-ime.test.tsspecial?debug=1ReactEditor and DOMBridge are now reviewed as current ownersbeforeinput is non-cancelable on Android, so legacy routed it through the
Android input manager instead of the normal DOM pathPrimary legacy evidence:
execCommand('indent')
/ deselect workaround pathbeforeinput(insertFromComposition) before
compositionend, so composition state had to be cleared earlyInputEvents could miss the Slate fragment payload, requiring
the clipboard fallback pathPrimary legacy evidence:
setDomSelectiondragend listening because dragged nodes
could unmount before their own dragendPrimary legacy evidence: