Add kicadCollabSnapshotItems / kicadCollabApplyItems / window.kicadCollab.onItems
to pl_editor, eeschema, pcbnew — per-item native-blob payloads
({added/changed:[{sexpr,parent}], removed:[uuid]}) alongside the untouched scalar
wire (legacy collab specs stay green).
- pl_editor: itemBlob per item; apply = SetPageLayout(append) + replace-by-uuid
(pointer-snapshot safe); bare payloads get the kicad_wks envelope. Snapshot +
apply + emit verified headless.
- eeschema: clipboard Format per item (symbols carry their lib_symbols); apply
mirrors the native paste — LoadContent into a throwaway sheet → detach →
replace-by-uuid → symbol lib relink (blob's lib_symbols first, live screen's
second) → SCH_COMMIT, in the CallAfter+COROUTINE context. Snapshot + apply
verified headless (a "lost" lone junction turned out to be correct connection
cleanup — test uses text).
- pcbnew: blobForItem per ROOT item with child→footprint lifting in flushDiff;
apply = makeFromBlob + commit replace-by-uuid on the fiber; bare non-footprint
payloads get wrapInBoardEnvelope (live board layer table). Snapshot + footprint
replace/add WITH children (the 0004 containment gap, closed) + removal verified
headless. Track/via/zone/text blob-apply hits the documented asyncify-fragile
envelope parse (reconfirmed empirically — a verbatim SaveSelection segment
envelope dies silently in the commit) and stays on the legacy scalar apply;
tracked in ysync 0008 status.
- eeschema/pcbnew scheduleFlush now runs flushDiff inside a COROUTINE: the
per-item Format in the v2 emit needs the fiber stack (0007 lesson). Their emit
remains unverifiable headless (both legacy two-tab tests are test.skip:
"open=false → SCH_COMMIT no-ops" / "harness can't PAINT") — verify in the real
app at Stage D; pl_editor's emit IS verified.
- tests/kicad/items-bridge.spec.ts: per-tool suite (snapshot uuids → local-edit
emit (where drivable) → apply changed/added/removed via save-readback → no
apply echo). 3/3 pass; roundtrip + collab suites unaffected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>