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
2.9 KiB
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
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 withbinding.seed(undefined, { editorMatchesDoc: false })web/standalone/src/wasm/collab/kicad-binding.ts:176-188— that adopt branch renders ALL doc roots (renderItemper root) and sends them as oneapplyItemsbatch; C++doApplyItemsthen 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
Pushwith full connectivity/ERC recompute; - produces one undo entry containing the whole sheet (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:
- Accumulate the parked delta. Instead of a boolean
dirty, buffer the uuid set of changed items while parked (theupdateevent's transaction carries changed keys viaY.decodeUpdate, or cheaper: attach the standardobserveDeep→deltaFromYEventspipeline to the parked doc and accumulate into a pendingKicadDelta, coalescing per uuid). On rebind, convert just that delta withdeltaToItemsWireand apply it — identical code path to a live remote batch. - Diff on rebind (no bookkeeping). On rebind, parse
bridge.snapshotItems()(already called for baselining), convert withitemsWireToDeltaagainst 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.