From d8c6938027e8e6857fd88d1e53860cf0a8f58a97 Mon Sep 17 00:00:00 2001 From: claude Date: Thu, 23 Jul 2026 16:08:26 +0200 Subject: [PATCH] feat(engine, market, strategy, backtest): NodeSchema.doc threading across the domain crates C29 compile/unit seam, tasks 4+5 of the self-description plan. aura-engine (task 4): derive_signature stamps doc: "" with the stance recorded in-code -- a derived composite signature is graph wiring, not a vocabulary entry; no seam walks its doc, the described surface is the composite's own doc at the register seam. All in-crate test literals thread doc: "test-only schema". Domain crates (task 5): the 12 production builder sites in aura-market / aura-strategy / aura-backtest carry authored meaning lines; test sites in aura-backtest / aura-composites / aura-ingest thread the test-only doc. Three texts were corrected against the actual node semantics after quality review rather than kept from the first authoring pass: SimBroker is the frictionless integrator of held exposure times price return into cumulative pip equity (no fills/stops/lifecycle -- that is PositionManagement's domain), the shared cost-node line names the PM-geometry inputs and both charge modes (AtClose / PerHeldCycle) instead of a "per-trade gross R" mapping, and LongOnly's line conditions on its enabled param and speaks port-term "exposure". Gates: cargo test green for all six touched crates (engine, market, strategy, backtest, composites, ingest); the workspace-wide gate follows task 6 (aura-runner is the one remaining unthreaded site, E0063 by design until then). refs #316 --- crates/aura-backtest/src/metrics.rs | 1 + .../aura-backtest/src/position_management.rs | 7 ++++- crates/aura-backtest/src/sim_broker.rs | 1 + crates/aura-composites/tests/risk_executor.rs | 1 + crates/aura-engine/src/blueprint.rs | 28 +++++++++++++++---- crates/aura-engine/src/graph_model.rs | 2 ++ crates/aura-engine/src/harness.rs | 9 ++++++ crates/aura-engine/tests/bind_tap_e2e.rs | 1 + crates/aura-ingest/tests/real_bars.rs | 1 + crates/aura-ingest/tests/streaming_seam.rs | 1 + crates/aura-market/src/resample.rs | 1 + crates/aura-market/src/session.rs | 2 ++ crates/aura-strategy/src/bias.rs | 1 + crates/aura-strategy/src/cost.rs | 11 +++++++- crates/aura-strategy/src/cost_sum.rs | 1 + crates/aura-strategy/src/longonly.rs | 1 + crates/aura-strategy/src/sizer.rs | 1 + crates/aura-strategy/src/stop_rule.rs | 1 + crates/aura-strategy/src/vol_tf_stop.rs | 1 + 19 files changed, 65 insertions(+), 7 deletions(-) diff --git a/crates/aura-backtest/src/metrics.rs b/crates/aura-backtest/src/metrics.rs index 1520151..c447a6c 100644 --- a/crates/aura-backtest/src/metrics.rs +++ b/crates/aura-backtest/src/metrics.rs @@ -1214,6 +1214,7 @@ mod tests { inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "in".into() }], output: vec![], params: vec![], + doc: "test-only schema", } } diff --git a/crates/aura-backtest/src/position_management.rs b/crates/aura-backtest/src/position_management.rs index b8802c7..430bbe2 100644 --- a/crates/aura-backtest/src/position_management.rs +++ b/crates/aura-backtest/src/position_management.rs @@ -87,7 +87,12 @@ impl PositionManagement { .collect(); PrimitiveBuilder::new( "PositionManagement", - NodeSchema { inputs, output, params: vec![] }, + NodeSchema { + inputs, + output, + params: vec![], + doc: "turns bias plus protective stop into a managed position in R", + }, |_| Box::new(PositionManagement::new()), ) } diff --git a/crates/aura-backtest/src/sim_broker.rs b/crates/aura-backtest/src/sim_broker.rs index e9fac88..b841d34 100644 --- a/crates/aura-backtest/src/sim_broker.rs +++ b/crates/aura-backtest/src/sim_broker.rs @@ -68,6 +68,7 @@ impl SimBroker { ], output: vec![FieldSpec { name: "equity".into(), kind: ScalarKind::F64 }], params: vec![], + doc: "frictionless sim-optimal broker: integrates held exposure times price return into cumulative pip equity", }, move |_| Box::new(SimBroker::new(pip_size)), ) diff --git a/crates/aura-composites/tests/risk_executor.rs b/crates/aura-composites/tests/risk_executor.rs index 5c87c02..e0faaca 100644 --- a/crates/aura-composites/tests/risk_executor.rs +++ b/crates/aura-composites/tests/risk_executor.rs @@ -35,6 +35,7 @@ impl ConstLongBias { inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "price".into() }], output: vec![FieldSpec { name: "bias".into(), kind: ScalarKind::F64 }], params: vec![], + doc: "test-only schema", }, |_| Box::new(ConstLongBias { out: [Cell::from_f64(0.0)] }), ) diff --git a/crates/aura-engine/src/blueprint.rs b/crates/aura-engine/src/blueprint.rs index 27cd60e..f554b21 100644 --- a/crates/aura-engine/src/blueprint.rs +++ b/crates/aura-engine/src/blueprint.rs @@ -129,7 +129,15 @@ fn derive_signature(c: &Composite) -> NodeSchema { .collect(); let mut params = Vec::new(); collect_params(c.nodes(), c.gangs(), "", &mut params); - NodeSchema { inputs, output, params } + NodeSchema { + inputs, + output, + params, + // A derived composite signature is graph wiring, not a vocabulary entry: + // no seam walks this doc. The described surface is the composite's own + // `doc`, gated at register (C29, register seam). + doc: "", + } } /// The scalar kind of the interior input slot a composite target addresses, @@ -1838,6 +1846,7 @@ mod tests { inputs: vec![], output: vec![FieldSpec { name: "v".into(), kind: ScalarKind::F64 }], params: vec![], + doc: "test-only schema", }; let to = NodeSchema { inputs: vec![ @@ -1846,6 +1855,7 @@ mod tests { ], output: vec![], params: vec![], + doc: "test-only schema", }; assert!(edge_kind_check(&from, 0, &to, 0).is_ok()); assert_eq!( @@ -2269,7 +2279,7 @@ mod tests { fn pass1() -> BlueprintNode { PrimitiveBuilder::new( "Pass1", - NodeSchema { inputs: vec![f64_any()], output: out_v(), params: vec![] }, + NodeSchema { inputs: vec![f64_any()], output: out_v(), params: vec![], doc: "test-only schema" }, |_| Box::new(Pass1 { out: [Cell::from_f64(0.0)] }), ) .into() @@ -2277,7 +2287,12 @@ mod tests { fn join2() -> BlueprintNode { PrimitiveBuilder::new( "Join2", - NodeSchema { inputs: vec![f64_any(), f64_any()], output: out_v(), params: vec![] }, + NodeSchema { + inputs: vec![f64_any(), f64_any()], + output: out_v(), + params: vec![], + doc: "test-only schema", + }, |_| Box::new(Join2 { out: [Cell::from_f64(0.0)] }), ) .into() @@ -2285,7 +2300,7 @@ mod tests { fn sink_f64() -> BlueprintNode { PrimitiveBuilder::new( "SinkF64", - NodeSchema { inputs: vec![f64_any()], output: vec![], params: vec![] }, + NodeSchema { inputs: vec![f64_any()], output: vec![], params: vec![], doc: "test-only schema" }, |_| Box::new(SinkF64), ) .into() @@ -2297,6 +2312,7 @@ mod tests { inputs: vec![PortSpec { kind: ScalarKind::I64, firing: Firing::Any, name: "in".into() }], output: vec![], params: vec![], + doc: "test-only schema", }, |_| Box::new(SinkI64), ) @@ -2849,6 +2865,7 @@ mod tests { inputs: vec![f64_any()], output: vec![], params: vec![], + doc: "test-only schema", }; let h = Harness::bootstrap(FlatGraph { nodes: vec![ @@ -3454,6 +3471,7 @@ mod tests { inputs: vec![PortSpec { kind: ScalarKind::I64, firing: Firing::Any, name: "in".into() }], output: vec![FieldSpec { name: "v".into(), kind: ScalarKind::I64 }], params: vec![], + doc: "test-only schema", }, |_| panic!("build must not run when validation fails pre-build"), ); @@ -3556,7 +3574,7 @@ mod tests { // cannot take .named). let paramless_sma = PrimitiveBuilder::new( "Pass1", - NodeSchema { inputs: vec![f64_any()], output: out_v(), params: vec![] }, + NodeSchema { inputs: vec![f64_any()], output: out_v(), params: vec![], doc: "test-only schema" }, |_| Box::new(Pass1 { out: [Cell::from_f64(0.0)] }), ) .named("sma"); diff --git a/crates/aura-engine/src/graph_model.rs b/crates/aura-engine/src/graph_model.rs index d9da496..6b4c26a 100644 --- a/crates/aura-engine/src/graph_model.rs +++ b/crates/aura-engine/src/graph_model.rs @@ -348,6 +348,7 @@ mod tests { ], output: vec![FieldSpec { name: "diff".into(), kind: ScalarKind::F64 }], params: vec![], + doc: "test-only schema", }, |_| Box::new(Bare), ) @@ -462,6 +463,7 @@ mod tests { FieldSpec { name: "lo".into(), kind: ScalarKind::I64 }, ], params: vec![], + doc: "test-only schema", }, |_| Box::new(Bare), ) diff --git a/crates/aura-engine/src/harness.rs b/crates/aura-engine/src/harness.rs index 74cdc88..883cdf4 100644 --- a/crates/aura-engine/src/harness.rs +++ b/crates/aura-engine/src/harness.rs @@ -878,6 +878,7 @@ mod tests { inputs: kinds.iter().enumerate().map(|(i, &kind)| PortSpec { kind, firing, name: format!("col[{i}]") }).collect(), output: vec![], params: vec![], + doc: "test-only schema", } } @@ -895,6 +896,7 @@ mod tests { inputs: vec![f64_port(Firing::Any), f64_port(Firing::Any)], output: vec![FieldSpec { name: "value".into(), kind: ScalarKind::F64 }], params: vec![], + doc: "test-only schema", } } } @@ -924,6 +926,7 @@ mod tests { inputs: vec![f64_port(Firing::Barrier(0)), f64_port(Firing::Barrier(0))], output: vec![FieldSpec { name: "value".into(), kind: ScalarKind::F64 }], params: vec![], + doc: "test-only schema", } } } @@ -951,6 +954,7 @@ mod tests { inputs: vec![f64_port(Firing::Any)], output: vec![FieldSpec { name: "value".into(), kind: ScalarKind::Bool }], params: vec![], + doc: "test-only schema", } } } @@ -984,6 +988,7 @@ mod tests { ], output: vec![FieldSpec { name: "value".into(), kind: ScalarKind::F64 }], params: vec![], + doc: "test-only schema", } } } @@ -1022,6 +1027,7 @@ mod tests { FieldSpec { name: "volume".into(), kind: ScalarKind::F64 }, ], params: vec![], + doc: "test-only schema", } } } @@ -1057,6 +1063,7 @@ mod tests { FieldSpec { name: "i".into(), kind: ScalarKind::I64 }, ], params: vec![], + doc: "test-only schema", } } } @@ -1084,6 +1091,7 @@ mod tests { inputs: vec![f64_port(Firing::Any)], output: vec![FieldSpec { name: "value".into(), kind: ScalarKind::F64 }], params: vec![], + doc: "test-only schema", } } } @@ -2442,6 +2450,7 @@ mod tests { FieldSpec { name: "i".into(), kind: ScalarKind::I64 }, ], params: vec![], + doc: "test-only schema", } } } diff --git a/crates/aura-engine/tests/bind_tap_e2e.rs b/crates/aura-engine/tests/bind_tap_e2e.rs index 64bf95f..a5bd52c 100644 --- a/crates/aura-engine/tests/bind_tap_e2e.rs +++ b/crates/aura-engine/tests/bind_tap_e2e.rs @@ -43,6 +43,7 @@ fn recorder_sig(kinds: &[ScalarKind]) -> NodeSchema { .collect(), output: vec![], params: vec![], + doc: "test-only schema", } } diff --git a/crates/aura-ingest/tests/real_bars.rs b/crates/aura-ingest/tests/real_bars.rs index ddca513..3ba9df5 100644 --- a/crates/aura-ingest/tests/real_bars.rs +++ b/crates/aura-ingest/tests/real_bars.rs @@ -29,6 +29,7 @@ fn run_sample_over(prices: Vec<(Timestamp, Scalar)>) -> RunReport { inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "in".into() }], output: vec![], params: vec![], + doc: "test-only schema", }; let mut h = Harness::bootstrap(FlatGraph { nodes: vec![ diff --git a/crates/aura-ingest/tests/streaming_seam.rs b/crates/aura-ingest/tests/streaming_seam.rs index 964ae64..e9ea78d 100644 --- a/crates/aura-ingest/tests/streaming_seam.rs +++ b/crates/aura-ingest/tests/streaming_seam.rs @@ -35,6 +35,7 @@ fn run_sample(window: (Timestamp, Timestamp), source: Box) -> RunRep inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "in".into() }], output: vec![], params: vec![], + doc: "test-only schema", }; let mut h = Harness::bootstrap(FlatGraph { nodes: vec![ diff --git a/crates/aura-market/src/resample.rs b/crates/aura-market/src/resample.rs index 885689a..4b62e58 100644 --- a/crates/aura-market/src/resample.rs +++ b/crates/aura-market/src/resample.rs @@ -88,6 +88,7 @@ impl Resample { FieldSpec { name: "close".into(), kind: ScalarKind::F64 }, ], params: vec![ParamSpec { name: "period_minutes".into(), kind: ScalarKind::I64 }], + doc: "emits a completed bar once per resample boundary, never mid-bar", }, |p| Box::new(Resample::new(p[0].i64())), ) diff --git a/crates/aura-market/src/session.rs b/crates/aura-market/src/session.rs index fc0db3b..6941d83 100644 --- a/crates/aura-market/src/session.rs +++ b/crates/aura-market/src/session.rs @@ -72,6 +72,7 @@ impl Session { inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "trigger".into() }], output: vec![FieldSpec { name: "bars_since_open".into(), kind: ScalarKind::I64 }], params: vec![], + doc: "bars elapsed since the session open, from the configured open time and timezone", }, move |_| Box::new(Session::new(open_hour, open_minute, tz, period_minutes)), ) @@ -99,6 +100,7 @@ impl SessionFrankfurt { inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "trigger".into() }], output: vec![FieldSpec { name: "bars_since_open".into(), kind: ScalarKind::I64 }], params: vec![ParamSpec { name: "period_minutes".into(), kind: ScalarKind::I64 }], + doc: "bars elapsed since the Frankfurt session open (09:00 Europe/Berlin)", }, |p| Box::new(Session::new(9, 0, chrono_tz::Europe::Berlin, p[0].i64())), ) diff --git a/crates/aura-strategy/src/bias.rs b/crates/aura-strategy/src/bias.rs index b3c9d44..a062939 100644 --- a/crates/aura-strategy/src/bias.rs +++ b/crates/aura-strategy/src/bias.rs @@ -32,6 +32,7 @@ impl Bias { inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "signal".into() }], output: vec![FieldSpec { name: "bias".into(), kind: ScalarKind::F64 }], params: vec![ParamSpec { name: "scale".into(), kind: ScalarKind::F64 }], + doc: "clamps the strategy signal into the bias contract [-1,+1]", }, |p| Box::new(Bias::new(p[0].f64())), ) diff --git a/crates/aura-strategy/src/cost.rs b/crates/aura-strategy/src/cost.rs index e43d080..28c1bf7 100644 --- a/crates/aura-strategy/src/cost.rs +++ b/crates/aura-strategy/src/cost.rs @@ -224,7 +224,16 @@ pub fn cost_node_builder( ) -> PrimitiveBuilder { let mut inputs = geometry_input_ports(); inputs.extend(extra_inputs); - PrimitiveBuilder::new(name, NodeSchema { inputs, output: cost_output_fields(), params }, build) + PrimitiveBuilder::new( + name, + NodeSchema { + inputs, + output: cost_output_fields(), + params, + doc: "cost-model node: charges its cost in R from position geometry, at close or accrued per held cycle", + }, + build, + ) } #[cfg(test)] diff --git a/crates/aura-strategy/src/cost_sum.rs b/crates/aura-strategy/src/cost_sum.rs index cc90f8b..12fa5a4 100644 --- a/crates/aura-strategy/src/cost_sum.rs +++ b/crates/aura-strategy/src/cost_sum.rs @@ -58,6 +58,7 @@ impl CostSum { .map(|n| FieldSpec { name: (*n).into(), kind: ScalarKind::F64 }) .collect(), params: vec![], + doc: "sums cost-model contributions into one cost-in-R stream", }, move |_| Box::new(CostSum::new(n_costs)), ) diff --git a/crates/aura-strategy/src/longonly.rs b/crates/aura-strategy/src/longonly.rs index 3adcd5d..75e4b7e 100644 --- a/crates/aura-strategy/src/longonly.rs +++ b/crates/aura-strategy/src/longonly.rs @@ -31,6 +31,7 @@ impl LongOnly { inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "exposure".into() }], output: vec![FieldSpec { name: "exposure".into(), kind: ScalarKind::F64 }], params: vec![ParamSpec { name: "enabled".into(), kind: ScalarKind::Bool }], + doc: "when enabled, clamps negative exposure to flat (long-only); otherwise passes exposure through", }, |p| Box::new(LongOnly::new(p[0].bool())), ) diff --git a/crates/aura-strategy/src/sizer.rs b/crates/aura-strategy/src/sizer.rs index cbdef69..9471b73 100644 --- a/crates/aura-strategy/src/sizer.rs +++ b/crates/aura-strategy/src/sizer.rs @@ -36,6 +36,7 @@ impl Sizer { ], output: vec![FieldSpec { name: "size".into(), kind: ScalarKind::F64 }], params: vec![ParamSpec { name: "risk_budget".into(), kind: ScalarKind::F64 }], + doc: "size = risk_budget / stop_distance at the deploy edge; bias only gates firing, research runs flat-1R", }, |p| Box::new(Sizer::new(p[0].f64())), ) diff --git a/crates/aura-strategy/src/stop_rule.rs b/crates/aura-strategy/src/stop_rule.rs index 6c6c723..9793ee1 100644 --- a/crates/aura-strategy/src/stop_rule.rs +++ b/crates/aura-strategy/src/stop_rule.rs @@ -34,6 +34,7 @@ impl FixedStop { inputs: vec![PortSpec { kind: ScalarKind::F64, firing: Firing::Any, name: "price".into() }], output: vec![FieldSpec { name: "stop_distance".into(), kind: ScalarKind::F64 }], params: vec![ParamSpec { name: "distance".into(), kind: ScalarKind::F64 }], + doc: "derives the protective stop that defines the risk unit R", }, |p| Box::new(FixedStop::new(p[0].f64())), ) diff --git a/crates/aura-strategy/src/vol_tf_stop.rs b/crates/aura-strategy/src/vol_tf_stop.rs index ef98367..a72d6dc 100644 --- a/crates/aura-strategy/src/vol_tf_stop.rs +++ b/crates/aura-strategy/src/vol_tf_stop.rs @@ -72,6 +72,7 @@ impl VolTfStop { ParamSpec { name: "length".into(), kind: ScalarKind::I64 }, ParamSpec { name: "k".into(), kind: ScalarKind::F64 }, ], + doc: "volatility- and timeframe-scaled protective stop rule", }, |p| Box::new(VolTfStop::new(p[0].i64(), p[1].i64(), p[2].f64())), )