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
5.6 KiB
Miss 08 + opts 12/13 implemented; opt 14 deliberately deferred (2026-07-03)
Status: miss 08 (both halves), opt
12's TS items, and opt
13 implemented and verified. All
TS/shared-side — the C++ already did its part (eeschema's itemBlob emits the
lib_symbols context; doApplyItems' findLib was designed to prefer a
blob-carried definition), so no WASM rebuild was needed.
08A — lib_symbols channel
- New
kdoc_libsymbolsY.Map (lib id →(symbol …)definition text): concurrent placements of DIFFERENT symbols merge per definition instead of LWW-clobbering one layout slot. docToYextracts the layout's(lib_symbols …)definitions into the map and keeps the layout slot EMPTY (the injection point);yToDocre-injects the map's definitions sorted by lib id — the order KiCad's own writer emits, so materialization matches editor saves.- Emit direction:
wireLibSymbols(wire)recovers definitions from the multi-form clipboard blob (unwrapWireItemstill strips them from the ITEM payload); the binding stores them in the same transaction as the item delta. - Apply direction:
deltaToItemsWire(delta, view, libDefs)prefixes a root item carrying(lib_id …)with its definition — exactly the multi-form shape eeschema's paste path parses, sofindLib's first branch resolves it and a peer that has never seen the symbol renders it correctly. - e2e:
tests/kicad/ysync-libsymbols.spec.ts— a joiner whose cold copy lacks the symbol adopts it WITH its definition (chromium two-tab; F2 applies).
08B — coarse layout save-sync
- New shared
syncLayoutToY(fileDoc, ydoc, origin): reconciles non-item layout slots per HEAD KEYWORD group (title block, paper, setup, settings…) from a just-saved file — a changed group is replaced wholesale (LWW at head granularity; different heads merge).{item}slots are never touched. - Deliberate freezes:
net(pcbnew's root net table — net-creating edits are not possible in the standalone; repeated positional heads can't be reconciled by name) stays seed-frozen;lib_symbolsroutes to the defs map ADDITIVELY (a save can't know about a peer's not-yet-applied placement). - Wiring:
registerSaveHookgainedonSavedText(decoded saved text); WasmTool routes it — eeschema per sheet via the manager's newsyncLayoutFromSave(parked rooms sync too; the dirty mark it causes costs only the real delta now, see opt 13), pcbnew/pl_editor via the single-room doc. - Known limitation (unchanged from the doc's "coarse but converging"): a peer's EDITOR does not live-update non-item state — the room doc converges, so materialization/reopen and drift-detect see it; live propagation into an open editor's title block would need a C++ apply for non-item state.
Opt 12 — TS hot-path (items 2 + 4)
yToItemUnchecked(no zod) feeds the binding'sitemsView()— both hot directions (every local emit, every remote batch). zod stays at the trust boundaries: wire parse, seed, materialize.itemsWireToDeltabuilds the parent→children index ONCE per conversion (was: full-scandescendants()per wire item and per removed id).- NOT taken from doc 12: retiring the C++ scalar scan + legacy emit (the scan
still feeds the legacy wire and covers eeschema's unreported post-Push
connectivity cleanup — retire it together with the legacy-wire removal,
miss 11 follow-up), and the lazy
deltaToItemsWireview (item 3) — killing zod removed the dominant cost; revisit if profiling says otherwise.
Opt 13 — diff-on-rebind adopt (option 2)
seed()'s adopt no longer renders and re-applies EVERY doc root. It diffs the
editor snapshot against the doc view (itemsWireToDelta + wireItemUuids) and
applies only the doc-authoritative difference:
- doc-only ROOTS → added (their sexprs embed descendants; a doc-only child makes its shared parent differ and rides the parent's re-apply);
- differing items → the DOC's version re-applied, lifted to their root (the C++ upsert replaces roots; a bare child apply would mis-parent);
- editor-only ROOTS → removed (editor-only children vanish with their parent's re-apply).
An empty diff degrades to baseline-only — the parked-dirty rebind, the clean revisit, and the cold divergent adopt now share one code path, and the adopt's single commit (and undo entry — the miss-09 "adopt undo bomb") shrinks to the real changed set.
Opt 14 — deferred, on purpose
The slot-level CRDT refinement is a meaningful rewrite of kicad-y's write path
plus the whole conversion layer, with real interleaving-anomaly risk. Doc 14's
own revisit triggers (measured bandwidth/storage cost; concurrent same-item UX
complaints) are unmet, and the flatten already gives per-child granularity.
Nothing in this batch forecloses it — body stayed one JSON value.
Verification
- pcbjam-shared: 107 (9 new in
test/layout-libsymbols-sync.test.ts) - standalone: 79 + 2 known pre-existing wasm-assets fixture failures (collab suite 42, incl. 3 new diff-adopt + 2 lib_symbols binding tests; save-flow +2)
- e2e (chromium): full ysync set +
ysync-libsymbols.spec.tsgreen - No C++ changes; no WASM rebuild.
Remaining from the review
Misses 09 (collab-aware undo — the adopt shrink here removes its worst case) and 10 (drift repair), opt 12's C++ retirement half (with the legacy-wire removal), opt 14 (triggers above), and doc 17's carried-over follow-ups.