5.2 KiB
Direct state editing — bounded design, 2026-09-05
Read-only investigation; implementation and native verification remain pending. Connection routing became the user's next priority after this design handoff.
Decision and first task
Reuse Diagram/NodePlacement and existing atomic commands. Prefer a typed
ProjectionKind::StateMachine { machine: Id } over desktop-only coordinates or
a second persisted behavior-layout store. Existing projection strings remain
valid. Proposed source: projection StateMachine { machine @operating_modes; };.
The context references a same-layer machine and scopes placements to its machine,
regions and vertices. Explicit creation initializes existing contents in one
transaction; rendering must not dirty a model. Missing placements remain legal
and discoverable through an elements-not-shown action.
Retain active behavior diagram identity independently of semantic selection; selecting a root Event must not switch machines. Diagram context/layout are model content; active tool, pointer and zoom remain editor state. Context participates in reference remapping/deletion, language reference controls and OpenAPI.
The first native task is: create a region and Initial/State; drag a child and a composite; draw a transition; reconnect its endpoint; edit its guard; undo/redo; save/reopen and inspect the equivalent source/API records. This is the minimum vertical slice, not acceptance of all behavior editing.
Existing seams and implementation contract
behavior.rs:56,118,494: selection-derived context, selection-only canvas.behavior/state_scene.rs:24,163: computed vertical geometry; retain its state symbols, internal-transition rows and typed routing, but consume persisted shared node geometry. Generic projection drops equal-anchored/self edges and includes relationships unsuitable for a state diagram.behavior/states.rs:73,191: reuse existing typed transition controls and candidate validation. Reconnection edits a clone of the original relation.model.rs:1235,1247,projection.rs:104,184,session.rs:562: reuse placement identity, semantic nesting/folding and grouped movement.
Events carry diagram identity explicitly: CreateAt(diagram, parent, kind, position), Move(diagram, node, position), Connect(diagram, source, target), Reconnect(diagram, relation, endpoint, vertex), EditTransition(diagram, relation). They lower to existing CreateElement+CreateNode Batch, MoveNode, CreateRelation/EditRelation commands. No alternate mutation API is required. Gesture state is Idle/Move/Connect/Reconnect with transient preview and a captured revision. Release commits once; Escape, stale revision or context change cancels. Allocate creation IDs once per accepted plan. Drawing/hit testing/preview consume one scene. Extend app.rs:864's draft guard to every mutation gesture.
Required invariants
Creation targets the explicitly highlighted semantic Region. Region creation targets a machine or stable State/Mode. Dragging never reparents. Moving a container moves all descendant placements once, including folded descendants, only in that diagram. Child movement preserves ownership and siblings. Resize constraints preserve child/header space and movement cannot misleadingly suggest ownership by another region. Entry/Exit remain region-owned boundary symbols.
Reconnect preserves relation UUID, alias, name, prose, triggers/effects and artifact references; validate the full replacement so the old relation is not double-counted for cardinality. Do not silently change transition kind or erase incompatible data. Internal remains a row/self contract; External self-loops and Local edges remain distinct. Cross-immediate-region transitions can be valid; cross-machine endpoints reject. Existing history, boundary and orthogonal rules in state_validation.rs remain authoritative.
Reject invalid drafts without losing them. New tools must not discard unfinished behavior drafts. Preserve semantic selection after movement and same-card reselection. Context references remap with UUID changes; machine deletion removes its dedicated views without deleting cross-layer counterparts. Source-created unplaced elements remain discoverable; cross-machine reparenting must also handle incompatible placements atomically or reject with an actionable diagnostic.
Partition and evidence gates
Core/context owns model.rs, projection.rs, references.rs, validation.rs and focused tests. After type freeze, representation owns language.rs, source-project reference handling, reST/OpenAPI and round-trip/API tests. Desktop gestures own new behavior/state_canvas.rs and state_scene.rs. Lead integrates behavior.rs, states.rs, app.rs and diagram context controls. Avoid a general graph framework.
Test pointer events at non-100% zoom, one history entry per gesture, exact identities, grouped movement limited to one view, atomic rejection, context lifecycle and source/JSON/REST equality. Native trial at 1440x900 and 1100x700 uses two regions, a nested composite and guarded transitions. Try invalid edges into Initial, invalid history reconnection, Escape mid-drag, a folded composite, root-Event selection and save/reopen. Record task completion, discoverability, ownership clarity and recoverability; no such native result is claimed here.