// Milestone fieldtest — axis (c): nest a composite INSIDE another composite, // build a Blueprint, compile() + bootstrap() + run(). The milestone promises // composites "nest arbitrarily" and that the compiled/flat view handles // nesting (#26 notes the CLUSTERED blueprint render has an `unimplemented!` on // nested composites — but that path is only reachable through `aura graph` on // the built-in sample, which a downstream consumer cannot point at their own // graph; see the spec finding). // // Here we verify the run-path promise from the consumer side: a composite that // CONTAINS a composite lowers (inlines, recursively) to a flat runnable // instance that produces a populated trace. // // Public interface only. use std::sync::mpsc; use aura_core::{Firing, Scalar, ScalarKind, Timestamp}; use aura_engine::{Blueprint, BlueprintNode, Composite, Edge, OutPort, SourceSpec, Target}; use aura_std::{Exposure, Recorder, SimBroker, Sma, Sub}; /// Inner composite: the SMA(2)/SMA(4) cross (one price role -> spread output). fn inner_cross() -> Composite { Composite::new( "sma_cross", vec![ BlueprintNode::from(Sma::new(2)), BlueprintNode::from(Sma::new(4)), BlueprintNode::from(Sub::new()), ], vec![ Edge { from: 0, to: 2, slot: 0, from_field: 0 }, Edge { from: 1, to: 2, slot: 1, from_field: 0 }, ], vec![vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }]], OutPort { node: 2, field: 0 }, ) } /// Outer composite: wraps inner_cross then maps it through Exposure(0.5). /// Interior: 0 = inner_cross (Composite), 1 = Exposure(0.5). /// One price role fans into the inner composite's role 0. /// Output: Exposure's output field. fn strategy() -> Composite { Composite::new( "strategy", vec![ BlueprintNode::Composite(inner_cross()), BlueprintNode::from(Exposure::new(0.5)), ], vec![Edge { from: 0, to: 1, slot: 0, from_field: 0 }], // cross -> Exposure vec![vec![Target { node: 0, slot: 0 }]], // price -> inner role 0 OutPort { node: 1, field: 0 }, ) } fn main() { let (tx, rx) = mpsc::channel::<(Timestamp, Vec)>(); // Top-level: 0 = strategy (nested Composite), 1 = SimBroker, 2 = Recorder. let blueprint = Blueprint::new( vec![ BlueprintNode::Composite(strategy()), BlueprintNode::from(SimBroker::new(1e-4)), BlueprintNode::from(Recorder::new(&[ScalarKind::F64], Firing::Any, tx)), ], vec![SourceSpec { kind: ScalarKind::F64, targets: vec![ Target { node: 0, slot: 0 }, // strategy price role Target { node: 1, slot: 1 }, // broker price leg ], }], vec![ Edge { from: 0, to: 1, slot: 0, from_field: 0 }, // strategy -> broker.exposure Edge { from: 1, to: 2, slot: 0, from_field: 0 }, // broker -> Recorder ], ); let mut harness = blueprint .bootstrap() .expect("nested-composite blueprint should bootstrap"); let prices: Vec = vec![ 1.00, 1.01, 1.02, 1.03, 1.05, 1.08, 1.06, 1.04, 1.02, 1.01, 1.03, 1.07, ]; let stream: Vec<(Timestamp, Scalar)> = prices .iter() .enumerate() .map(|(i, &p)| (Timestamp(60_000_000_000 * i as i64), Scalar::F64(p))) .collect(); harness.run(vec![stream]); drop(harness); let rows: Vec<(Timestamp, Vec)> = rx.iter().collect(); println!("nested-composite recorded rows: {}", rows.len()); assert!( !rows.is_empty(), "a composite-in-composite must inline to a flat runnable instance" ); println!("OK: composite-inside-composite inlined, bootstrapped, ran, recorded."); }