Files
Aura/fieldtests/milestone-construction-layer/mc_1_composite_build_run.rs
T
Brummel 7e195f66b7 fieldtest: milestone construction-layer — 4 examples, 7 findings
End-to-end milestone fieldtest (closing gate) for the "Construction layer"
milestone (#12 composites + #13 aura graph render). Four real downstream tasks
authored against the PUBLIC interface only (ledger + doc-comments + re-exports
+ the aura CLI), under fieldtests/milestone-construction-layer/:
  mc_1 — author a named sma_cross composite, build a Blueprint, compile +
         bootstrap + run (12 populated equity rows);
  mc_2 — correct vs fast/slow-swapped cross: labels + graph-as-data differ
         observably (the headline mis-wire-visible property);
  mc_3 — composite-nested-in-composite inlines and runs;
  mc_4 — walk the built graph via the read-only accessors, no engine internals.

Roll-up: friction_found, NO bugs. The milestone delivers its core promise —
fractal authoring -> compile -> bootstrap -> run, introspection as graph-as-data,
and param-carrying labels that make a mis-wire readable. None of the findings
block the gate.

Findings filed to the forward queue (not fixed here):
- #28 (feature) — the headline friction: `aura graph` renders only the built-in
  sample and the render adapter is CLI-private, so a consumer can't render their
  OWN graph. Subsumes the reachability of #26 (the nested-render panic is
  structurally unreachable until the render is parameterizable). Likely next
  (consumer-project / World) milestone.
- #29 (idea) — aura-engine doesn't re-export the scalar vocabulary (ScalarKind
  etc.) a graph-builder needs; one-crate ergonomics tidy.
- #16 (comment) — `aura graph` arg policy (help / unknown-arg) should unify with
  the still-open `aura run` strictness question.

The fieldtester read no implementation source; all artefacts are the consumer
crate + the two live render captures (render_clustered.txt / render_compiled.txt,
byte-identical across runs).
2026-06-05 22:38:39 +02:00

112 lines
4.7 KiB
Rust

// Milestone fieldtest — axis (a): author a small signal as a reusable NAMED
// Composite, build a Blueprint that uses it, compile() + bootstrap() + run(),
// and confirm the recorded trace is non-empty.
//
// Public interface only: Blueprint / Composite / BlueprintNode / Edge / Target /
// OutPort / SourceSpec from aura-engine; Sma / Sub / Exposure / SimBroker /
// Recorder from aura-std; ScalarKind / Scalar / Firing / Timestamp from
// aura-core. No crates/*/src was read.
//
// The downstream task: package an SMA(2)/SMA(4)-cross into a reusable
// `sma_cross` composite exposing one output (the cross spread), then wire that
// composite into a harness blueprint (source -> composite -> Exposure ->
// SimBroker -> Recorder), bootstrap it, and run it over a tiny synthetic price
// ramp. This is the milestone's headline authoring story: build a graph
// fractally from a Rust builder via a named composite.
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};
fn main() {
// --- The reusable composite: a 2/4 SMA cross. ----------------------------
// Interior layout (local indices):
// 0: Sma(2) (fast) 1: Sma(4) (slow) 2: Sub (fast - slow)
// One input role (the price) fans into BOTH SMAs' slot 0.
// The exposed output port is Sub's single output field.
let sma_cross = Composite::new(
"sma_cross",
vec![
BlueprintNode::from(Sma::new(2)),
BlueprintNode::from(Sma::new(4)),
BlueprintNode::from(Sub::new()),
],
// interior edges (local indices): fast -> Sub.slot0, slow -> Sub.slot1
vec![
Edge { from: 0, to: 2, slot: 0, from_field: 0 },
Edge { from: 1, to: 2, slot: 1, from_field: 0 },
],
// input role 0 (price) fans into Sma(2).slot0 AND Sma(4).slot0
vec![vec![
Target { node: 0, slot: 0 },
Target { node: 1, slot: 0 },
]],
// single exposed output: Sub's output field 0
OutPort { node: 2, field: 0 },
);
// --- The harness blueprint that USES the composite. ----------------------
// Top-level items:
// 0: sma_cross (Composite) 1: Exposure(0.5) 2: SimBroker(1e-4)
// 3: Recorder over [F64] (taps the broker equity)
let (tx, rx) = mpsc::channel::<(Timestamp, Vec<Scalar>)>();
let blueprint = Blueprint::new(
vec![
BlueprintNode::Composite(sma_cross),
BlueprintNode::from(Exposure::new(0.5)),
BlueprintNode::from(SimBroker::new(1e-4)),
BlueprintNode::from(Recorder::new(&[ScalarKind::F64], Firing::Any, tx)),
],
// one f64 price source: feeds the composite (item 0, role 0) AND the
// broker's price leg (item 2, slot 1).
vec![SourceSpec {
kind: ScalarKind::F64,
targets: vec![
Target { node: 0, slot: 0 }, // composite price role
Target { node: 2, slot: 1 }, // broker price leg
],
}],
// top-level edges: composite-out -> Exposure -> broker.exposure(slot0)
// -> Recorder
vec![
Edge { from: 0, to: 1, slot: 0, from_field: 0 }, // sma_cross -> Exposure
Edge { from: 1, to: 2, slot: 0, from_field: 0 }, // Exposure -> SimBroker.exposure
Edge { from: 2, to: 3, slot: 0, from_field: 0 }, // SimBroker -> Recorder
],
);
// --- compile() + bootstrap() + run() -------------------------------------
let mut harness = blueprint
.bootstrap()
.expect("composite-authored blueprint should bootstrap");
// a synthetic upward price ramp then a dip, enough to warm SMA(4) and flip
let prices: Vec<f64> = 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); // drop the recorder's tx clone held inside
let rows: Vec<(Timestamp, Vec<Scalar>)> = rx.iter().collect();
println!("recorded equity rows: {}", rows.len());
for (ts, row) in &rows {
let v = match row[0] {
Scalar::F64(x) => x,
other => panic!("expected f64 equity, got {other:?}"),
};
println!(" ts={:>14} equity_pips={:.4}", ts.0, v);
}
assert!(
!rows.is_empty(),
"the composite-authored harness must record a populated equity trace"
);
println!("OK: composite authored, compiled, bootstrapped, ran, recorded.");
}