2026-09-05 20:00:21 +03:00
|
|
|
|
# Direct state editing — bounded design, 2026-09-05
|
|
|
|
|
|
|
2026-09-06 03:31:26 +03:00
|
|
|
|
Originally a read-only proposal. Implemented in the isolated state-integration
|
|
|
|
|
|
checkout through e0b2210; current verification and outstanding acceptance are in
|
|
|
|
|
|
STATE.md. The old file/line seams below describe the pre-implementation baseline.
|
|
|
|
|
|
State layouts now use the typed context and commands proposed here; full scenario
|
|
|
|
|
|
and process direct editing remain separate release work.
|
2026-09-05 20:00:21 +03:00
|
|
|
|
|
|
|
|
|
|
## 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
|
2026-09-06 02:13:49 +03:00
|
|
|
|
valid. Use the existing constructor syntax:
|
|
|
|
|
|
`projection { StateMachine { machine @operating_modes; }; };`.
|
2026-09-05 20:00:21 +03:00
|
|
|
|
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.
|
2026-09-06 02:13:49 +03:00
|
|
|
|
|
|
|
|
|
|
## Current-interface review (2026-09-06)
|
|
|
|
|
|
|
|
|
|
|
|
Independent core and desktop maps confirm the payload projection remains the
|
|
|
|
|
|
smallest persisted boundary. Preserve unit-variant JSON strings; the new value
|
|
|
|
|
|
is `{"StateMachine":{"machine":"UUID"}}`. A machine context is required for
|
|
|
|
|
|
empty and partial views; inferring it from placements cannot represent an empty
|
|
|
|
|
|
diagram, while an optional unrelated Diagram context adds invalid combinations.
|
|
|
|
|
|
Use one narrow state-view membership predicate and preserve existing projections'
|
|
|
|
|
|
legal hidden placements. Dedicated views disappear with their machine; moving
|
|
|
|
|
|
elements across machines must repair incompatible views/routes in the same Batch
|
|
|
|
|
|
or reject atomically.
|
|
|
|
|
|
|
|
|
|
|
|
The shared router now owns route pins, label placement and grouped translation.
|
|
|
|
|
|
An executed probe found that merely retaining an External self-transition yields
|
|
|
|
|
|
an 18 px out-and-back stub. Add genuine self-loop and state-symbol endpoint
|
|
|
|
|
|
geometry in the shared routing/projection path; Entry/Exit snapping must precede
|
|
|
|
|
|
draw/hit testing. Internal transitions remain rows, and folded descendants must
|
|
|
|
|
|
not create false visible self-transitions. Probe:
|
|
|
|
|
|
`D:/CodexBuilds/Capella2-source-document-contract/examples/state_projection_boundary_probe.rs`.
|
|
|
|
|
|
|
|
|
|
|
|
Before adding gestures, close existing behavior draft gaps: Start/Edit must not
|
|
|
|
|
|
overwrite an unresolved form, Submit must retain it until Document source/model
|
|
|
|
|
|
commit succeeds, and Save/Close/navigation must account for behavior drafts.
|
|
|
|
|
|
Canvas events carry the existing document/diagram/revision/epoch context and
|
|
|
|
|
|
recheck it before acceptance. Generic MoveNode message delivery selects the
|
|
|
|
|
|
current active diagram and is insufficient for delayed behavior gestures.
|
|
|
|
|
|
|
|
|
|
|
|
Keep Select, State/symbol, Region, Transition and Fit in a compact toolbar.
|
|
|
|
|
|
Create inside an explicitly highlighted eligible owner, place missing ancestry
|
|
|
|
|
|
in the same command batch, and expose unplaced semantic elements. Retain the
|
|
|
|
|
|
behavior view independently of selection, including root Events. Reconnect
|
|
|
|
|
|
clones the relation and changes one endpoint; preserve all other data and reject
|
|
|
|
|
|
invalid cardinalities. Keep form editing in a bounded panel so the canvas remains
|
|
|
|
|
|
usable at 1100×700. These are decision-ready interfaces; no implementation or
|
2026-09-06 03:31:26 +03:00
|
|
|
|
native gesture acceptance is claimed by this design record. The implemented
|
|
|
|
|
|
contract and subsequent acceptance evidence are in release-state-editing.md;
|
|
|
|
|
|
production316dc55 closes the direct state slice, while scenario/process work remains.
|