pcbjam/docs/features/ysync-review/12-opt-hot-path-full-model-work.md
Gergő Törcsvári 62ca571802
feat(ysync): lib_symbols travel + layout save-sync (miss 08), TS hot-path opts (12), diff-on-rebind adopt (13) — doc 18
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
2026-07-06 08:57:58 +02:00

60 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Optimization 12 — O(full-model) work on every edit, apply, and remote batch
**Severity:** performance (fine on demo boards; seconds-per-edit territory at 510k items)
**Status:** TS items DONE 2026-07-03 (zod off the observer path, children index once — see [18](18-miss08-opts-12-13.md)); C++ item 1 delivered by [17](17-fixes-bugs-01-07.md) batch 3 except the scalar-scan/legacy-wire retirement (goes with the legacy-wire removal)
## The costs, per hot path
**Every local commit (C++):**
- `flushDiff` runs `snapshotByUuid``itemToJson` for **every** item on the
board/screen (json allocation per item) — plus a full map compare against
`g_baseline` (`pcbnew_embind.cpp:546-668`, eeschema `:374-453`).
- The legacy scalar wire is still built and emitted alongside the v2 wire even though
production registers no `onDelta` listener (the json arrays are constructed
regardless; the `EM_ASM` no-ops).
**Every remote apply (C++):**
- `rebaseline()` at the end of `doApply`/`doApplyItems` — another full-model
`snapshotByUuid`.
**Every remote batch (TS):**
- The `observeDeep` handler builds `itemsView()``yToItem` for **every** item, each
going through a zod `.parse` of its entire body tree
(`kicad-binding.ts:82-88,116`). zod validation dominates; on a large board this is
by far the most expensive step, and it runs even for a single-item remote nudge.
- `deltaToItemsWire`'s `coveredByAncestor`/`renderItem` only need the delta's items
plus their ancestor chains and descendant subtrees — not the full view.
- `itemsWireToDelta``descendants()` rebuilds the full children index per wire item
(`items-wire.ts:63-83`) → O(n·m) for an m-item wire.
**Drift check:** full scratch save + `fileToDoc` + `yToDoc` + `docDelta` — but only
every 50 doc updates and at unload; acceptable as designed. (The `beforeunload` check
is synchronous full-model work and will add visible tab-close latency on big boards —
worth a size guard, not a redesign.)
## Fixes, in leverage order
1. **Dirty-set + blob-hash diffing on the C++ side** — the same change bug
[04](04-bug-lossy-change-detection.md) needs for correctness. Collect touched-item
uuids from the listener callbacks (currently discarded), lift children to roots,
and post-settle compare only those roots' blob hashes against a uuid→hash baseline.
Replaces both full snapshots (flush AND rebaseline — see
[05](05-bug-rebaseline-swallows-local-edits.md) for the targeted-rebaseline tie-in)
and retires the scalar snapshot + legacy emit entirely. Per-edit cost drops from
O(board) to O(edit).
2. **Kill zod on the TS hot path.** `yToItem`'s schema parse guards against malformed
Y content, but the observer path re-validates the *entire* model on every batch.
Either:
- cache the materialized `KicadItem` per item Y.Map (WeakMap keyed by the Y.Map,
invalidated from the event's changed keys), so a batch only converts touched
items + the subtrees `renderItem` walks; or
- validate at trust boundaries only (wire parse already zod-validates; Y reads can
use a cheap structural cast) and keep zod for seed/materialize paths.
3. **Scope the view to the delta.** `deltaToItemsWire` needs `view` for ancestor
chains and descendant rendering; build it lazily (resolve `items.get(uuid)` on
demand) instead of materializing the whole map up front.
4. **Index children once per conversion.** Build the parent→children map once per
`itemsWireToDelta` call, not per wire item.
Items 24 are contained TS changes; item 1 is the structural one and pairs with the
bug-04/05 fixes — do them as one piece of work.