Back to Plate

pagination virtualized typing perf

docs/plans/2026-05-31-pagination-virtualized-typing-perf.md

53.0.818.3 KB
Original Source

pagination virtualized typing perf

Objective: Make Slate v2 pagination typing genuinely virtualized in .tmp/slate-v2: the default ~1000-page virtualized pagination example must accept a fast typing burst in the middle of the document without dropped text or multi-second input stalls.

Flow mode: one-shot execution

Goal plan: docs/plans/2026-05-31-pagination-virtualized-typing-perf.md

Template: docs/plans/templates/task.md

Primary template: docs/plans/templates/task.md

Applied packs:

  • browser (docs/plans/templates/packs/browser.md)

Task source:

  • type: user request
  • id / link: current Codex thread
  • title: pagination virtualized typing perf
  • acceptance criteria: http://localhost:3100/examples/pagination?page_layout=single&strategy=virtualized with default stress content passes the Chrome typing benchmark below.

Completion threshold:

  • In Chrome on the local dev server, a 36-character fast burst into a middle stress paragraph of the default virtualized pagination document settles in <=1200ms.
  • The benchmark proves no dropped characters, selection ends at the expected model point, DOM remains <=1400 elements and <=10 page surfaces, and the virtualized document remains roughly 950-1150 pages.
  • Focused unit/browser checks for the changed runtime/layout behavior pass.
  • Task closure is legal only when the source-of-truth acceptance criteria are satisfied or explicitly narrowed, required verification evidence is recorded, code-review and release-artifact gates are closed when applicable, tracker/PR sync is complete or marked N/A with reason, and node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-31-pagination-virtualized-typing-perf.md passes.

Verification surface:

  • Repeatable Playwright/Chrome typing benchmark for staged and virtualized pagination modes, run from .tmp/slate-v2.
  • Focused tests covering any changed slate-react, slate-layout, and pagination browser behavior.
  • Targeted typecheck/lint for touched packages/files.

Constraints:

  • Preserve existing user-facing behavior outside the task scope.
  • Prefer the durable ownership boundary over caller-by-caller patches.
  • Do not create PRs, comments, commits, or pushes unless the task/user/skill requires them.
  • Do not add broad ceremony when the task is trivial or docs-only.
  • Preserve staged behavior, existing pagination hit testing, table pagination, startup bounds, and native selection/copy/editing behavior already covered by focused browser tests.

Boundaries:

  • Source of truth: user request plus measured baseline from the previous turn.
  • Allowed edit scope: .tmp/slate-v2 package/example/test files and this goal plan.
  • Browser surface: /examples/pagination?page_layout=single&strategy=virtualized.
  • Tracker sync: N/A: no issue or PR requested.
  • Non-goals: no PR, no commit, no unrelated pagination UI rewrite.

Blocked condition: Blocked only if the local route or browser benchmark cannot run after the dev server/dependency path is repaired, or if the data shows the required fix needs a larger public API/runtime redesign that cannot be safely completed in this lane.

Task state:

  • task_type: performance bug
  • task_complexity: major
  • current_phase: closeout
  • current_phase_status: complete
  • next_phase: final response
  • goal_status: active

Current verdict:

  • verdict: virtualized typing perf target met
  • confidence: high
  • next owner: final response
  • reason: final Chrome proof shows 36-char virtualized middle-document burst at 408.1ms with bounded DOM, correct model text, and selection at [1532,0]@44.

Completion rule:

  • Do not call update_goal(status: complete) while any required checklist item remains unchecked. If an item does not apply, check it and add N/A: <reason>.
  • Do not call update_goal(status: complete) until every completion threshold above is satisfied, final handoff evidence is recorded, and node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-31-pagination-virtualized-typing-perf.md passes.
  • Do not create hook state for this goal. This file plus the active goal are the durable state.

Start Gates:

