6.2.3. Aggregate Family¶
6.2.3.1. When To Use It¶
Use AggregateVM1 through AggregateVM6 when the parent owns a fixed set of
heterogeneous children and each slot has a stable semantic role: workspace
shells, multi-pane roots, dashboards, or status bundles.
This is the right primitive when "component 1" and "component 2" mean different things and variable-length child lists would weaken the contract.
6.2.3.2. Shape And Ownership¶
An aggregate is a component-shaped parent with named child slots:
Component1is always present on every arity.- Higher arities add
Component2throughComponent6. - Each slot is populated lazily through a factory during
construct().
The explicit arity surface is deliberate. VMx keeps AggregateVM1 through
AggregateVM6 rather than a variadic abstraction so every flavor preserves the
same compile-time slot contract.
Aggregate slots are fixed ownership positions. All factories are evaluated and validated before any existing slot is overwritten. A duplicate identity, an already-owned component, or an ownership cycle rejects the population without changing prior slots. A populated aggregate child cannot be transferred into a mutable container because that would leave an invalid empty slot.
6.2.3.3. Lifecycle And Messaging¶
Construction and destruction cascade through the slot children:
- slot factories run during
construct() - each populated child is constructed
- the aggregate reaches
Constructedonly after every child does
Each successful slot population publishes a property-changed message for that
slot (Component1, component_1, component1, and so on).
Reconstruction is transactional across every slot. VMx creates and validates all candidates before disposing old slots. It continues cleanup after a slot failure, remembers the first failure, and then either commits every viable candidate together or disposes them all if the aggregate became terminal. Factory or ownership preflight failure leaves all old slots and parent links unchanged. Concurrent disposal waits for this decision, so it never observes a half-replaced aggregate.
6.2.3.4. Cross-Language Surface¶
| Concept | C# | Python | TypeScript | Swift | Rust |
|---|---|---|---|---|---|
| Arity-6 type | AggregateVM6<...> |
AggregateVM6[...] |
AggregateVM6<...> |
AggregateVM6<...> |
AggregateVm6<...> |
| Slot builder setters | Component1(...) |
component_1(...) |
component1(...) |
component1(...) |
component_1(...) |
| Slot property | Component1 |
component_1 |
component1 |
component1 |
component_1() |
6.2.3.5. Example¶
C#:AggregateVM6<...>.Builder().Name("workspace").Services(hub, dispatcher).Component1(() => notebooks).Component2(() => notes).Build()Python:AggregateVM6Builder[...]().name("workspace").services(hub, dispatcher).component_1(lambda: notebooks).component_2(lambda: notes).build()TypeScript:AggregateVM6.builder<...>().name("workspace").services(hub, dispatcher).component1(() => notebooks).component2(() => notes).build()Swift:try AggregateVM6<...>.builder().name("workspace").services(hub: hub, dispatcher: dispatcher).component1 { notebooks }.component2 { notes }.build()Rust:AggregateVm6::<...>::builder().name("workspace").services(hub, dispatcher).component_1(|| notebooks.clone()).component_2(|| notes.clone()).build()?
The Notes Workspace shell uses this pattern as its six-pane root in the C#, Python, TypeScript, and Swift examples.
Rust implements the same aggregate type and builder shape. Its slot-notification and construction ordering evidence is recorded in the completed Rust parity ledger.
6.2.3.6. Common Pitfalls¶
- Using an aggregate when the child set is variable or homogeneous. Prefer
CompositeVMorGroupVM. - Expecting slot factories to run at build time. They run at construct time.
- Passing a component that is still owned by a composite or group. Remove it explicitly before returning it from an aggregate factory.
- Flattening semantic slots into a list and losing explicit ownership names.
- Treating slot children as selectable peers. Aggregates own structure, not a
Currentselection slot.