2026 04 03_layout_backend_state_ownership_plan - mark-ik/graphshell GitHub Wiki
Status: Active follow-on plan
Scope: Extracts the layout-backend and state-ownership lane from 2026-02-24_physics_engine_extensibility_plan.md into an execution plan focused on widening ActiveLayoutState, stabilizing persisted layout IDs, and defining when Graphshell must move beyond its current wrapper around the upstream layout trait seam.
Related:
2026-02-24_physics_engine_extensibility_plan.md2026-04-03_layout_variant_follow_on_plan.md2026-04-03_twod_twopointfive_isometric_plan.md2026-04-03_wasm_layout_runtime_plan.mdlayout_algorithm_portfolio_spec.mdmulti_view_pane_spec.mdview_dimension_spec.md2026-04-02_parry2d_scene_enrichment_plan.md
Graphshell already owns more of the layout story than the original umbrella note implied:
-
ActiveLayoutis the built-in dispatcher -
ActiveLayoutStateis the concrete render-facing persisted wrapper - the render layer deals with one view-owned state carrier rather than per-layout concrete types
- built-in layout modules already live under Graphshell control
The current carrier is still narrow, though. It is shaped around kind + physics, which is enough for force-directed and Barnes-Hut variants, but it is too specific for:
- analytic layouts with non-FR state
- runtime-loaded WASM layouts
- richer scene-backed layout/runtime state
- future backend-neutral spatial or projection metadata
This plan exists to isolate the ownership question from the variant and projection lanes. Those lanes need a wider carrier, but they should not each invent their own persistence shape.
- replacing
egui_graphswith a brand-new native layout trait in the first slice - implementing the first new analytic variants directly in this doc
- delivering the WASM runtime itself
- turning scene enrichment into a mandatory prerequisite for state widening
- quietly expanding this lane into full free-camera 3D ownership
Today the persisted wrapper is effectively force-directed-shaped. Future layout families need a carrier that remains single and render-facing while allowing different backends to store different state.
- Replace the implicit
physics-only assumption with a Graphshell-owned tagged carrier for per-backend state payloads. - Define stable serialized layout IDs independent of Rust enum variant names.
- Keep one concrete per-view wrapper for
render/mod.rsand snapshot persistence. - Preserve deterministic fallback behavior when the saved layout kind is unknown or unavailable.
- Keep projection-specific derived data out of canonical 2D layout truth unless a later lane explicitly widens that boundary.
- Existing force-directed and Barnes-Hut views roundtrip without state loss.
- A saved view with an unknown layout ID degrades through a documented fallback path.
- The widened carrier can hold at least one non-FR payload shape without changing render-facing APIs.
Not every backend-owned detail belongs in the snapshot. Some state is canonical and resumable; some state is runtime-only cache, derived scene data, or a transient stepping artifact.
- Draw an explicit line between persisted layout state, runtime caches, and scene/projection derivations.
- Keep per-view ownership aligned with
multi_view_pane_spec.mdso one graph view can change backend without contaminating others. - Define where guest-owned opaque bytes live for runtime-loaded layouts without making them the default for all native layouts.
- Keep scene-enrichment runtime data and projection overlays optional dependents of the layout carrier rather than stuffing them into every saved payload.
- Ensure
TwoDlayout truth remains recoverable even when a view temporarily renders with derived depth or scene effects.
- Snapshot payloads remain bounded and understandable after the carrier widens.
- Clearing runtime-only caches does not mutate saved layout truth.
- Per-view backend swaps do not leak runtime-only state across views.
The carrier should describe what kinds of layout backends Graphshell intends to support, even if not all of them are implemented immediately.
- Define the initial backend families Graphshell intends to support through the shared carrier: built-in force-directed, built-in analytic, runtime-loaded WASM, and future scene-backed variants.
- Keep layout selection, diagnostics, and persistence keyed by stable backend/layout IDs rather than ad hoc enum names.
- Clarify whether
ActiveLayoutstays a bounded enum, gains an internal registration table, or becomes a mixed model with a stable external ID layer. - Make the ownership boundary explicit: Graphshell owns the persisted wrapper and backend selection policy even while the underlying trait seam still routes through
egui_graphs. - Document the dependency edges: layout-variant, WASM runtime, and projection-mode work all consume this carrier.
- Diagnostics can report both the requested layout ID and the resolved backend family.
- Snapshot serialization survives internal enum refactors because the external ID remains stable.
- At least one future backend family can be sketched without forcing immediate trait replacement.
The main architectural question is not whether Graphshell owns some layout state already. It does. The real question is when the imported Layout<S> / LayoutState seam becomes the bottleneck.
- Define the triggers that justify replacing the imported trait boundary: unbounded backend families, backend-neutral stepping, broader spatial-query ownership, or non-
egui_graphsrender paths. - Record the cases that do not require full replacement yet: bounded built-in variants, projected 2.5D views, and post-physics helper composition.
- Ensure follow-on plans can proceed against the widened wrapper without prematurely forcing a wholesale trait migration.
- Keep the migration path explicit if full seam ownership becomes necessary later.
- Tie that escalation decision to real dependent work rather than abstract purity.
- The plan can admit new built-in variants without immediate trait replacement.
- The plan identifies concrete criteria for when the current wrapper is no longer sufficient.
- Follow-on plans can reference this document as the ownership authority instead of restating the tradeoff.
This plan is complete when Graphshell has a widened, snapshot-safe, per-view layout state carrier with stable external layout IDs, explicit separation between persisted and runtime-only state, and a documented decision gate for when full native ownership of the layout trait seam is actually required.