# Miss 08 + opts 12/13 implemented; opt 14 deliberately deferred (2026-07-03) **Status:** miss [08](08-miss-layout-state-never-syncs.md) (both halves), opt [12](12-opt-hot-path-full-model-work.md)'s TS items, and opt [13](13-opt-parked-dirty-full-sheet-replace.md) 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_libsymbols` Y.Map (lib id → `(symbol …)` definition text): concurrent placements of DIFFERENT symbols merge per definition instead of LWW-clobbering one layout slot. - `docToY` extracts the layout's `(lib_symbols …)` definitions into the map and keeps the layout slot EMPTY (the injection point); `yToDoc` re-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 (`unwrapWireItem` still 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, so `findLib`'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_symbols` routes to the defs map ADDITIVELY (a save can't know about a peer's not-yet-applied placement). - Wiring: `registerSaveHook` gained `onSavedText` (decoded saved text); WasmTool routes it — eeschema per sheet via the manager's new `syncLayoutFromSave` (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's `itemsView()` — both hot directions (every local emit, every remote batch). zod stays at the trust boundaries: wire parse, seed, materialize. - `itemsWireToDelta` builds the parent→children index ONCE per conversion (was: full-scan `descendants()` 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 `deltaToItemsWire` view (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.ts` green - No C++ changes; no WASM rebuild. ## Remaining from the review Misses [09](09-miss-undo-not-collab-aware.md) (collab-aware undo — the adopt shrink here removes its worst case) and [10](10-miss-no-repair-path.md) (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.