//! Fieldtest c0006 #4 — recorded output is byte-identical across two runs (C1). //! //! Axis: "Then verify determinism: same input => byte-identical recorded output //! across two runs." //! //! Two fresh harnesses (each its own channel), identical input. Drain both //! recorded streams and assert bit-identical. A recorded side effect cannot feed //! back into the graph, so determinism must hold (the cycle's own acceptance //! claim). To make "byte-identical" concrete we compare the bit patterns of the //! recorded f64s, not just `==` (which treats NaN specially), and the timestamps. use std::sync::mpsc::{self, Sender}; use aura_core::{Ctx, Firing, InputSpec, Node, NodeSchema, Scalar, ScalarKind, Timestamp}; use aura_engine::{Edge, Harness, SourceSpec, Target}; use aura_std::{Sma, Sub}; struct Recorder { tx: Sender<(Timestamp, f64)>, } impl Recorder { fn new(tx: Sender<(Timestamp, f64)>) -> Self { Self { tx } } } impl Node for Recorder { fn schema(&self) -> NodeSchema { NodeSchema { inputs: vec![InputSpec { kind: ScalarKind::F64, lookback: 1, firing: Firing::Any, }], output: vec![], } } fn eval(&mut self, ctx: Ctx<'_>) -> Option<&[Scalar]> { let w = ctx.f64_in(0); if w.is_empty() { return None; } let _ = self.tx.send((ctx.now(), w[0])); None } } fn f64_stream(pairs: &[(i64, f64)]) -> Vec<(Timestamp, Scalar)> { pairs .iter() .map(|&(t, v)| (Timestamp(t), Scalar::F64(v))) .collect() } fn build_and_run(tx: Sender<(Timestamp, f64)>) { let mut h = Harness::bootstrap( vec![ Box::new(Sma::new(2)), Box::new(Sma::new(4)), Box::new(Sub::new()), Box::new(Recorder::new(tx)), ], vec![SourceSpec { kind: ScalarKind::F64, targets: vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }], }], vec![ Edge { from: 0, to: 2, slot: 0, from_field: 0 }, Edge { from: 1, to: 2, slot: 1, from_field: 0 }, Edge { from: 2, to: 3, slot: 0, from_field: 0 }, ], ) .expect("valid DAG"); h.run(vec![f64_stream(&[ (1, 10.5), (2, 12.25), (3, 9.75), (4, 16.0), (5, 18.125), (6, 7.0), (7, 21.5), ])]); } fn main() { let (tx1, rx1) = mpsc::channel(); build_and_run(tx1); let run1: Vec<(Timestamp, f64)> = rx1.try_iter().collect(); let (tx2, rx2) = mpsc::channel(); build_and_run(tx2); let run2: Vec<(Timestamp, f64)> = rx2.try_iter().collect(); println!("run1 = {run1:?}"); println!("run2 = {run2:?}"); // bit-exact comparison (f64::to_bits) — true byte-identity, not float ==. assert_eq!(run1.len(), run2.len(), "same number of recorded events"); for (a, b) in run1.iter().zip(run2.iter()) { assert_eq!(a.0, b.0, "timestamps byte-identical"); assert_eq!(a.1.to_bits(), b.1.to_bits(), "values byte-identical"); } assert!(!run1.is_empty(), "the run actually recorded something"); println!("c0006_4 OK: recorded output byte-identical across two runs (C1)"); }