pcbjam/docs/features/async/18-embind-audit.md
Gergő Törcsvári 61b5f266fb
mailbox S1: shim delivery tick, embind audit, app-side WasmMailbox
Shim: mailbox FIFO + self-armed delivery tick calling wxWasmMailboxTick
(plain export — never inside a pump's awaited ccall); injector sentinel
fixed (the old marker also matched evtloop's EM_JS probe text). Doc 18:
79-export embind audit (14+3 production mutators to wrap, 20 pure-read
allowlist, asymmetries). web/standalone WasmMailbox: FIFO defer-until-
settled keyed on the proxy-safe kicadOpenFileBusy probe, 7 vitest green.
Dual-variant wx battery green (28+39+7 both variants). Bump wxwidgets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TfxKn5utcntBSnxz4ZnYKs
2026-08-10 10:14:12 +02:00

81 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 18 — Embind export audit (doc 17 S1 deliverable)
> **Status: AUDIT (2026-08-05).** The sync-embind classification doc 17 §4 S1 calls for:
> every JS-callable export in `wasm/bindings/`, classified for the mailbox migration.
> Method: all `EMSCRIPTEN_BINDINGS` blocks enumerated; each body followed one level deep.
> Classes: **PURE-READ** (stays synchronous), **MUTATOR** (becomes a queued message),
> **PARKER** (can asyncify-park itself), **TEST-LEVER** (`kicadTest*`, e2e only).
## Headline numbers
**79 distinct JS names** (171 `function()` registrations across 6 bindings blocks —
names duplicate per-bundle behind `#ifndef KICAD_MERGED_EMBIND`; pcb_calculator's block
is empty). No `EMSCRIPTEN_KEEPALIVE` JS entries exist in the tree.
| class | count | migration consequence |
|---|---|---|
| MUTATOR | 47 (33 test-only, 14 production) | queued mailbox message (S1 wrapper / S4) |
| PURE-READ | 20 | stays sync — the allowlist |
| TEST-LEVER | 9 (6 of them park-capable by design) | keep direct — they *stage* collisions |
| PARKER | 3 production (`kicadOpenFile`, `kicadOpenFiles`, `kicadLibsReload`) | fiber contexts at S4 |
**The 14+3 production mutators/IO:** `kicadSetChrome`, `kicadSetReadOnly`,
`kicadCollabApply`, `kicadCollabApplyItems`, `kicadCollabSnapshot`,
`kicadCollabSnapshotItems`, `kicadCollabPresenceStart`, `kicadCollabSetRemote`,
`kicadCollabSetPins`, `kicadCollabSetStyle`, `kicadCollabSetViewport`,
`kicadCollabFitViewport`, `kicadCollabReleaseSelection`, `kicadSetColorTheme`
(park-suspect: settings Save + full chrome rebuild), plus light `kicadSetDarkChrome`
and the three bare-stack I/O entries `kicadSaveBoard` / `kicadSaveSchematic` /
`kicadSaveDrawingSheet`.
**The PURE-READ allowlist (stays sync):** `kicadOpenFileBusy`, `kicadCollabFiberBusy`,
`kicadCollabGetPos`, `kicadCollabGetViewport`, `kicadCollabGetSelection`,
`kicadCollabGetSelectionFull`, `kicadCollabTestGetCrossMapped`, `kicadCollabTestGetLocked`,
`kicadCollabTestListItems`, `kicadCollabTestDemoSet`, `kicadCollabTestItemBlob`,
`kicadCollabTestUndoDepth`, `kicadTestTimerParkState`, `kicadTestFiberParkState`,
`kicadLibsSymbolUsage`, `Board_GetFootprints`, `Board_GetFileName`, `Footprint_GetPads`,
`Footprint_GetReference`, `Footprint_GetValue`, `Pad_GetNumber`, `Pad_GetPinFunction`.
Caveat below: "sync" is safe for the asyncify machinery, but reads that walk the model
still need the open to have settled (N6 territory).
## Guard coverage today
| guard | coverage |
|---|---|
| `pcbjam_open::BusyGuard` (sets the gate) | the 6 open entries |
| `pcbjam_open::busy()` early-return | ONLY 8 names: Collab{Apply,ApplyItems,Snapshot,SnapshotItems} × pcbnew/eeschema/pl_editor |
| `runOnFiber` FIFO (collab_common.h) | ~35 mutators |
| bare `CallAfter`, no fiber | selection/presence sub-paths, eeschema's 2 move test hooks |
| entirely unguarded, bare embind stack | `kicadSetChrome`, `kicadSetReadOnly`, the 3 `kicadSave*`, pl_editor applies (busy-gated but not fibered, inline `HardRedraw`), `kicadCollabTestAddText`, `kicadLibsReload` (fibered, no busy check), and every model-walking PURE-READ |
## Asymmetries the migration must fix (or knowingly accept)
1. **Model-walking pure-reads have no `busy()` gate** (`kicadCollabGetPos`,
`kicadCollabGetSelection*`, `kicadCollabTestListItems`, `Board_*`/`Footprint_*`/`Pad_*`,
`kicadLibsSymbolUsage`, `kicadCollabTestItemBlob`) — they can walk a half-built model
during a parked `OpenProjectFiles`. Same exposure class the gate was built for; the
mailbox does NOT fix reads (they stay sync) — needs either a busy() early-return with a
benign empty result, or documented "caller must await settle" (open-flow already does).
2. **pl_editor's `kicadCollabApply`/`ApplyItems` are busy-gated but NOT fibered** — they
mutate `DS_DATA_MODEL` + `HardRedraw()` on the bare embind stack (pl_editor_embind.cpp:313,
:515), unlike the pcbnew/eeschema twins. `kicadCollabTestAddText` (PL:597) likewise.
3. **`kicadLibsReload` is the only production PARKER with no `busy()` gate**
(pcbjam_libs_reload.h — `LoadLibraryEntry` asyncify-suspends per its own header).
4. **eeschema's `schCollabTestMoveFirst`/`MoveSchItem` use bare `CallAfter`** where the
pcbnew twins use `runOnFiber`.
5. **Split-context construction**: `kicadCollabTestDuplicate*`/`AddSymbol` clone/construct
items off-fiber then commit on-fiber.
6. `kicadSave*` park-safety rests on MEMFS writes staying synchronous — UNCERTAIN, verify
before S4 puts saves on fibers.
7. Registration gaps: `kicadSetChrome` merged-image only; the timer/fiber park test levers
exist in kicad_editor + pcbnew only.
## Consequences for the S1 wrapper (doc 17 S1.5)
Wrap-and-enqueue applies to the **14 production mutators + 3 saves**; test-only mutators
keep direct entry (the harness *wants* to stage collisions). The busy()-gated four
(apply/snapshot pairs) are the first wrap targets — their drop→deliver flip is N2's
subject. `kicadSetDarkChrome` is documented main-thread-safe and can stay direct.
Full per-export table (file:line, evidence, guard) lives in the audit transcript; the
classifications above are the binding contract for S1/S4 work.