Miss 08A: the binding stores wire-carried (lib_symbols …) definitions in kdoc_libsymbols and prefixes them on apply wires — a joiner that never saw a symbol adopts it WITH its definition (new e2e ysync-libsymbols.spec.ts). Miss 08B: registerSaveHook gains onSavedText; WasmTool routes saved-file text to syncLayoutToY (per sheet room via the manager's syncLayoutFromSave, or the single-room doc) so title block / paper / setup edits converge instead of drifting. Opt 12 (TS half): zod off the observer hot path (yToItemUnchecked), children index built once per conversion. Opt 13: seed()'s adopt diffs the editor snapshot against the doc view and applies only the doc-authoritative difference — clean rebinds apply nothing, the adopt undo entry shrinks to the real changed set. Opt 14 deliberately deferred (doc 18). All TS-side; no wasm rebuild (the C++ blob/findLib sides already carried definitions). Verified: shared 107, standalone 79 (+2 known pre-existing wasm-assets), ysync e2e 21/21 chromium, collab regression 21/3-skip firefox. Bumps: web/pcbjam-shared (lib_symbols channel + syncLayoutToY + opts). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgThWXtdvrYLK47EDFoGdq
56 lines
2.9 KiB
Markdown
56 lines
2.9 KiB
Markdown
# Optimization 13 — Parked-dirty sheet rebind re-applies the entire sheet instead of the delta
|
|
|
|
**Severity:** performance + UX (heavy on big sheets; creates the adopt undo-bomb)
|
|
**Status:** FIXED 2026-07-03 — option 2 (diff on rebind) — see [18](18-miss08-opts-12-13.md)
|
|
|
|
## Where
|
|
|
|
- `web/standalone/src/wasm/collab/sheet-manager.ts:188-191` — a sheet revisited after
|
|
any remote traffic while parked (`room.dirty`) is re-seeded with
|
|
`binding.seed(undefined, { editorMatchesDoc: false })`
|
|
- `web/standalone/src/wasm/collab/kicad-binding.ts:176-188` — that adopt branch
|
|
renders **ALL** doc roots (`renderItem` per root) and sends them as one
|
|
`applyItems` batch; C++ `doApplyItems` then does remove+add for **every** item on
|
|
the sheet, in one commit
|
|
|
|
## What it costs
|
|
|
|
A single remote edit to a parked sheet marks it dirty; the next `switchTo` then:
|
|
|
|
- renders every root item's full subtree s-expr from the Y view (O(sheet));
|
|
- ships one giant wire batch across embind;
|
|
- C++ parses every blob through the clipboard-paste path, removes and re-adds every
|
|
item, runs one `Push` with full connectivity/ERC recompute;
|
|
- produces **one undo entry containing the whole sheet**
|
|
([09-miss-undo-not-collab-aware.md](09-miss-undo-not-collab-aware.md)) and resets
|
|
selection/view state for everything.
|
|
|
|
The warm-pool design already pays the memory/connection cost to keep parked docs
|
|
current precisely so switches are cheap — then throws that away by re-applying
|
|
everything instead of the accumulated difference.
|
|
|
|
## Fix
|
|
|
|
The parked room already knows what changed — `startWatch` marks `dirty` on every
|
|
update. Two escalating options:
|
|
|
|
1. **Accumulate the parked delta.** Instead of a boolean `dirty`, buffer the
|
|
uuid set of changed items while parked (the `update` event's transaction carries
|
|
changed keys via `Y.decodeUpdate`, or cheaper: attach the standard
|
|
`observeDeep` → `deltaFromYEvents` pipeline to the parked doc and accumulate into
|
|
a pending `KicadDelta`, coalescing per uuid). On rebind, convert just that delta
|
|
with `deltaToItemsWire` and apply it — identical code path to a live remote batch.
|
|
2. **Diff on rebind (no bookkeeping).** On rebind, parse `bridge.snapshotItems()`
|
|
(already called for baselining), convert with `itemsWireToDelta` against the doc
|
|
view, and apply only the resulting difference in the *editor* direction (doc
|
|
authority: added/updated from doc side, removed for editor-only items). This is a
|
|
generalization of the existing adopt that degrades gracefully — the empty diff
|
|
case becomes the current "clean revisit" baseline-only branch, and the code paths
|
|
unify.
|
|
|
|
Option 2 is more robust (it also self-corrects any drift the parked bookkeeping might
|
|
miss) and reuses existing conversion machinery; its cost is one editor snapshot per
|
|
rebind, which the seed already pays today.
|
|
|
|
Either way, the giant single-commit adopt shrinks to the real changed set, which also
|
|
shrinks the undo entry and the selection churn.
|