//! End-to-end coverage for the `FlatTap` / `FlatGraph.taps` plumbing (#282): //! a `Composite` can declare a `Tap` (via `with_taps`), and `compile()` now //! resolves it into the flat graph it hands to `Harness::bootstrap`. These //! tests pin the two halves of that contract at the public `aura_engine` //! boundary: `compile()` surfaces a declared `Tap` into `FlatGraph.taps`, //! resolved to its flat producer `(node, field)` //! (`compile_resolves_a_declared_tap_at_the_public_boundary`), and doing so //! is otherwise transparent to compilation of the rest of the graph — the //! same node/edge structure, just an added taps entry //! (`tapped_composite_compiles_identically_to_untapped_besides_the_taps_list`). use aura_core::ScalarKind; use aura_engine::{BlueprintNode, CompileError, Composite, FlatTap, OutField, Role, Tap, TapWire, Target}; use aura_std::Sub; /// A trivial one-node composite with a single declared output (`Sub`'s /// difference), matching the `taps` argument requested by each test. Both of /// `Sub`'s input slots are fed by one root-bound (source) role — enough to /// satisfy `compile()`'s port-connectivity + root-binding checks. fn leaf(taps: Vec) -> Composite { Composite::new( "leaf", vec![Sub::builder().into()], vec![], vec![Role { name: "price".into(), targets: vec![Target { node: 0, slot: 0 }, Target { node: 0, slot: 1 }], source: Some(ScalarKind::F64), }], vec![OutField { node: 0, field: 0, name: "o".into() }], ) .with_taps(taps) } /// Property: **`compile()` resolves a declared `Tap` at the public /// boundary.** A composite declaring a valid `Tap` (naming a real interior /// producer, `node: 0, field: 0`) compiles to a `FlatGraph` whose `taps` list /// carries the resolved `FlatTap` — name preserved, wire resolved to the flat /// producer index. #[test] fn compile_resolves_a_declared_tap_at_the_public_boundary() { let tapped = leaf(vec![Tap { name: "spread".into(), from: TapWire { node: 0, field: 0 } }]); let flat = tapped.compile().expect("a tap-bearing composite compiles"); assert_eq!( flat.taps, vec![FlatTap { name: "spread".into(), node: 0, field: 0 }], "compile() must resolve the declared Tap into FlatGraph.taps: {:?}", flat.taps ); } /// Property: **a declared `Tap` is otherwise inert at compile time** — it /// changes nothing about the flattened node/edge structure. Compiling the /// same composite with and without a `Tap` declaration must produce /// structurally identical flat graphs (same node count, same edges); the /// only difference tap-bearing scaffolding is allowed to make is the `taps` /// list itself (empty vs. carrying the one resolved entry). #[test] fn tapped_composite_compiles_identically_to_untapped_besides_the_taps_list() { let untapped = leaf(vec![]).compile().expect("untapped compiles"); let tapped = leaf(vec![Tap { name: "spread".into(), from: TapWire { node: 0, field: 0 } }]) .compile() .expect("tapped compiles"); assert_eq!(untapped.nodes.len(), tapped.nodes.len(), "tap declaration must not add/remove flat nodes"); assert_eq!(untapped.edges, tapped.edges, "tap declaration must not perturb flat edges"); assert!(untapped.taps.is_empty(), "the untapped composite compiles to an empty taps list"); assert_eq!( tapped.taps, vec![FlatTap { name: "spread".into(), node: 0, field: 0 }], "the tapped composite compiles to the one resolved entry" ); } /// Property: **the `validate_wiring` structural leg rejects a tap whose wire /// names a node index beyond the composite's own node count**, before any /// lowering or field-arity resolution ever runs — mirroring how the sibling /// `output` leg raises `OutputPortOutOfRange` for the same shape of mistake. /// This is the early, cheap structural gate (`tap.from.node >= nodes.len()`) /// added alongside tap resolution in this iteration; without it, a /// wildly-out-of-range tap wire would only be caught by luck at whichever /// later stage happens to index into a lowering table, not deterministically /// at compile's first validation pass. #[test] fn compile_rejects_a_tap_wire_node_out_of_range() { let tapped = leaf(vec![Tap { name: "ghost".into(), from: TapWire { node: 1, field: 0 } }]); match tapped.compile() { Err(CompileError::TapWireOutOfRange { tap }) => assert_eq!(tap, "ghost"), other => panic!("expected TapWireOutOfRange{{tap: \"ghost\"}}, got {:?}", other.map(|_| ())), } } /// Property: **a `Tap` declared on a nested composite hoists all the way to /// the root `FlatGraph.taps`, with its wire remapped through the inline /// offset** accumulated by every flat node lowered ahead of it — not just /// carried through unresolved, and not resolved to its interior-local index. /// The root here lowers a plain leaf node first (flat index 0) followed by /// the tapped composite (whose interior `Sub` therefore lands at flat index /// 1, not 0), so a remap that silently stayed at the interior-local index — /// or hoisted at all — is caught by asserting the hoisted `FlatTap` points at /// index 1. This is the exact shape the by-name tap-binding CLI wrapper /// needs: a tap declared arbitrarily deep in an authored blueprint must /// surface as one flat, addressable measurement point at the root. #[test] fn compile_hoists_a_nested_composite_tap_to_the_root_with_remapped_index() { let inner = Composite::new( "inner", vec![Sub::builder().into()], vec![], vec![Role { name: "x".into(), targets: vec![Target { node: 0, slot: 0 }, Target { node: 0, slot: 1 }], source: None }], vec![OutField { node: 0, field: 0, name: "o".into() }], ) .with_taps(vec![Tap { name: "inner_d".into(), from: TapWire { node: 0, field: 0 } }]); let root = Composite::new( "root", vec![Sub::builder().into(), BlueprintNode::Composite(inner)], vec![], vec![ Role { name: "lead".into(), targets: vec![Target { node: 0, slot: 0 }, Target { node: 0, slot: 1 }], source: Some(ScalarKind::F64), }, Role { name: "a".into(), targets: vec![Target { node: 1, slot: 0 }], source: Some(ScalarKind::F64) }, ], vec![], ); let flat = root.compile().expect("root with a nested tapped composite compiles"); assert_eq!( flat.taps, vec![FlatTap { name: "inner_d".into(), node: 1, field: 0 }], "the inner tap must hoist to root FlatGraph.taps, remapped to the inline-offset flat node index" ); }