sim_bind
Record a checked connection between two stored models' declared ports, fromModel's fromPort (a place tagged port.output) feeding toModel's toPort (a transition tagged port.input), as a content-addressed Binding (ROADMAP.md Phase 9/11f). Checked now, by the same binds-port-v1 rule sim_run_pipeline applies: both ports exist with the right direction and element kind, the output is a token place, the input is not a delayed transition, the declared kinds are equal, port.unit agrees exactly where both ends declare one (a unit missing on either end is reported unchecked, never agreed), and a numeric transform is at most 1000000. Differing units bind only with a declared conversion, never inferred from the unit names ("order" and "orders" are two units): pass convertFrom, convertTo and convertFactor together (1 convertFrom = convertFactor convertTo), checked by binds-port-v2 — both ports declare port.unit, the two differ, convertFrom and convertTo are exactly those units, the factor is between 1e-06 and 1000000, and the transform times the factor is at most 1000000; sim_run_pipeline multiplies the resampled rate by the transform and then by the factor. A binding without a conversion is checked by binds-port-v1 exactly as before and keeps its id. A delay (hours, in (0, 10000]) is checked by binds-port-v3 (v2 plus check 12: a finite number in range; 0 is no delay and keeps the binding's id): the target receives the source's flow that many hours later and runs on its own declared rate before then, and a loop between models runs only through a binding that declares one. A self-binding is refused, with or without a delay: a model driving its own input is a loop inside one net, built with sim_extend. Set-level checks (a loop with no delayed binding, two bindings into one input, the schedule-segment cap, a loop over 4 models) belong to sim_run_pipeline and sim_create_system; a binding that closes a loop with bindings already stored is not refused here, since a loop exists only in a set someone runs or defines. A refusal stores nothing. It records binding→fromModel "from", binding→toModel "to" and fromModel→toModel "feeds"; storing the same binding twice returns the same id. A recorded binding passes every run's per-binding check; a run still applies the set-level checks to the set it is given and can stop on what only the run decides (a resampled rate that overflows at a very short horizon, the step budget, the deadline). Costs 1 compute token (it stores a Binding).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| delay | No | hours after the source's flow that toPort receives it, in (0, 10000]; default unset, no delay. Before the delay ends toPort runs on its own declared rate. A loop between models runs only through a binding with a delay (binds-port-v3) | |
| toPort | Yes | element id of the declared input port on toModel: a rated transition tagged port.input | |
| toModel | Yes | id of the model receiving the connection | |
| fromPort | Yes | element id of the declared output port on fromModel: a token place tagged port.output (see GET /api/models/{id}/ports) | |
| convertTo | No | a declared unit conversion's target unit: exactly toPort's port.unit, which must differ from fromPort's | |
| fromModel | Yes | id of the model supplying the connection's output | |
| transform | No | how fromPort's value becomes toPort's. A plain non-negative number is applied by sim_run_pipeline as a scale factor on the resampled rate; it scales, never converts a unit. Any other text (a unit note, a resample window, an aggregation) is recorded, reported by sim_run_pipeline as an assumption, and treated as 1:1 | |
| convertFrom | No | a declared unit conversion's source unit: exactly fromPort's port.unit. Pass convertFrom, convertTo and convertFactor together or none of them | |
| convertFactor | No | how many convertTo one convertFrom is (1 convertFrom = convertFactor convertTo), between 1e-06 and 1000000; sim_run_pipeline multiplies the resampled rate by it, after any numeric transform |