Implements the frontend side of the control-flow engine's Fase 4-5
backend extension: presentation-only swimlanes for grouping nodes by
actor/responsibility, and a new IOType.JSON for structured input/
output descriptors. Both are additive/optional fields, backward
compatible with existing flows.
Swimlanes:
- Model: FlowLane (id, name, description, order, color), FlowData.lanes,
and an optional laneId on every block/container.
- Lane management (add/rename/reorder/color/delete) in a new "Lanes"
section of the title toolbar, mirroring the existing Global Inputs
editor. Deleting a lane clears laneId on any node that referenced it,
avoiding an immediate NODE_LANE_NOT_FOUND validation error.
- Real visual swimlanes on the rete.js canvas: horizontal color-coded
bands with labels that pan/zoom together with the nodes, backed by a
transform layer kept in sync with the area's live transform.
- Drag-to-reassign: moving a node updates its laneId based on the drop
Y position, but only for genuine pointer drags — programmatic moves
(initial load, clone, server-side node regeneration) are excluded via
the existing programmatic-translation tracking, so loading a flow
never silently reassigns lanes.
- A small lane badge on the node header confirms the current
assignment after a drag.
- The readonly/execution-view diff and patch logic now accounts for
laneId and lanes so live updates are detected correctly.
Also fixes a data-loss bug found while wiring this up: exportGraph()
rebuilt each node and the top-level FlowData as explicit object
literals that never carried laneId/lanes through, and flowFromApi()
never normalized lanes coming back from the backend — both would have
silently dropped the field on save/reload, the same class of bug fixed
earlier for biasAnnotations.
JSON IO type:
- Global input type picker now offers JSON alongside TEXT/FILE.
- Behavioral probe editor: JSON-typed mock outputs default to {} and
use the JSON textarea editor instead of a plain text input.
- portSelectableKinds (generic-node) includes JSON among the concrete
types offered wherever a port's kind is ANY.
Verified with the full suite (253/253, 21 new tests) and a live
end-to-end browser check: created two lanes, dragged a node from the
unassigned area into a lane (confirmed via the node's lane badge),
saved, and reopened the saved flow with the lane assignment intact.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>