Not a bug — a teaching-UX gap. Wiring nodes (sources / observers / inputs) is the hardest Krill concept for new users, and the only affordances were the per-type wiring editors (Sources tab, InputNodeSelectorSection), which presume the user already understands the model. There was no guided path from “I want these two nodes connected” to correctly-written wiring metadata.
The wiring model’s central asymmetry — a connection is stored on the node that observes (or reads), not on the node being observed — is invisible in the existing editors. A user editing node X has no way to express “make Y run after X” without leaving X’s editor, opening Y, and understanding that Y’s sources list is where that lives.
ConnectNodesWiring.kt (new, composeApp): ConnectRelationship enum (RUN_AFTER / OBSERVE / AS_INPUT), connectWriteTarget / connectOptionEnabled / applyConnect pure helpers. RUN_AFTER writes the selected node’s sources + SOURCE_INVOKED; OBSERVE writes the current node’s; AS_INPUT appends to the current node’s inputs only (inputs are read at execution time and never fire the node — no trigger change). All appends .distinct(), nodeAction never touched.NodeMetaDataSourceWiring.kt (shared): added the generic withInputs(...) per-subtype copy helper alongside withWiring(...), with the lockstep-when note extended to cover it.ConnectNodesWizard.kt (new): inline two-step flow (explainer + standard SourceList picker → icons + three gated radio options); confirm re-reads both nodes’ latest state and persists via ClientNodeManager.submit (the Save path, host-routed for remote write targets).DialogComponents.kt: “Connect Nodes” button below the chip on every editor’s Overview tab (EDIT mode); wizard replaces the tab content while the editor chrome stays; selecting any tab dismisses it; done exits via screenCore.reset() like Save.ConnectNodesWiringTest.kt: pins write-target selection, trigger-preserving appends, duplicate no-op, inputs-only semantics, nodeAction preservation, structural gating. Scenarios.kt: two Roborazzi screenshots of the wizard steps.when family in NodeMetaDataSourceWiring.kt (now three lockstep arms: withParentSourceDefault, withWiring, withInputs) instead of scattering meta.copy(...) casts in editors — a missing subtype arm silently makes that type’s field uneditable.