audit: cycle 0003 tidy — rename Sim -> Harness (glossary alignment)
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<dyn Node> 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).
This commit is contained in:
@@ -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<NodeBox>,
|
||||
topo: Vec<usize>,
|
||||
out_edges: Vec<Vec<Edge>>,
|
||||
@@ -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<Edge>,
|
||||
source_kind: ScalarKind,
|
||||
observe: usize,
|
||||
) -> Result<Sim, BootstrapError> {
|
||||
) -> Result<Harness, BootstrapError> {
|
||||
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<Option<Scalar>> {
|
||||
// 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<Box<dyn Node>> = 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<Box<dyn Node>> =
|
||||
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<Box<dyn Node>> = 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<Box<dyn Node>> = 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<Box<dyn Node>> = vec![Box::new(Sma::new(1))];
|
||||
let err = Sim::bootstrap(
|
||||
let err = Harness::bootstrap(
|
||||
nodes,
|
||||
vec![Target { node: 0, slot: 0 }],
|
||||
vec![],
|
||||
@@ -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};
|
||||
|
||||
Reference in New Issue
Block a user