pcbjam/docs/features/ysync-review/08-miss-layout-state-never-syncs.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

4 KiB

Design miss 08 — Non-item document state only syncs at seed; lib_symbols is a landmine for the symbol-libraries milestone

Severity: design gap (silent divergence for settings edits; structural blocker later) Status: IMPLEMENTED 2026-07-03 — see 18 (lib_symbols channel + coarse layout save-sync; nets stay seed-frozen by design)

Where

  • web/pcbjam-shared/src/kicad-y.ts:79-94kdoc_layout is written by docToY (seed) and only ever appended to / pruned by applyDeltaToY for root items; non-item layout slots are never updated live
  • web/pcbjam-shared/src/items-wire.ts:85-117unwrapWireItem deliberately strips the blob's envelope, including a symbol blob's (lib_symbols …) cache ("sender context, not document content")
  • wasm/bindings/eeschema_embind.cpp:786-808doApplyItems' findLib fallback chain: blob's own lib cache (stripped upstream) → live screen's cache → nullptr
  • Drift flags: web/standalone/src/wasm/collab/drift-detect.ts:110-115 (layoutChanged / metaChanged are computed and reported — but nothing consumes them beyond telemetry)

What doesn't sync (by design, today)

Everything that lives in layout (non-uuid forms at the document root):

  • eeschema: title block, paper size/orientation, (settings …), lib_symbols
  • pcbnew: (setup …) (design rules), net declarations ((net N "NAME") at root), layer table, title block / paper

A peer editing the title block or board setup diverges silently from the room and from other peers; drift-detect reports layoutChanged forever and nothing repairs it (10-miss-no-repair-path.md). Because ydoc-mode opens materialize from the doc, the author's own settings edit is lost on the next reload (the saved file went to the API, but the doc wins on open — see the save-vs-room note in 10).

The lib_symbols landmine

Today symbol placement is blocked (no bundled symbol libraries), which masks this. When that lands:

  1. Sender places a symbol → the emit's clipboard blob carries the symbol AND its (lib_symbols …) definition (that's what aForClipboard Format does).
  2. unwrapWireItem strips the lib_symbols envelope → the definition never enters the Y.Doc.
  3. Peers apply the symbol; findLib falls back to the live screen's cache — which doesn't have the definition for a symbol the peer has never seen → nullptr → symbol added without a LIB_SYMBOL (renders broken).
  4. Worse, persistently: the room's layout.lib_symbols still has only the seed-time definitions, so docToFile produces a schematic referencing a lib id it doesn't contain — an invalid file.

Fix directions

  • Short term (before symbol placement ships): stop stripping lib_symbols on the eeschema wire. Either merge the blob's definitions into a dedicated kdoc_libsymbols Y.Map (keyed by lib id, LWW per definition — definitions are content-addressed-ish and rarely conflict), or fold them into the layout's lib_symbols slot on upsert. Mirror on apply: render the definitions into the wire so findLib's first branch works.
  • Layout state generally: decide per class:
    • Settings/title block: add a coarse "layout rev" sync — on local save (the existing onSave hook) diff the saved file's layout against the doc's (docDelta covers items; layout needs a slot-list compare, which drift-detect already does) and write changed non-item slots into kdoc_layout with LWW-at-slot-head granularity. Coarse but converging.
    • Net declarations (pcbnew): must be kept in step if/when net-creating edits are possible in the standalone; otherwise document explicitly that nets are seed-frozen.
  • Minimum bar if deliberately deferred: document the freeze and make drift-detect's layoutChanged distinguish "expected class" (title block) from "unexpected" (missing lib_symbols), so telemetry stays actionable.