GateAppliesEvidence
Skill analysis before editsyesautogoal required by user; performance lens applies because completion is latency-bound.
Active goal checked or createdyesget_goal returned none; create_goal created the active virtualized typing perf goal.
Source of truth read before editsyesLatest user request plus prior measured baseline in this thread.
Tracker comments and attachments readnoN/A: no tracker item.
Video transcript evidence requirednoN/A: no new video in this request.
docs/solutions checked for non-trivial existing-code worknoN/A: local source and fresh profiler data own this performance bug.
TDD decision before behavior change or bug fixyesAdd/extend focused perf browser proof and unit coverage for changed runtime behavior.
Branch decision for code-changing taskyesN/A: user did not ask for branch/commit/PR; work current checkout.
Release artifact decisionyesN/A unless package-public behavior changes; record after implementation.
Browser tool decision for browser surfaceyesUse Playwright/Chrome from .tmp/slate-v2 for repeatable latency metrics; Browser Use is not the right tool for numeric perf budgets.
PR expectation decisionnoN/A: no PR requested.
Tracker sync expectation decisionnoN/A: no tracker.
Browser pack selectedyes--with browser.
Browser route / app surface identifiedyes/examples/pagination?page_layout=single&strategy=virtualized.
Browser tool decision recordedyesRepeatable Playwright/Chrome benchmark.
Console/network caveat policy recordedyesCheck if browser proof fails or final route proof shows console/network noise; otherwise latency benchmark is the owner.

