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
This commit is contained in:
parent
ae5d41a3d7
commit
62ca571802
14 changed files with 570 additions and 27 deletions
|
|
@ -93,3 +93,4 @@ sending half emits NOTHING, not the bare removal the doc predicted).
|
|||
| 15 | [15-plan-repro-tests-and-v2-e2e.md](15-plan-repro-tests-and-v2-e2e.md) | The approved plan: repro tests for bugs 01–07 + the v2 e2e port |
|
||||
| 16 | [16-repro-suite-results-and-empirical-findings.md](16-repro-suite-results-and-empirical-findings.md) | Plan 15 executed (2026-07-03): suite map, verified failure sites, empirical findings F1–F4 |
|
||||
| 17 | [17-fixes-bugs-01-07.md](17-fixes-bugs-01-07.md) | Bugs 01–07 fixed & verified (2026-07-03); findings F5–F6; remaining follow-ups |
|
||||
| 18 | [18-miss08-opts-12-13.md](18-miss08-opts-12-13.md) | Miss 08 (lib_symbols + layout save-sync) + opts 12/13 implemented; opt 14 deferred (2026-07-03) |
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# 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:** open decision
|
||||
**Status:** IMPLEMENTED 2026-07-03 — see [18](18-miss08-opts-12-13.md) (lib_symbols channel + coarse layout save-sync; nets stay seed-frozen by design)
|
||||
|
||||
## Where
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Optimization 12 — O(full-model) work on every edit, apply, and remote batch
|
||||
|
||||
**Severity:** performance (fine on demo boards; seconds-per-edit territory at 5–10k items)
|
||||
**Status:** open
|
||||
**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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Optimization 13 — Parked-dirty sheet rebind re-applies the entire sheet instead of the delta
|
||||
|
||||
**Severity:** performance + UX (heavy on big sheets; creates the adopt undo-bomb)
|
||||
**Status:** open
|
||||
**Status:** FIXED 2026-07-03 — option 2 (diff on rebind) — see [18](18-miss08-opts-12-13.md)
|
||||
|
||||
## Where
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Optimization 14 — Item-level body granularity: whole-item payloads per nudge, LWW drops concurrent property edits
|
||||
|
||||
**Severity:** known/documented v1 tradeoff — recorded here so its costs are visible when prioritizing
|
||||
**Status:** open (deliberate design decision; revisit trigger below)
|
||||
**Status:** open (deliberate design decision; revisit trigger below — reaffirmed 2026-07-03, see [18](18-miss08-opts-12-13.md))
|
||||
|
||||
## Where
|
||||
|
||||
|
|
|
|||
102
docs/features/ysync-review/18-miss08-opts-12-13.md
Normal file
102
docs/features/ysync-review/18-miss08-opts-12-13.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
# 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.
|
||||
Loading…
Reference in a new issue