a6a314bb98
Add an additive, fluent GraphBuilder authoring surface that wires a blueprint's topology by typed node handles and port/field names instead of raw positional indices. Node references are Copy NodeHandle values (a node reference cannot be mistyped); only port/field names are strings, resolved against each node's cached NodeSchema by exactly-one-match at a single fallible build() -> Result<Composite, BuildError> — the Binder posture, one level up. build() lowers to the unchanged Composite::new, so the compilat stays index-wired (C23): names resolve at the authoring boundary and never reach FlatGraph. A new From<Composite> for BlueprintNode lets add() accept nested composites. Verified: builder-authored sma_cross is structurally equal to the hand-wired fixture, and the full builder-authored harness lowers to a byte-identical FlatGraph (equal edges + sources). The five BuildError variants (Unknown/Ambiguous In/Out, BadHandle) are covered, and the SimBroker exposure/price legs are now addressable by name (the #21 legibility win). The structural close of the exposure/price swap (#21) is deliberately out of scope — this builder makes the swap legible, not impossible — tracked as #65. Two plan-test corrections applied during implementation (both in-scope, no behaviour change): the harness parity test uses compile_with_params with a topology-invariant param vector on both sides (the harness declares three params, so a no-param compile() would trip ParamArity), and the error asserts use .err()/Some(...) rather than unwrap_err() (Composite is not Debug). aura-engine 123 tests green (+9); full workspace green; clippy --all-targets -D warnings clean. Existing index-form Composite::new sites and tests untouched (coexistence). closes #64
72 lines
3.2 KiB
Rust
72 lines
3.2 KiB
Rust
//! `aura-engine` — the headless, UI-agnostic reactive SoA engine.
|
|
//!
|
|
//! Delivered across cycles 0003-0004 — the harness and its deterministic run
|
|
//! loop:
|
|
//!
|
|
//! - [`Harness`] — the closed root graph that runs (a flat node array + an index
|
|
//! edge table, topologically ordered) and its deterministic `run` loop: a
|
|
//! k-way merge of timestamped sources (C3/C4) driven through a wired DAG of
|
|
//! nodes, cycle by cycle, with freshness-gated recompute and the two firing
|
|
//! policies (C5/C6) deciding when each node re-evaluates and what it holds.
|
|
//! - [`Edge`] / [`Target`] / [`SourceSpec`] — producer->consumer wiring,
|
|
//! source->consumer wiring, and a declared source (its kind + target slots).
|
|
//! - [`BootstrapError`] — wiring faults caught once, at bootstrap (kind
|
|
//! mismatch, bad index, directed cycle).
|
|
//!
|
|
//! Delivered in cycle 0009 — the run report surface:
|
|
//!
|
|
//! - [`RunMetrics`] / [`RunManifest`] / [`RunReport`] — the `(manifest, metrics)`
|
|
//! pair C18 mandates per run, with [`RunReport::to_json`] for the structured
|
|
//! C14 face;
|
|
//! - [`summarize`] — the post-run pure reduction over a run's recorded
|
|
//! pip-equity + exposure streams into [`RunMetrics`]; [`f64_field`] bridges a
|
|
//! recording sink's `Vec<Scalar>` rows to it.
|
|
//!
|
|
//! Still to come (subsequent cycles): the `Source` trait + data-server ingestion
|
|
//! and source-native time normalization (C3/C11), the broker-independent
|
|
//! position-event output and downstream broker nodes (C10), and the param
|
|
//! injection + orchestration axes of the atomic sim unit
|
|
//! (`(topology + params + data-window + seed)`, swept by optimize / walk-forward
|
|
//! / Monte-Carlo) — its `-> metrics` reduction now ships via [`summarize`].
|
|
//!
|
|
//! Visualization is never here: it is a downstream consumer node on the streams.
|
|
|
|
mod blueprint;
|
|
mod builder;
|
|
mod graph_model;
|
|
mod harness;
|
|
mod report;
|
|
mod sweep;
|
|
|
|
pub use blueprint::{
|
|
BindError, Binder, BlueprintNode, CompileError, Composite, OutField, Role,
|
|
SweepBinder,
|
|
};
|
|
pub use builder::{BuildError, GraphBuilder, InPort, NodeHandle, OutPort, RoleHandle};
|
|
pub use graph_model::model_to_json;
|
|
pub use harness::{BootstrapError, Edge, FlatGraph, Harness, SourceSpec, Target};
|
|
pub use report::{f64_field, summarize, RunManifest, RunMetrics, RunReport};
|
|
pub use sweep::{sweep, GridSpace, SweepError, SweepFamily, SweepPoint};
|
|
// #29: re-export the core scalar vocabulary a Blueprint builder needs
|
|
// (SourceSpec.kind is a ScalarKind; sources/Recorder columns are Scalar /
|
|
// Firing / Timestamp) so a graph builder has one import surface, not two.
|
|
pub use aura_core::{Firing, NodeSchema, ParamSpec, PortSpec, Scalar, ScalarKind, Timestamp};
|
|
|
|
#[cfg(test)]
|
|
mod test_fixtures;
|
|
|
|
#[cfg(test)]
|
|
mod reexport_tests {
|
|
// #29: the core scalar vocabulary a Blueprint builder needs is reachable
|
|
// from aura-engine alone (crate::X == external aura_engine::X), so a
|
|
// downstream author does not add a second aura-core import for ScalarKind.
|
|
#[test]
|
|
fn core_scalar_vocabulary_is_reexported_from_crate_root() {
|
|
use crate::{Firing, Scalar, ScalarKind, Timestamp};
|
|
let _k: ScalarKind = ScalarKind::F64;
|
|
let _f: Firing = Firing::Any;
|
|
let _s: Scalar = Scalar::F64(0.0);
|
|
let _t: Timestamp = Timestamp(0);
|
|
}
|
|
}
|