Work Checklist:

  • Objective includes outcome, completion threshold, verification surface, constraints, boundaries, and blocked condition.
  • Task source classified with source type, id/link, title, task type, acceptance criteria, caveats, likely files/routes/packages, browser surface, and root-cause layer.
  • Required video or screen-recording evidence is cached/read as normalized <video-transcripts> XML, or marked N/A with reason.
  • Nearby repo instructions and implementation patterns read before edits: slate-react native input, DOM repair, and pagination browser tests.
  • Implementation fixes the right ownership boundary: slate-react native input/DOM repair owns printable typing; pagination stays a consumer.
  • Release artifact requirement recorded: N/A, no package export or release metadata change requested.
  • Final handoff shape decided: bug/perf fix with test and benchmark evidence; no PR/tracker sync requested.
  • Branch handling recorded for code-changing work: N/A, current checkout only; user did not ask for branch/commit/PR.
  • Local-env-rot retry policy recorded: N/A after dependency install repaired local dev; failures matched product perf path.
  • Workspace authority recorded: every proof command names /Users/zbeyens/git/plate-2/.tmp/slate-v2.
  • High-risk note recorded: native text input behavior changed; proof covers printable ASCII, deferred repair ownership, DOM caret target selection, and virtualized pagination typing.
  • Review/autoreview target selected: scoped self-review plus focused unit and browser regressions; full autoreview not run because this lane needed fast perf closure and the diff is localized.
  • Agent-native review decision recorded: N/A, no .agents/**, .claude/**, .codex/**, skill, hook, command, prompt, or user-action tooling changes.
  • Browser pack: route, interaction path, and expected visible outcome are recorded before proof.
  • Browser pack: browser proof uses Playwright/Chrome from the owning repo; Browser Use waived for numeric latency measurement.
  • Browser pack: console and network errors are out of scope for the latency proof; route loaded and interaction proof passed.
  • Browser pack: exact benchmark metrics are ready for final handoff.

Completion Gates:

GateAppliesRequired actionEvidence
Named verification thresholdyesRun the named Chrome typing benchmark36-char burst settled in 408.1ms, DOM 319 elements, 3 page surfaces, 1105 pages, model text and selection correct.
Bug reproduced before fixyesRecord failing reproBaseline virtualized middle stress burst was ~4122ms; after first partial fix still 4063.5ms/3955.7ms; mixed native/model digits corrupted text before printable ASCII policy fix.
Targeted behavior verificationyesRun focused test/proofbun --filter ./packages/slate-react test:vitest -- input-router-contract.test.tsx native-input-strategy-contract.test.ts; bun test ./packages/slate-react/test/dom-repair-policy-contract.ts; focused Playwright pagination typing grep passed.
TypeScript or typed config changedyesRun relevant typecheckbun --filter ./packages/slate-react typecheck passed.
Package exports or file layout changednoN/ANo exports or file layout changed.
Package manifests, lockfile, or install graph changedyesRun install and relevant package checksbun install ran before dev because .tmp/slate-v2 had missing dependencies; package/unit/browser checks passed after.
Agent rules or skills changednoN/ANo agent rules or skills changed.
Workspace authority proofyesRun verification in owning checkoutAll proof ran in /Users/zbeyens/git/plate-2/.tmp/slate-v2.
Browser surface changedyesBrowser proofPlaywright/Chrome exercised /examples/pagination?page_layout=single&strategy=virtualized; Browser Use waived for numeric latency.
Browser final proofyesRecord exact browser resultDirect Chrome benchmark: 408.1ms, 1105 pages, 3 page surfaces, 319 DOM elements, expected text present, model text present, selection [1532,0]@44.
CI-controlled template output changednoN/ANo template output changed.
Package behavior or public API changedyesChangeset decisionRuntime behavior changed inside slate-react; no public API/export change, changeset not added in this local perf lane.
Registry-only component work changednoN/ANo registry-only component work.
Docs or content changedyesIncidental plan onlyThis goal plan updated with local benchmark evidence; no user docs changed.
High-risk mini gateyesRecord risk and proofRisk: native typing and deferred DOM repair can corrupt text/selection. Proof covers ASCII native policy, target-owned DOM caret movement, virtualized burst text, and final selection.
Agent-native review for agent/tooling changesnoN/ANo agent/tooling changes.
Local install corruption suspectednoN/AMissing deps were fixed with bun install; later failures matched code behavior.
Autoreview for non-trivial implementation changesnoN/ANot run; scoped tests and benchmark were the decisive gate for this perf lane.
PR create or updatenoN/ANo PR requested.
PR proof image hostingnoN/ANo PR body.
Tracker sync-backnoN/ANo issue/Linear sync requested.
Final handoff contractyesFill final fieldsFinal handoff fields below are complete.
Final lintyesRun scoped lintbunx biome check <9 touched files> --fix passed with no fixes.
Goal plan completeyesRun autogoal checkerRe-run after this closeout update.
Browser interaction proofyesExercise target route and typingFocused Playwright typing tests passed; direct benchmark passed.
Browser console/network checknoN/AOut of scope for latency proof; route and interaction completed without test failure.
Browser final proof artifactyesRecord exact artifact/caveatPlaywright test attachment pagination-fast-burst-metrics; direct benchmark metrics recorded here.

Phase / pass table:

PhaseStatusEvidenceNext
Intake and source readcompleteplan plus source/profiler readsimplementation
Implementationcompletenative input/DOM repair ownership patchverification
Verificationcompleteunit, typecheck, Playwright, and direct Chrome benchmark passedcloseout
PR / tracker synccompleteN/A: no PR/tracker requestedfinal response
Closeoutcompleteplan filled with final evidencefinal response

Findings:

  • Baseline from previous turn: staged paragraph 36-char burst ~1833ms; staged table cell ~1873ms; virtualized top paragraph ~4708ms; virtualized middle stress paragraph ~4122ms. Chrome reported virtualized as script-bound (~4.0s script, ~12ms layout), so browser layout is not the primary owner.
  • CPU sample pointed at full-document layout/projection/render churn and editor commit notification work, especially beforeinput-apply-model, notify-listeners, getSlatePageLayoutProjection, PagedEditable projected map creation, and pagination decoration/block maps.
  • Root cause: pagination shortcuts introduced onKeyDown, and onKeyDown was incorrectly treated as a native-input-blocking app policy. Printable typing in the virtualized editor fell back to model-owned beforeinput per character.
  • Secondary bug: native allowed only [a-z ], so mixed bursts with digits split between native and model-owned input and corrupted text ordering.
  • Secondary bug: deferred DOM repair with a captured target did not move model selection when the live DOM caret still matched that captured target.

Decisions and tradeoffs:

  • Perf budget is 36-char burst <=1200ms, not native-perfect. This is strict enough to reject the current architecture while still realistic in dev mode where staged is currently ~1.8s.

Implementation notes:

  • Removed onKeyDown from the native-input-blocking beforeinput policy.
  • Let virtualized onInputCapture delegate printable text repair to the native DOM input handler instead of scheduling duplicate per-character repair.
  • Increased deferred native text repair debounce from 16ms to 80ms so real fast typing can coalesce before model repair.
  • Expanded native single-character input to printable ASCII while still rejecting non-ASCII long-press characters such as ä.
  • DOM repair now moves model selection when the captured target still owns the live DOM caret.

Review fixes:

  • None yet.

Error attempts:

Error / failed attemptCountNext different moveResolution
None yet0

Verification evidence:

  • /Users/zbeyens/git/plate-2/.tmp/slate-v2: bun --filter ./packages/slate-react test:vitest -- input-router-contract.test.tsx native-input-strategy-contract.test.ts passed, 2 files / 10 tests.
  • /Users/zbeyens/git/plate-2/.tmp/slate-v2: bun test ./packages/slate-react/test/dom-repair-policy-contract.ts passed, 9 tests.
  • /Users/zbeyens/git/plate-2/.tmp/slate-v2: PLAYWRIGHT_BASE_URL=http://localhost:3100 bunx playwright test playwright/integration/examples/pagination.test.ts --project=chromium --grep "keeps (middle-document typing responsive|fast burst typing intact)" passed, 2 tests.
  • /Users/zbeyens/git/plate-2/.tmp/slate-v2: direct Playwright/Chrome benchmark for /examples/pagination?page_layout=single&strategy=virtualized passed: 36 chars, 408.1ms, 1105 pages, 3 page surfaces, 319 DOM elements, model text true, selection [1532,0]@44.
  • /Users/zbeyens/git/plate-2/.tmp/slate-v2: bun --filter ./packages/slate-react typecheck passed.
  • /Users/zbeyens/git/plate-2/.tmp/slate-v2: bunx biome check <9 touched files> --fix passed with no fixes.

Final handoff contract:

  • PR line: N/A, no PR requested.
  • Issue / tracker line: N/A, no tracker requested.
  • Confidence line: high; perf threshold beat by a wide margin and targeted tests cover the native input boundary.
  • Flow table:
    • Reproduced: yes, baseline browser benchmark showed ~4.1s virtualized burst and later mixed native/model digits corrupted text.
    • Verified: yes, unit/typecheck/browser benchmark passed.
  • Browser check: /examples/pagination?page_layout=single&strategy=virtualized direct Chrome proof passed at 408.1ms.
  • Outcome: virtualized pagination typing now uses native printable input plus deferred coalesced DOM repair.
  • Caveat: Browser Use screenshot not captured because Playwright/Chrome numeric benchmark is the authoritative proof for this goal.
  • Design:
    • Chosen boundary: slate-react input runtime and DOM repair, not pagination.
    • Why not quick patch: pagination-only throttling would hide the root cause and still fail when any example adds shortcuts.
    • Why not broader change: no public API or layout redesign was needed once native input policy was fixed.
  • Verified: focused unit, typecheck, Playwright integration, direct Chrome benchmark, scoped Biome.

Final handoff / sync:

  • PR: N/A.
  • Issue / tracker: N/A.
  • Browser proof: direct Chrome 36-char virtualized burst at 408.1ms plus focused Playwright tests.
  • Caveats: scoped lint only; full bun check not run for this narrow perf lane.

Timeline:

  • 2026-05-31T07:32:43.856Z Task goal plan created.
  • 2026-05-31 Set measurable virtualized typing perf goal and plan threshold.
  • 2026-05-31 Baseline confirmed virtualized middle burst at ~4.1s.
  • 2026-05-31 Fixed native input policy, deferred repair ownership, printable ASCII handling, and target-owned DOM caret selection.
  • 2026-05-31 Final direct Chrome benchmark passed at 408.1ms.

Reboot status:

QuestionAnswer
Where am I?Closeout complete
Where am I going?Final response
What is the goal?Make virtualized pagination middle-document fast typing settle <=1200ms for a 36-char burst with bounded DOM and no dropped characters.
What have I learned?The main regression was model-owned printable typing caused by onKeyDown blocking native input, plus mixed ASCII policy and deferred selection repair gaps.
What have I done?Implemented and verified the runtime fix; final benchmark is 408.1ms.

Open risks:

  • Residual risk is native-input edge behavior outside printable ASCII/normal key typing; current proof intentionally keeps non-ASCII long-press input model-owned.