Skip to content

Derive every editor mutation through one seam so Escape reaches your core#129

Open
ctate wants to merge 4 commits into
mainfrom
fix/escape-edit-derivation
Open

Derive every editor mutation through one seam so Escape reaches your core#129
ctate wants to merge 4 commits into
mainfrom
fix/escape-edit-derivation

Conversation

@ctate

@ctate ctate commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Fixes the launch-round live-smoke finding: pressing Escape in a search field cleared the runtime's text editor visually while the core never heard about it — model.query diverged from the screen, the list stayed filtered under an empty field, and the next keystroke dispatched against the stale query.

The root cause was architectural: some editor mutations derived core events (typing, paste, the clear button) while others were runtime-local operations that bypassed derivation. Mapping every mutation source found five bypassing paths: Escape-clear, Escape composition-cancel, ArrowUp/Down caret moves on single-line kinds, and the automation/AX composition and selection verbs.

  • One choke point: the runtime derives each keyboard editor mutation once and stamps it onto the routed event before applying it; both tiers' app dispatch consume the stamped edit (local derivation kept only as fallback for events that never crossed the runtime). Any future derivation arm automatically reaches the core. Stamping happens even when applying is a no-op, so an already-diverged mirror resyncs.
  • No wire change: the existing clear arm expresses it — Escape now looks to the core exactly like the clear button always did — so the journal format is untouched and replay reproduces the clear byte-identically (the reference record→replay session now drives an Escape-clear and pins identical model state, fingerprints, and per-frame checkpoints).
  • Automation composition verbs now dispatch real IME platform events (journaled — they previously weren't), and set_selection synthesizes the same stamped keyboard event the context-menu edits use.
  • Pinned in both tiers: a runtime test that provably fails without the stamp, the record→replay pins, the Zig soundboard live test, and the soundboard-ts e2e.

Flagged for follow-up (design questions, deliberately not implemented here): pointer-placed selection reaching on_input (needs coalescing), automation set_selection replay honesty (needs a wire-level selection input kind), and the raw editCanvasWidgetText host API's mirror contract.

Suites: validate, test-examples-native, test-ts-core-e2e green; zig build test's five step-runner noise lines reproduce identically on clean main (every flagged binary passes directly).

ctate added 4 commits July 13, 2026 15:33
- updateCanvasWidgetTextFromKeyboard now stamps the edit it derives and applies onto the routed event, so the app dispatch hears exactly what the retained editor did — Escape's search-field clear, its composition cancel, and the single-line ArrowUp/Down caret jumps were runtime-only before and never reached the model.
- The app-side msgForKeyboard consumes the stamped edit first and keeps its own derivation only as the fallback for events that never crossed the runtime.
- The context-menu edit path routes through the same seam and dispatches the stamped event.
- widget-action set_composition/commit_composition/cancel_composition now dispatch the ime gpu input events a live IME session produces: journaled for replay, applied by the editor, and mirrored to the core's on_input — direct editor writes kept the model out of the loop.
- set_selection synthesizes the stamped keyboard event the clipboard edits use, so the core's selection mirror follows; it stays un-journaled (no selection input kind exists on the wire).
- The accessibility action dispatch and the mobile widget-action ABI funnel through the same verbs, so all three surfaces converge.
- ui_app tests drive a search field through Escape, ArrowUp, ime cancel, and the automation composition/selection verbs, asserting the model mirror and the retained editor agree.
- The reference record/replay session types into a search field and Escape-clears it, so replay must re-derive the same clear from the raw journaled events.
- Soundboard e2e batteries (Zig live app and transpiled TS core) pin Escape clearing the query and unfiltering the library.
- User-facing story: Escape in a search field now reaches your core, plus the automation composition verbs riding the real input path.
@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
native-sdk Ready Ready Preview, Comment Jul 13, 2026 8:55pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant