2026-07-03 12:43:55 +02:00
|
|
|
# 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)
|
2026-07-06 08:35:18 +02:00
|
|
|
**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)
|
2026-07-03 12:43:55 +02:00
|
|
|
|
|
|
|
|
## Where
|
|
|
|
|
|
|
|
|
|
- `web/pcbjam-shared/src/kicad-y.ts:79-94` — `kdoc_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-117` — `unwrapWireItem` 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-808` — `doApplyItems`' `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](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](10-miss-no-repair-path.md)).
|
|
|
|
|
|
|
|
|
|
## 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.
|