From 02fe89176fb96180a2a7d3e0e2fc80c1aee06349 Mon Sep 17 00:00:00 2001 From: Brummel Date: Wed, 3 Jun 2026 13:07:43 +0200 Subject: [PATCH] =?UTF-8?q?audit:=20cycle=200003=20tidy=20=E2=80=94=20rena?= =?UTF-8?q?me=20Sim=20->=20Harness=20(glossary=20alignment)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Architect drift review over 71c8f6e..dd5c3fa (deterministic-sim-loop). Invariants hold: C1 (single-threaded, bit-identical re-run, alloc-free per-cycle ring path), C7 (AnyColumn type-erased edges, Box is the node object not a dyn-Any payload, kinds checked once at bootstrap), C8/C9 (DAG wired, Kahn rejects cycles, None forwards nothing = sample-and-hold seed). Column::run_count already exists, so the C5 freshness primitive lives at the substrate — the deferral is honest, not a hole. Resolved [high]: the runtime type was named `Sim`, colliding with the glossary's load-bearing distinction — `sim` is the disjoint *executable unit / parallelism* framing, whereas the thing built here (a closed root graph of source + nodes + observe under a clock) is by C20 / the glossary a **harness**. Renamed `Sim` -> `Harness`, `sim.rs` -> `harness.rs`, and the module/exports/doc to match, before any other code takes a dependency on the wrong term. Gates re-run green (26 tests, clippy -D warnings, purity grep). Resolved [med] (glossary gap): added an `edge` entry anchoring the new wiring vocabulary (Edge / source target) to the glossary — record-reality per the boss glossary-write authority. Carry-on with forward notes (next-cycle owners, not fixes now): - [med] C4 monotonic cycle_id has no realization in the runtime type yet (the cycle clock is the record iteration; the explicit counter's first reader is freshness). Cycle 0004 owns materializing it together with C5. - [low] Sub declares lookback 1; once depth>1 join nodes exist, add a test guarding C8's "a node never reads beyond its declared lookback". Regression gate: profile regression list empty — architect is the sole gate, now clean. Next direction: freshness-gated recompute + a second source (C5/C3). --- crates/aura-engine/src/{sim.rs => harness.rs} | 41 ++++++++++--------- crates/aura-engine/src/lib.rs | 9 ++-- docs/glossary.md | 4 ++ 3 files changed, 30 insertions(+), 24 deletions(-) rename crates/aura-engine/src/{sim.rs => harness.rs} (90%) diff --git a/crates/aura-engine/src/sim.rs b/crates/aura-engine/src/harness.rs similarity index 90% rename from crates/aura-engine/src/sim.rs rename to crates/aura-engine/src/harness.rs index f116185..5c68d91 100644 --- a/crates/aura-engine/src/sim.rs +++ b/crates/aura-engine/src/harness.rs @@ -1,10 +1,11 @@ -//! The deterministic single-source sim loop. A `Sim` is a bootstrapped, frozen -//! root graph — a flat node array plus an index edge table, topologically ordered -//! — driven cycle by cycle by one source. It is the flat, monomorphized sharpening -//! of RustAst's reference-counted, interior-mutable observer push graph: no -//! reference counting, no interior mutability, no per-cycle allocation (C1/C7). -//! Each node owns its input -//! columns (the cycle-0002 shape), so `Ctx` is unchanged; a producer's `eval` +//! The harness — the closed root graph that runs (glossary: `harness`, C20) — +//! and its deterministic single-source run loop. A `Harness` is a bootstrapped, +//! frozen root graph: a flat node array plus an index edge table, topologically +//! ordered, driven cycle by cycle by one source. It is the flat, monomorphized +//! sharpening of RustAst's reference-counted, interior-mutable observer push +//! graph: no reference counting, no interior mutability, no per-cycle allocation +//! (C1/C7). Each node owns its input columns (the cycle-0002 shape), so `Ctx` is +//! unchanged; a producer's `eval` //! output is forwarded into its consumers' input columns, and a `None` forwards //! nothing (the structural seed of sample-and-hold, realized with freshness in a //! later cycle). @@ -45,7 +46,7 @@ struct NodeBox { } /// A bootstrapped, frozen root graph instance plus its deterministic run loop. -pub struct Sim { +pub struct Harness { nodes: Vec, topo: Vec, out_edges: Vec>, @@ -57,9 +58,9 @@ pub struct Sim { // cannot derive it. This summary form is enough for `Result::unwrap_err` (which // formats the `Ok` arm on a failed bootstrap-rejection assertion) without // printing node internals. -impl core::fmt::Debug for Sim { +impl core::fmt::Debug for Harness { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("Sim") + f.debug_struct("Harness") .field("nodes", &self.nodes.len()) .field("topo", &self.topo) .field("out_edges", &self.out_edges) @@ -69,7 +70,7 @@ impl core::fmt::Debug for Sim { } } -impl Sim { +impl Harness { /// Bind nodes + wiring into a frozen, runnable graph. Sizes each node's input /// columns from its `schema`, kind-checks every edge and source target, and /// topologically orders the nodes (Kahn), rejecting any directed cycle. @@ -79,7 +80,7 @@ impl Sim { edges: Vec, source_kind: ScalarKind, observe: usize, - ) -> Result { + ) -> Result { let n = nodes.len(); if observe >= n { return Err(BootstrapError::BadIndex); @@ -148,7 +149,7 @@ impl Sim { return Err(BootstrapError::Cycle); } - Ok(Sim { + Ok(Harness { nodes: boxes, topo, out_edges, @@ -165,7 +166,7 @@ impl Sim { ) -> Vec> { // disjoint field borrows so the topo walk can read `topo`/`out_edges` // while mutating `nodes` - let Sim { nodes, topo, out_edges, source_targets, observe } = self; + let Harness { nodes, topo, out_edges, source_targets, observe } = self; let observe = *observe; let mut out = Vec::new(); @@ -217,7 +218,7 @@ mod tests { fn chain_source_sma_runs() { // node 0 = SMA(3); source -> SMA(3).in0; observe node 0 let nodes: Vec> = vec![Box::new(Sma::new(3))]; - let mut sim = Sim::bootstrap( + let mut sim = Harness::bootstrap( nodes, vec![Target { node: 0, slot: 0 }], vec![], @@ -241,10 +242,10 @@ mod tests { #[test] fn fan_out_join_dag_runs_deterministically() { // 0 = SMA(2), 1 = SMA(4), 2 = Sub; source fans into both SMAs; SMAs join into Sub - let build = || -> Sim { + let build = || -> Harness { let nodes: Vec> = vec![Box::new(Sma::new(2)), Box::new(Sma::new(4)), Box::new(Sub::new())]; - Sim::bootstrap( + Harness::bootstrap( nodes, vec![Target { node: 0, slot: 0 }, Target { node: 1, slot: 0 }], vec![Edge { from: 0, to: 2, slot: 0 }, Edge { from: 1, to: 2, slot: 1 }], @@ -281,7 +282,7 @@ mod tests { fn bootstrap_rejects_a_cycle() { // two SMA(1) nodes wired a -> b -> a let nodes: Vec> = vec![Box::new(Sma::new(1)), Box::new(Sma::new(1))]; - let err = Sim::bootstrap( + let err = Harness::bootstrap( nodes, vec![], vec![Edge { from: 0, to: 1, slot: 0 }, Edge { from: 1, to: 0, slot: 0 }], @@ -296,7 +297,7 @@ mod tests { fn bootstrap_rejects_a_kind_mismatch() { // SMA(1) declares an f64 input; feeding an i64 source mismatches let nodes: Vec> = vec![Box::new(Sma::new(1))]; - let err = Sim::bootstrap( + let err = Harness::bootstrap( nodes, vec![Target { node: 0, slot: 0 }], vec![], @@ -314,7 +315,7 @@ mod tests { fn bootstrap_rejects_a_bad_index() { // observe node 5 does not exist let nodes: Vec> = vec![Box::new(Sma::new(1))]; - let err = Sim::bootstrap( + let err = Harness::bootstrap( nodes, vec![Target { node: 0, slot: 0 }], vec![], diff --git a/crates/aura-engine/src/lib.rs b/crates/aura-engine/src/lib.rs index 7fc395b..b93ae33 100644 --- a/crates/aura-engine/src/lib.rs +++ b/crates/aura-engine/src/lib.rs @@ -1,8 +1,9 @@ //! `aura-engine` — the headless, UI-agnostic reactive SoA engine. //! -//! Delivered in cycle 0003 — the deterministic single-source sim loop: +//! Delivered in cycle 0003 — the harness and its deterministic single-source +//! run loop: //! -//! - [`Sim`] — a bootstrapped, frozen root graph (a flat node array + an index +//! - [`Harness`] — the closed root graph that runs (a flat node array + an index //! edge table, topologically ordered) and its deterministic `run` loop: one //! source driven through a wired DAG of nodes, cycle by cycle, each output //! forwarded into its consumers' input columns (C1/C4/C7/C8/C9). @@ -18,6 +19,6 @@ //! //! Visualization is never here: it is a downstream consumer node on the streams. -mod sim; +mod harness; -pub use sim::{BootstrapError, Edge, Sim, Target}; +pub use harness::{BootstrapError, Edge, Harness, Target}; diff --git a/docs/glossary.md b/docs/glossary.md index 27f0098..5b491ca 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -51,6 +51,10 @@ A node that wires a sub-graph and exposes one output (a combined signal, or a st **Avoid:** — One data-driven clock step: one input record = one cycle, advanced in global timestamp order with a monotonic `cycle_id`. (In the pipeline-process sense "cycle" also names one milestone round; the engine sense is this clock step.) +### edge +**Avoid:** — +A directed wiring link in a harness that forwards one node's `eval` output into a consumer node's input slot (the engine's `Edge`); the source-side variant binding the source value into an input slot is a **source target** (`Target`). Edges define the DAG the bootstrap topologically orders; mismatched scalar kinds across an edge are rejected at bootstrap. + ### equity stream **Avoid:** — A broker node's output: the marked value of open positions over time — synthetic pips for the sim-optimal broker, currency for realistic brokers. An equity *curve* is explicitly not a strategy's output (the position table is).