Relationships
Relationships are typed references between instances. Together with fields, they make SedaroML models relational: a model is a graph of instances, not a bag of records. Relationships represent:
- Flows — e.g. data, propellant, electrical current
- Composition — e.g. Component A is bolted to Component B
- Association — e.g. a
Threatwas launched by aThreatLauncher
Declaring Relationships
A relationship is simply a field whose type is another ontology. The shape of the type determines cardinality:
| Declaration | Cardinality | Supported |
|---|---|---|
battery: Battery | one-to-one, required | ✅ |
battery: Battery? | one-to-one, optional | ✅ |
cells: list[BatteryCell] | one-to-many (ordered) | ✅ |
cells: set[BatteryCell] | one-to-many (unordered) | ✅ |
panels: (SolarPanel, SolarPanel) | one-to-many (fixed arity) | ✅ |
source: GroundStation | Satellite | one-to-one (union target) | ❌ |
cells: dict[str, BatteryCell] | one-to-many (keyed) | ❌ |
A union target (source: GroundStation | Satellite) and a keyed / "data side" dict relationship (cells: dict[str, BatteryCell]) are expressible in the language surface but are not currently supported relation types — see Current Limitations.
Because subtyping applies, a relationship targeting Actuator accepts any instance whose ontology extends Actuator.
Reverse Relationships
A relationship may declare a reverse: the name of a field on the target ontology that refers back. As the model is built, the two sides are kept consistent — setting the forward side populates the reverse side:
- If the reverse field is a collection, the referring instance is added to it.
- If the reverse field is scalar, it is set — and if it is already set to a different instance, the assignment is an error (no silent re-linking).
For example, Threat.threatLauncher (with reverse threats) and ThreatLauncher.threats (with reverse threatLauncher) form a consistent one-to-many pair maintained from either side.
The built-in parent/children pair that forms the composition tree is itself an ordinary reverse-linked relationship — composition is not a separate mechanism, just a distinguished relationship. Within a single agent, every instance is reachable from the agent root through the transitive closure of children, so the composition tree spans the whole agent.
Current Limitations
- Many-to-many reverse relationships are not yet supported.
- Union-target relationships (
source: A | B) are not currently a supported relation type:RelInfois rejected on union targets, so reverse links cannot attach to them — model the alternatives as separate fields instead. - Keyed (
dict) relationships — the simulator's data-side relationships — are not currently available in SedaroML.