Skip to content

Design-import framework comparison (2026-10-04)

Compared against the refactor plan in planning/2026-10-04-design-import-refactor-GOAL.md.

Reference Evidence at studied commit Transfer decision
Octane 322162cb79e72a322783d8765c97ec8ab0947bbe packages/octane/src/compiler/compile-universal.js lowers child blocks and preserves keyed identity; its benchmark corpus measures compiled templates and keyed updates. Adopted the identity and block-planning idea, using Pulp's existing stable_anchor_id rather than introducing a second key field or compiler.
Inferno 5c343f5f3 packages/inferno-create-element/src/patching.ts and patchKeyedChildren.spec.ts keep keyed and non-keyed paths explicit; tests cover reorder, insert, remove, and mixed lists. Adopted a fail-closed split: unique anchors use keyed matching; missing or duplicate anchors report ambiguous_keys and replace the sibling set wholesale rather than reusing anything by position.
React Native Skia e72c9647a packages/skia/src/sksg/Reconciler.ts turns commits into Skia pictures; RNSkPictureRenderer::applyUpdatesTo applies recorder values without rebuilding the picture. Deferred retained picture ownership. Pulp's native materializer does not yet expose a safe recorder/picture lifetime seam, so adding one here would exceed a safe importer slice.

Adopted slice

core/view/include/pulp/view/design_update.hpp and core/view/src/design_update.cpp add a pure plan_design_child_updates() function. It emits retained, moved, inserted, and removed operations plus contiguous DesignUpdateBlock runs. The planner is read-only and does not alter code generation or native materialization; it is therefore safe to use as the next bridge between re-import and retained views.

The tests cover keyed reorder plus insert/remove and the duplicate-key negative control. Ambiguous siblings are replaced wholesale, so a future materializer cannot accidentally retain a view by position. It can consume the blocks, while the current import path remains byte-compatible.

Measurements

Host: Daniels-Mac-Studio-m3.local, Darwin 27.0.0, arm64; Apple Clang 21.0.0; macOS SDK 27.0. Build type: Release. The governed target build completed successfully (initial clean target: 1,118 Ninja steps; final incremental rebuild after formatting: 40 steps). The resulting test executable is 46,353,528 bytes with SHA-256 6fcc4ac828e106475214059012b81091824bb6077aee53844eab751659eab11b.

The two focused cases passed: 2/2, 0.25 seconds wall time. The required negative control also passed: confirm_failure.sh broke the keyed comparison, observed the reorder test fail, restored the source, and observed the test pass again. The comparison itself found no evidence that a compiled-template compiler or Skia retained recorder should be copied into Pulp before a measured runtime seam exists.

2026-10-13 importer refinements

The follow-up slice applies the reference ideas at Pulp's existing Skia/Dawn boundary. It does not vendor, link, or execute Octane or Inferno.

Refinement Pulp behavior Evidence
Octane-style keyed identity and block planning stable_anchor_id drives deterministic retained/moved/inserted/removed work; duplicate or missing anchors fail closed to positional replacement. DesignUpdateWorkCounters, [update] tests, and the duplicate-anchor negative control.
Inferno-style explicit child and value lanes Static visuals and scalar, vector, meter, text, and action slots are classified explicitly; geometry text fields and XY pads retain their typed setter lanes. [slots] tests, including the delimiter-collision negative control.
Bounded observability instead of a second runtime The existing benchmark emits bridge, layout, paint, invalidation, mutation, RSS, and paint-command counters under pulp-design-import-benchmark-counters-v1. One-second live/baked lane receipts recorded in the execution plan.
Agent-safe import validation A fresh authored HTML fixture records Chromium and native Skia hashes, two interactions, and a rejected selector mutation. The committed receipt is a mandatory validator baseline. 17-fresh-plugin-panel.receipt.json and the validator's expected-receipt check.

The measured interactive comparison is deliberately bounded: the live lane recorded 420 bridge calls, 120 layouts, 420 invalidations, and 14,820 paint commands; the baked C++ lane recorded zero bridge calls, 120 layouts, 360 invalidations, and 13,920 paint commands. These numbers describe the existing benchmark fixture, not a general plugin-host or DAW guarantee. Stable identity, resource-lifetime stress, canonical recording/replay byte counters, and host validation remain explicit follow-up work in the execution plan.

The exact receipt and validator baseline are committed under test/fixtures/import-differential/; review limitations remain documented in the validation output and are not promoted to a general plugin-host or DAW guarantee.