docs/plans/2026-05-26-slate-v2-synced-blocks-selection-history-coverage.md
Objective: Expand Slate v2 Synced Blocks selection/history coverage and list the current browser bugs around full-document keyboard navigation, Shift selection, Cmd/Meta+Arrow behavior, and history focus across repeated content-root projections.
Goal plan: docs/plans/2026-05-26-slate-v2-synced-blocks-selection-history-coverage.md
Template: docs/plans/templates/task.md
Primary template: docs/plans/templates/task.md
Applied packs:
Task source:
/examples/synced-blocks fixture if more coverage needs another synced block
from a different document.Completion threshold:
/examples/synced-blocks has enough fixture data to prove repeated synced
copies and a different synced document root..tmp/slate-v2; larger
bugs are listed with exact repro and owner.slate-react package tests
pass, or unresolved rows are intentionally marked as known failing/skipped
with reasons.node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-26-slate-v2-synced-blocks-selection-history-coverage.md passes.Verification surface:
.tmp/slate-v2/playwright/integration/examples/synced-blocks.test.ts.tmp/slate-v2/packages/slate-react/test/content-root-navigation-contract.test.tshttp://localhost:3100/examples/synced-blocksslate-react Vitest when runtime/navigation code changes.Constraints:
Boundaries:
.tmp/slate-v2/packages/slate-react/**,
.tmp/slate-v2/site/examples/ts/synced-blocks.tsx,
.tmp/slate-v2/playwright/integration/examples/synced-blocks.test.ts, and
this plan.http://localhost:3100/examples/synced-blocks.Blocked condition:
Task state:
Current verdict:
Completion rule:
update_goal(status: complete) while any required checklist item
remains unchecked. If an item does not apply, check it and add N/A: <reason>.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-26-slate-v2-synced-blocks-selection-history-coverage.md passes.Start Gates:
| Gate | Applies | Evidence |
|---|---|---|
| Skill analysis before edits | yes | task, testing, and autogoal loaded before edits. |
| Active goal checked or created | yes | Active goal created for this coverage slice. |
| Source of truth read before edits | yes | User prompt plus Synced Blocks source/test files read. |
| Tracker comments and attachments read | no | N/A: no tracker. |
| Video transcript evidence required | no | N/A: no video. |
docs/solutions checked for non-trivial existing-code work | no | N/A: this is live browser coverage on new local feature surface. |
| TDD decision before behavior change or bug fix | yes | Add browser/unit regression rows before or with fixes. |
| Branch decision for code-changing task | yes | No PR/commit requested; keep current checkout as-is. |
| Release artifact decision | yes | Existing synced content-root changeset covers public slot/API; this slice adds tests/bugfix unless public API changes. |
| Browser tool decision for browser surface | yes | Use Playwright for committed browser rows and in-app Browser/browser-use for final route proof if code changes affect visible behavior. |
| PR expectation decision | yes | No PR requested. |
| Tracker sync expectation decision | yes | N/A: no tracker. |
| Browser pack selected | yes | Browser pack selected by scratchpad helper. |
| Browser route / app surface identified | yes | http://localhost:3100/examples/synced-blocks. |
| Browser tool decision recorded | yes | Playwright plus in-app Browser final proof if needed. |
| Console/network caveat policy recorded | yes | Runtime error guard for known Slate errors in browser tests; final browser proof records console caveat. |
Work Checklist:
<video-transcripts> XML, or marked N/A with reason..agents/**, .claude/**,
.codex/**, skills, hooks, commands, prompts, or user-action tooling.Completion Gates:
| Gate | Applies | Required action | Evidence |
|---|---|---|---|
| Named verification threshold | yes | Done: run the named browser/package/typecheck/lint/check commands | bun check, focused Vitest, focused Playwright, all-project Synced Blocks Playwright, and completion checker close this threshold. |
| Bug reproduced before fix | yes | Done: encode rows in package/browser tests before closeout | Repeated-root exit/entry and history-focus bugs are covered by new regression rows; Shift+Arrow cross-root expansion is recorded as a larger follow-up. |
| Targeted behavior verification | yes | Done: run focused test/proof for changed behavior | Synced Blocks Playwright: 25 passed, 15 intentionally skipped outside Chromium; navigation contract Vitest passed. |
| TypeScript or typed config changed | yes | Done: run relevant typecheck | .tmp/slate-v2: bun --filter slate-react typecheck passed; bun check typecheck stage passed. |
| Package exports or file layout changed | no | N/A: no package export or file layout changes. | N/A: no pnpm brl required. |
| Package manifests, lockfile, or install graph changed | no | N/A: no manifest, lockfile, or install graph changes. | N/A: install not required. |
| Agent rules or skills changed | no | N/A: no .agents source edits. | N/A: generated skill sync not required. |
| Workspace authority proof | yes | Done: run verification in .tmp/slate-v2. | All package/browser commands were run with cwd /Users/zbeyens/git/plate-2/.tmp/slate-v2 except the root autogoal checker for this plan. |
| Browser surface changed | yes | Done: exercise route by Playwright browser rows. | PLAYWRIGHT_BASE_URL=http://localhost:3100 ... synced-blocks.test.ts passed on Chromium and all configured projects. |
| Browser final proof | yes | Done: use exact browser verification caveat. | Proof is automated Playwright route interaction coverage, not a manual screenshot. |
| CI-controlled template output changed | no | N/A: no template output changed. | N/A. |
| Package behavior or public API changed | yes | Done: add changeset. | .tmp/slate-v2/.changeset/synced-content-root-slots.md covers editable content-root slot and active-copy navigation/history behavior. |
| Registry-only component work changed | no | N/A: not registry-only component work. | N/A. |
| Docs or content changed | yes | Done: source-backed plan only. | This plan records evidence; no user docs changed. |
| High-risk mini gate | yes | Done: record failure mode and boundary. | Runtime/browser behavior risk is root-owner identity drift; fixed at runtime context/navigation boundary and proved by repeated-copy tests. |
| Agent-native review for agent/tooling changes | no | N/A: no agent/tooling changes. | N/A. |
| Local install corruption suspected | no | N/A: no failure matched local install corruption. | N/A: reinstall not run. |
| Autoreview for non-trivial implementation changes | yes | Attempted and blocked by tool/runtime failure. | Claude no-tools run hung and was killed; Codex no-tools rejected --no-tools; bounded Codex scoped run timed out after 180s with exit code 124 and no output. |
| PR create or update | no | N/A: no PR requested. | N/A: no check or PR body sync required. |
| PR proof image hosting | no | N/A: no PR body. | N/A. |
| Tracker sync-back | no | N/A: no tracker. | N/A. |
| Final handoff contract | yes | Done: fill fields below. | Final handoff records bugs, tests, caveats, and no PR/commit. |
| Final lint | yes | Done: run lint fixer and lint. | .tmp/slate-v2: bun lint:fix passed; bun lint passed. |
| Goal plan complete | yes | Done. | node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-26-slate-v2-synced-blocks-selection-history-coverage.md passed. |
| Browser interaction proof | yes | Done: exercise route interactions. | Full keyboard paths covered by Playwright on http://localhost:3100/examples/synced-blocks. |
| Browser console/network check | yes | Done by test failure policy. | Playwright route tests would fail on runtime errors; no separate network assertion was needed for local static example. |
| Browser final proof artifact | yes | Done: exact caveat recorded. | Automated Playwright proof only; no screenshot artifact. |
Phase / pass table:
| Phase | Status | Evidence | Next |
|---|---|---|---|
| Intake and source read | complete | Synced Blocks example/tests and runtime navigation/history paths inspected. | implementation complete |
| Implementation | complete | Runtime content-root owner registry, active-copy navigation repair, history focus repair, and expanded fixture/tests added. | verification complete |
| Verification | complete | Focused package/browser gates and bun check passed. | closeout complete |
| PR / tracker sync | complete | N/A: no PR, commit, push, or tracker requested. | final response |
| Closeout | complete | Plan evidence recorded; autogoal checker run before final. | final response |
Findings:
owner.childRoot === currentRoot, so repeated copies can exit at the wrong
document position.39; the current
text length is 43, so tests now use the actual body string length.Shift+ArrowDown across a root boundary creates a
native newline selection while the Slate model selection stays collapsed in
main and the synced root receives no selection. Owner: cross-root expanded
selection / DOM-selection export architecture.Decisions and tradeoffs:
Implementation notes:
.tmp/slate-v2/packages/slate-react/src/hooks/use-slate-runtime.tsx and
components/slate.tsx now expose runtime content-root owner registration,
active-owner lookup, and owner-path-to-view-editor lookup..tmp/slate-v2/packages/slate-react/src/components/editable-text-blocks.tsx
registers each mounted content-root view against the owning element path..tmp/slate-v2/packages/slate-react/src/editable/content-root-navigation.ts
uses active owner state on root exit and owner-specific view lookup on root
entry; it also covers Cmd/Meta+Arrow document boundary movement..tmp/slate-v2/packages/slate-react/src/editable/keyboard-input-strategy.ts
and runtime-keyboard-events.ts pass owner lookup into keyboard history
repair..tmp/slate-v2/packages/slate-react/src/hooks/use-slate-history.ts restores
focus to the latest non-selection commit operation root before falling back to
selection-root repair..tmp/slate-v2/site/examples/ts/synced-blocks.tsx now renders two copies of
one shared body root plus a separate synced document root..tmp/slate-v2/playwright/integration/examples/synced-blocks.test.ts covers
full ArrowDown and ArrowUp traversal, left/right repeated-copy traversal,
Cmd/Meta+Arrow document boundaries, cross-root undo/redo focus, shared-root
updates, separate-root isolation, duplicate, and unsync behavior.Review fixes:
Error attempts:
| Error / failed attempt | Count | Next different move | Resolution |
|---|---|---|---|
| Claude no-tools scoped autoreview hung silently | 1 | Kill and try Codex variant | Killed after roughly 2m47s. |
Codex no-tools autoreview rejected --no-tools | 1 | Try bounded scoped Codex run without that flag | Immediate CLI rejection. |
| Bounded Codex scoped autoreview timed out | 1 | Record review blocker and rely on direct tests/checks | Timed out after 180s with exit code 124 and no output. |
Verification evidence:
.tmp/slate-v2: bun lint:fix passed..tmp/slate-v2: bun lint passed..tmp/slate-v2: bun --filter slate-react typecheck passed..tmp/slate-v2/packages/slate-react: bun test:vitest -- test/use-slate-history.test.tsx test/content-root-navigation-contract.test.ts passed: 2 files, 15 tests..tmp/slate-v2: PLAYWRIGHT_BASE_URL=http://localhost:3100 PLAYWRIGHT_RETRIES=0 bunx playwright test playwright/integration/examples/synced-blocks.test.ts --project=chromium passed: 10 tests..tmp/slate-v2: PLAYWRIGHT_BASE_URL=http://localhost:3100 PLAYWRIGHT_RETRIES=0 bunx playwright test playwright/integration/examples/synced-blocks.test.ts passed: 25 passed, 15 skipped. Skips are intentional non-Chromium skips for geometry/focus rows..tmp/slate-v2: PLAYWRIGHT_BASE_URL=http://localhost:3100 PLAYWRIGHT_RETRIES=0 bunx playwright test playwright/integration/examples/editable-voids.test.ts --project=chromium --grep "content root|vertically|clicking outside" passed: 3 tests..tmp/slate-v2: bun check passed: lint, package/site/root typecheck, package tests, slate-layout, and slate-react Vitest./Users/zbeyens/git/plate-2: node .agents/rules/autogoal/scripts/check-complete.mjs docs/plans/2026-05-26-slate-v2-synced-blocks-selection-history-coverage.md passed.rg -n "console\\.log|test\\.only|\\.only\\(|debugger" ... found only the pre-existing android input manager debug comment.p1 at [0,0] offset 2, Shift+ArrowDown produced native selected text "\n", kept outer Slate selection collapsed at [0,0] offset 2, and left the first synced root selection null.Final handoff contract:
bun check passed.http://localhost:3100/examples/synced-blocks.Final handoff / sync:
Timeline:
Reboot status:
| Question | Answer |
|---|---|
| Where am I? | Closeout complete; waiting for final response. |
| Where am I going? | Run the mechanical autogoal checker, mark the active goal complete, then hand off. |
| What is the goal? | Synced Blocks selection/history/browser coverage with bugs listed and safe owner bugs fixed. |
| What have I learned? | Repeated content-root projection needs active owner identity; Shift+Arrow across roots needs a larger expanded-selection design. |
| What have I done? | Added fixture coverage, package tests, Playwright coverage, runtime/navigation/history fixes, and verification evidence. |
Open risks: