From b39fd633965071fcf9bd11f337d8a7e905cacc66 Mon Sep 17 00:00:00 2001 From: claude Date: Sun, 19 Jul 2026 20:28:20 +0200 Subject: [PATCH] refactor: split the aura-std roster into C28 layer crates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 4 of the Stratification milestone. aura-std held four C28 ladder layers in one roster; this cuts them into layer-aligned, aura-core-only node crates so the import direction is enforced by the crate graph: - aura-std — engine nodes only (arithmetic/logic/rolling + sinks) - aura-market — session, resample - aura-strategy — bias, stops, sizer, cost-model machinery - aura-backtest — sim_broker, position_management - aura-vocabulary — the relocated closed std_vocabulary roster Node modules move verbatim (byte-identical renames); consumers are rewired by import path only. A new structural test (aura-vocabulary/tests/c28_layering.rs) asserts each node crate's [dependencies] stay within its C28-permitted inner set, catching the acyclic-but-outward violation the compiler misses. Behaviour byte-identical: full workspace suite green (1448 tests), no golden edited, clippy -D warnings clean. C28 Status block updated. closes #288 --- Cargo.lock | 51 +++++++++++++++ Cargo.toml | 4 ++ crates/aura-backtest/Cargo.toml | 9 +++ crates/aura-backtest/src/lib.rs | 12 ++++ .../src/position_management.rs | 0 .../src/sim_broker.rs | 0 crates/aura-cli/Cargo.toml | 3 + crates/aura-cli/src/campaign_run.rs | 11 ++-- crates/aura-cli/src/graph_construct.rs | 4 +- crates/aura-cli/src/main.rs | 14 +++-- crates/aura-cli/src/project.rs | 2 +- crates/aura-cli/tests/cli_run.rs | 2 +- crates/aura-composites/Cargo.toml | 2 + crates/aura-composites/src/lib.rs | 9 +-- crates/aura-composites/tests/cost_graph.rs | 2 +- crates/aura-composites/tests/risk_executor.rs | 3 +- crates/aura-engine/Cargo.toml | 4 ++ crates/aura-engine/src/blueprint.rs | 16 +++-- crates/aura-engine/src/blueprint_serde.rs | 27 ++++---- crates/aura-engine/src/builder.rs | 4 +- crates/aura-engine/src/construction.rs | 15 ++--- crates/aura-engine/src/graph_model.rs | 3 +- crates/aura-engine/src/harness.rs | 4 +- crates/aura-engine/src/report.rs | 4 +- crates/aura-engine/src/test_fixtures.rs | 4 +- .../aura-engine/tests/blueprint_serde_e2e.rs | 8 ++- crates/aura-engine/tests/construction_e2e.rs | 8 ++- crates/aura-engine/tests/ger40_breakout.rs | 4 +- crates/aura-engine/tests/list_sweep_e2e.rs | 4 +- .../tests/ohlc_from_blueprint_data.rs | 3 +- crates/aura-engine/tests/r_sma_e2e.rs | 12 ++-- crates/aura-engine/tests/random_sweep_e2e.rs | 4 +- .../aura-engine/tests/reopen_rebuild_e2e.rs | 3 +- .../tests/rsi_from_blueprint_data.rs | 5 +- .../tests/streaming_reduction_equivalence.rs | 3 +- .../tests/streaming_reduction_memory.rs | 3 +- crates/aura-engine/tests/when_e2e.rs | 3 +- crates/aura-ingest/Cargo.toml | 3 + .../examples/shared/breakout_real.rs | 4 +- crates/aura-ingest/tests/real_bars.rs | 4 +- crates/aura-ingest/tests/streaming_seam.rs | 4 +- crates/aura-market/Cargo.toml | 11 ++++ crates/aura-market/src/lib.rs | 8 +++ .../{aura-std => aura-market}/src/resample.rs | 0 .../{aura-std => aura-market}/src/session.rs | 0 crates/aura-registry/Cargo.toml | 2 + crates/aura-registry/src/lib.rs | 34 +++++----- crates/aura-std/Cargo.toml | 4 ++ crates/aura-std/src/lib.rs | 36 ----------- crates/aura-std/src/sma.rs | 8 ++- crates/aura-strategy/Cargo.toml | 9 +++ .../{aura-std => aura-strategy}/src/bias.rs | 0 .../src/carry_cost.rs | 0 .../src/constant_cost.rs | 0 .../{aura-std => aura-strategy}/src/cost.rs | 2 +- .../src/cost_sum.rs | 0 crates/aura-strategy/src/lib.rs | 28 +++++++++ .../src/longonly.rs | 0 .../{aura-std => aura-strategy}/src/sizer.rs | 0 .../src/stop_rule.rs | 0 .../src/vol_slippage_cost.rs | 0 .../src/vol_tf_stop.rs | 0 crates/aura-vocabulary/Cargo.toml | 16 +++++ .../src/lib.rs} | 16 ++--- crates/aura-vocabulary/tests/c28_layering.rs | 62 +++++++++++++++++++ docs/design/INDEX.md | 30 +++++---- 66 files changed, 398 insertions(+), 152 deletions(-) create mode 100644 crates/aura-backtest/Cargo.toml create mode 100644 crates/aura-backtest/src/lib.rs rename crates/{aura-std => aura-backtest}/src/position_management.rs (100%) rename crates/{aura-std => aura-backtest}/src/sim_broker.rs (100%) create mode 100644 crates/aura-market/Cargo.toml create mode 100644 crates/aura-market/src/lib.rs rename crates/{aura-std => aura-market}/src/resample.rs (100%) rename crates/{aura-std => aura-market}/src/session.rs (100%) create mode 100644 crates/aura-strategy/Cargo.toml rename crates/{aura-std => aura-strategy}/src/bias.rs (100%) rename crates/{aura-std => aura-strategy}/src/carry_cost.rs (100%) rename crates/{aura-std => aura-strategy}/src/constant_cost.rs (100%) rename crates/{aura-std => aura-strategy}/src/cost.rs (99%) rename crates/{aura-std => aura-strategy}/src/cost_sum.rs (100%) create mode 100644 crates/aura-strategy/src/lib.rs rename crates/{aura-std => aura-strategy}/src/longonly.rs (100%) rename crates/{aura-std => aura-strategy}/src/sizer.rs (100%) rename crates/{aura-std => aura-strategy}/src/stop_rule.rs (100%) rename crates/{aura-std => aura-strategy}/src/vol_slippage_cost.rs (100%) rename crates/{aura-std => aura-strategy}/src/vol_tf_stop.rs (100%) create mode 100644 crates/aura-vocabulary/Cargo.toml rename crates/{aura-std/src/vocabulary.rs => aura-vocabulary/src/lib.rs} (92%) create mode 100644 crates/aura-vocabulary/tests/c28_layering.rs diff --git a/Cargo.lock b/Cargo.lock index eeb7a7a..d6012e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,13 @@ dependencies = [ "serde_json", ] +[[package]] +name = "aura-backtest" +version = "0.1.0" +dependencies = [ + "aura-core", +] + [[package]] name = "aura-bench" version = "0.1.0" @@ -139,6 +146,7 @@ dependencies = [ name = "aura-cli" version = "0.1.0" dependencies = [ + "aura-backtest", "aura-campaign", "aura-composites", "aura-core", @@ -147,6 +155,8 @@ dependencies = [ "aura-registry", "aura-research", "aura-std", + "aura-strategy", + "aura-vocabulary", "clap", "data-server", "libc", @@ -162,9 +172,11 @@ dependencies = [ name = "aura-composites" version = "0.1.0" dependencies = [ + "aura-backtest", "aura-core", "aura-engine", "aura-std", + "aura-strategy", "serde_json", ] @@ -181,8 +193,12 @@ name = "aura-engine" version = "0.1.0" dependencies = [ "aura-analysis", + "aura-backtest", "aura-core", + "aura-market", "aura-std", + "aura-strategy", + "aura-vocabulary", "chrono", "chrono-tz", "rayon", @@ -194,15 +210,27 @@ dependencies = [ name = "aura-ingest" version = "0.1.0" dependencies = [ + "aura-backtest", "aura-core", "aura-engine", + "aura-market", "aura-std", + "aura-strategy", "chrono", "chrono-tz", "data-server", "zip", ] +[[package]] +name = "aura-market" +version = "0.1.0" +dependencies = [ + "aura-core", + "chrono", + "chrono-tz", +] + [[package]] name = "aura-registry" version = "0.1.0" @@ -211,6 +239,8 @@ dependencies = [ "aura-engine", "aura-research", "aura-std", + "aura-strategy", + "aura-vocabulary", "serde", "serde_json", ] @@ -229,11 +259,32 @@ dependencies = [ name = "aura-std" version = "0.1.0" dependencies = [ + "aura-backtest", "aura-core", + "aura-strategy", "chrono", "chrono-tz", ] +[[package]] +name = "aura-strategy" +version = "0.1.0" +dependencies = [ + "aura-core", +] + +[[package]] +name = "aura-vocabulary" +version = "0.1.0" +dependencies = [ + "aura-backtest", + "aura-core", + "aura-market", + "aura-std", + "aura-strategy", + "toml", +] + [[package]] name = "autocfg" version = "1.5.1" diff --git a/Cargo.toml b/Cargo.toml index 99302f7..624b42c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,10 @@ resolver = "3" members = [ "crates/aura-core", "crates/aura-std", + "crates/aura-vocabulary", + "crates/aura-market", + "crates/aura-strategy", + "crates/aura-backtest", "crates/aura-engine", "crates/aura-analysis", "crates/aura-composites", diff --git a/crates/aura-backtest/Cargo.toml b/crates/aura-backtest/Cargo.toml new file mode 100644 index 0000000..fbd2f03 --- /dev/null +++ b/crates/aura-backtest/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "aura-backtest" +edition.workspace = true +version.workspace = true +license.workspace = true +publish.workspace = true + +[dependencies] +aura-core = { path = "../aura-core" } diff --git a/crates/aura-backtest/src/lib.rs b/crates/aura-backtest/src/lib.rs new file mode 100644 index 0000000..9845a90 --- /dev/null +++ b/crates/aura-backtest/src/lib.rs @@ -0,0 +1,12 @@ +//! `aura-backtest` — the backtest-execution node layer (C28): simulated execution +//! without money (the `SimBroker` pip yardstick, position management), measured in +//! R. Depends only on `aura-core`. + +mod position_management; +mod sim_broker; + +pub use position_management::{ + ExitReason, FIELD_NAMES as PM_FIELD_NAMES, PositionManagement, + RECORD_KINDS as PM_RECORD_KINDS, WIDTH as PM_WIDTH, +}; +pub use sim_broker::SimBroker; diff --git a/crates/aura-std/src/position_management.rs b/crates/aura-backtest/src/position_management.rs similarity index 100% rename from crates/aura-std/src/position_management.rs rename to crates/aura-backtest/src/position_management.rs diff --git a/crates/aura-std/src/sim_broker.rs b/crates/aura-backtest/src/sim_broker.rs similarity index 100% rename from crates/aura-std/src/sim_broker.rs rename to crates/aura-backtest/src/sim_broker.rs diff --git a/crates/aura-cli/Cargo.toml b/crates/aura-cli/Cargo.toml index e988e30..d9a550c 100644 --- a/crates/aura-cli/Cargo.toml +++ b/crates/aura-cli/Cargo.toml @@ -22,6 +22,9 @@ aura-research = { path = "../aura-research" } # and renders its outcome (#198). aura-campaign = { path = "../aura-campaign" } aura-std = { path = "../aura-std" } +aura-strategy = { path = "../aura-strategy" } +aura-backtest = { path = "../aura-backtest" } +aura-vocabulary = { path = "../aura-vocabulary" } aura-ingest = { path = "../aura-ingest" } # data-server: the local M1 archive `aura run --real` streams from. Mirrors the # git line in crates/aura-ingest/Cargo.toml verbatim (same source of truth). diff --git a/crates/aura-cli/src/campaign_run.rs b/crates/aura-cli/src/campaign_run.rs index 8e09880..394d748 100644 --- a/crates/aura-cli/src/campaign_run.rs +++ b/crates/aura-cli/src/campaign_run.rs @@ -31,7 +31,7 @@ use aura_research::{ campaign_to_json, content_id_of, parse_campaign, parse_process, validate_campaign, validate_process, CampaignDoc, CostSpec, DocRef, }; -use aura_std::{CarryCost, ConstantCost, VolSlippageCost}; +use aura_strategy::{CarryCost, ConstantCost, VolSlippageCost}; use crate::project::Env; use crate::research_docs::{ @@ -1358,7 +1358,8 @@ mod tests { /// (bind_axes surfaces THAT case as its own named fault once the /// reopened space is built downstream). fn raw_bound_overrides_of_selects_axes_naming_a_bound_param() { - use aura_std::{Bias, Sma}; + use aura_strategy::Bias; + use aura_std::Sma; let raw_signal = Composite::new( "fixture", vec![ @@ -1555,9 +1556,9 @@ mod tests { /// variant reconstruction with no compiler error; this pin makes it loud. fn every_cost_builder_declares_exactly_one_distinct_knob() { let knobs: Vec = [ - aura_std::ConstantCost::builder(), - aura_std::VolSlippageCost::builder(), - aura_std::CarryCost::builder(), + aura_strategy::ConstantCost::builder(), + aura_strategy::VolSlippageCost::builder(), + aura_strategy::CarryCost::builder(), ] .iter() .map(|b| { diff --git a/crates/aura-cli/src/graph_construct.rs b/crates/aura-cli/src/graph_construct.rs index c72adbb..c1991cb 100644 --- a/crates/aura-cli/src/graph_construct.rs +++ b/crates/aura-cli/src/graph_construct.rs @@ -2,7 +2,7 @@ //! JSON op-list document deserializes into the `OpDoc` DTO (so the engine `Op` //! stays serde-free), which maps 1:1 into `aura_engine::Op`. The `aura graph //! build` / `aura graph introspect` subcommands here drive these ops through the -//! injected `aura_std::std_vocabulary`. +//! injected `aura_vocabulary::std_vocabulary`. use std::collections::BTreeMap; use std::path::Path; @@ -16,7 +16,7 @@ use serde::Deserialize; // `std_vocabulary` is now only reached through `crate::project::Env::resolve` in // production code; tests still exercise it directly. #[cfg(test)] -use aura_std::std_vocabulary; +use aura_vocabulary::std_vocabulary; /// The wire DTO for one construction op — the document's by-identifier shape, /// internally tagged by `"op"`, mapped into the serde-free engine `Op`. Bind diff --git a/crates/aura-cli/src/main.rs b/crates/aura-cli/src/main.rs index 670c64b..de3c06d 100644 --- a/crates/aura-cli/src/main.rs +++ b/crates/aura-cli/src/main.rs @@ -30,16 +30,16 @@ use aura_registry::{ FamilyMember, Generalization, NameKind, PlateauMode, Registry, RunTraces, DEFLATION_BLOCK_LEN, DEFLATION_N_RESAMPLES, }; +use aura_backtest::{SimBroker, PM_FIELD_NAMES, PM_RECORD_KINDS}; use aura_std::{ - cost_port, GatedRecorder, LinComb, Recorder, RollingMax, RollingMin, - SeriesReducer, SimBroker, Sub, GEOMETRY_WIDTH, PM_FIELD_NAMES, - PM_RECORD_KINDS, + GatedRecorder, LinComb, Recorder, RollingMax, RollingMin, SeriesReducer, Sub, }; +use aura_strategy::{cost_port, GEOMETRY_WIDTH}; // `std_vocabulary` is now only reached through `project::Env::resolve` in production // code; the test module still builds reference blueprints against it directly, so // the import is test-only. #[cfg(test)] -use aura_std::std_vocabulary; +use aura_vocabulary::std_vocabulary; // `Delay` is now only used by the test-only `r_breakout_signal` carve (#159 cut 2's // fused-builder retirement dropped the production caller); the import is test-only. #[cfg(test)] @@ -61,9 +61,11 @@ use aura_engine::ColumnarTrace; // `Bias`/`Ema`/`Sma` are only reached from the test module; the imports are // test-only, mirroring `Delay`/`Scale` above. #[cfg(test)] -use aura_std::{Bias, Ema, Sma}; +use aura_strategy::Bias; #[cfg(test)] -use aura_std::{ConstantCost, VolSlippageCost}; +use aura_std::{Ema, Sma}; +#[cfg(test)] +use aura_strategy::{ConstantCost, VolSlippageCost}; use std::sync::mpsc; use std::sync::LazyLock; use std::collections::{BTreeMap, BTreeSet, HashSet}; diff --git a/crates/aura-cli/src/project.rs b/crates/aura-cli/src/project.rs index 182aa0f..5b952a8 100644 --- a/crates/aura-cli/src/project.rs +++ b/crates/aura-cli/src/project.rs @@ -14,7 +14,7 @@ use aura_core::project::{ }; use aura_engine::ProjectProvenance; use aura_registry::{Registry, TraceStore}; -use aura_std::{std_vocabulary, std_vocabulary_types}; +use aura_vocabulary::{std_vocabulary, std_vocabulary_types}; use sha2::{Digest, Sha256}; use std::fmt; use std::path::{Path, PathBuf}; diff --git a/crates/aura-cli/tests/cli_run.rs b/crates/aura-cli/tests/cli_run.rs index f8a1c63..b50b099 100644 --- a/crates/aura-cli/tests/cli_run.rs +++ b/crates/aura-cli/tests/cli_run.rs @@ -4336,7 +4336,7 @@ fn sweep_and_walkforward_refuse_trace_with_a_forward_pointer() { #[test] fn aura_sweep_persists_the_canonical_blueprint_keyed_by_topology_hash() { use aura_engine::{blueprint_from_json, blueprint_to_json}; - use aura_std::std_vocabulary; + use aura_vocabulary::std_vocabulary; use sha2::{Digest, Sha256}; let cwd = temp_cwd("blueprint-sweep-store"); diff --git a/crates/aura-composites/Cargo.toml b/crates/aura-composites/Cargo.toml index 4b9d90b..0d105b0 100644 --- a/crates/aura-composites/Cargo.toml +++ b/crates/aura-composites/Cargo.toml @@ -14,6 +14,8 @@ publish.workspace = true aura-core = { path = "../aura-core" } aura-engine = { path = "../aura-engine" } aura-std = { path = "../aura-std" } +aura-strategy = { path = "../aura-strategy" } +aura-backtest = { path = "../aura-backtest" } [dev-dependencies] # serde_json: the risk_executor fixture round-trips a folded RunMetrics through diff --git a/crates/aura-composites/src/lib.rs b/crates/aura-composites/src/lib.rs index 1e9e628..a9f95b1 100644 --- a/crates/aura-composites/src/lib.rs +++ b/crates/aura-composites/src/lib.rs @@ -17,10 +17,11 @@ //! what C19/C23 DCE deletes), so it appears nowhere here. use aura_core::{PrimitiveBuilder, Scalar}; use aura_engine::{Composite, GraphBuilder, NodeHandle}; -use aura_std::{ - cost_port, intern_port, CostSum, Delay, Ema, FixedStop, LinComb, Mul, - PositionManagement, Sizer, Sqrt, Sub, VolTfStop, COST_FIELD_NAMES, GEOMETRY_WIDTH, - PM_FIELD_NAMES, +use aura_backtest::{PositionManagement, PM_FIELD_NAMES}; +use aura_std::{Delay, Ema, LinComb, Mul, Sqrt, Sub}; +use aura_strategy::{ + cost_port, intern_port, CostSum, FixedStop, Sizer, VolTfStop, COST_FIELD_NAMES, + GEOMETRY_WIDTH, }; /// The volatility stop as a composition of primitives: diff --git a/crates/aura-composites/tests/cost_graph.rs b/crates/aura-composites/tests/cost_graph.rs index 5a4feea..28ade4f 100644 --- a/crates/aura-composites/tests/cost_graph.rs +++ b/crates/aura-composites/tests/cost_graph.rs @@ -5,7 +5,7 @@ use aura_composites::cost_graph; use aura_core::Scalar; -use aura_std::{ConstantCost, VolSlippageCost}; +use aura_strategy::{ConstantCost, VolSlippageCost}; /// Two heterogeneous cost nodes: ConstantCost (no extras, index 0) and /// VolSlippageCost (one extra `volatility`, index 1). The composite exposes the 4 diff --git a/crates/aura-composites/tests/risk_executor.rs b/crates/aura-composites/tests/risk_executor.rs index f5647a2..41bc5ad 100644 --- a/crates/aura-composites/tests/risk_executor.rs +++ b/crates/aura-composites/tests/risk_executor.rs @@ -10,7 +10,8 @@ use aura_core::{ }; use aura_composites::{risk_executor, StopRule}; use aura_engine::{summarize_r, GraphBuilder, RunMetrics, VecSource}; -use aura_std::{Recorder, PM_FIELD_NAMES, PM_RECORD_KINDS}; +use aura_backtest::{PM_FIELD_NAMES, PM_RECORD_KINDS}; +use aura_std::Recorder; use std::sync::mpsc::channel; // The dense-record columns this fixture reads, named in lockstep with the sibling diff --git a/crates/aura-engine/Cargo.toml b/crates/aura-engine/Cargo.toml index 02674ae..9d1f967 100644 --- a/crates/aura-engine/Cargo.toml +++ b/crates/aura-engine/Cargo.toml @@ -36,6 +36,10 @@ rayon = "1" # positionally, by index), so aura-std stays out of [dependencies] and the engine is # `-> aura-core` only. The node-naming composite-builders live in `aura-composites`. aura-std = { path = "../aura-std" } +aura-market = { path = "../aura-market" } +aura-strategy = { path = "../aura-strategy" } +aura-backtest = { path = "../aura-backtest" } +aura-vocabulary = { path = "../aura-vocabulary" } # chrono / chrono-tz build the Berlin-local-wall-clock epoch-ns timestamps the # GER40 session-breakout E2E fixture (tests/ger40_breakout.rs) feeds the engine, # exactly as `Session`'s own unit test does. Pinned to aura-std's versions (the diff --git a/crates/aura-engine/src/blueprint.rs b/crates/aura-engine/src/blueprint.rs index a17c99d..a85de8e 100644 --- a/crates/aura-engine/src/blueprint.rs +++ b/crates/aura-engine/src/blueprint.rs @@ -1384,7 +1384,9 @@ mod tests { use crate::test_fixtures::{composite_sma_cross_harness, synthetic_prices}; use crate::{f64_field, summarize, ParamRange, RandomSpace, RunManifest, VecSource}; use aura_core::{Cell, Ctx, FieldSpec, Firing, NodeSchema, Timestamp}; - use aura_std::{Bias, Ema, LinComb, Recorder, SimBroker, Sma, Sub}; + use aura_backtest::SimBroker; + use aura_std::{Ema, LinComb, Recorder, Sma, Sub}; + use aura_strategy::Bias; use std::sync::mpsc; /// One knob fanning into two sibling open params passes the gate; the @@ -3122,7 +3124,8 @@ mod tests { #[test] fn param_space_reflects_only_open_knobs() { - use aura_std::{Bias, Sma}; + use aura_strategy::Bias; + use aura_std::Sma; // "sma2_entry": Sma "bias" with length bound to 2 (a structural constant) // plus Bias "exp" whose `scale` stays open. The bound knob must be // absent from param_space; only the open one remains. @@ -3148,7 +3151,8 @@ mod tests { /// order — the bound value becomes a default an axis may override. #[test] fn reopen_returns_a_bound_knob_to_param_space() { - use aura_std::{Bias, Sma}; + use aura_strategy::Bias; + use aura_std::Sma; let strat = Composite::new( "sma2_entry", vec![ @@ -3169,7 +3173,8 @@ mod tests { /// error, not a silent no-op — open axes pass through without reopen. #[test] fn reopen_unknown_or_open_path_errors() { - use aura_std::{Bias, Sma}; + use aura_strategy::Bias; + use aura_std::Sma; let strat = Composite::new( "sma2_entry", vec![ @@ -3190,7 +3195,8 @@ mod tests { /// carries the bound value (the default the CLI renders in --list-axes). #[test] fn bound_param_space_is_path_qualified_with_values() { - use aura_std::{Bias, Sma}; + use aura_strategy::Bias; + use aura_std::Sma; let strat = Composite::new( "sma2_entry", vec![ diff --git a/crates/aura-engine/src/blueprint_serde.rs b/crates/aura-engine/src/blueprint_serde.rs index 7eb3d59..329b65a 100644 --- a/crates/aura-engine/src/blueprint_serde.rs +++ b/crates/aura-engine/src/blueprint_serde.rs @@ -244,7 +244,7 @@ fn reconstruct( } /// Load a blueprint from canonical JSON, resolving each primitive's type identity -/// through the injected `resolve` (e.g. `aura_std::std_vocabulary`). The version +/// through the injected `resolve` (e.g. `aura_vocabulary::std_vocabulary`). The version /// envelope is checked before the payload is reconstructed. pub fn blueprint_from_json( data: &str, @@ -267,7 +267,8 @@ mod tests { use crate::harness::{Edge, Target}; use crate::VecSource; // crate-root re-export (blueprint.rs tests import it the same way, e.g. :923) use aura_core::{Scalar, ScalarKind, Timestamp}; - use aura_std::{Bias, Recorder, Sma, Sub}; + use aura_std::{Recorder, Sma, Sub}; + use aura_strategy::Bias; use std::sync::mpsc; // Open param point for the sink-free signal (fast.length is bound): [slow.length, bias.scale]. @@ -303,7 +304,7 @@ mod tests { fn serialized_blueprint_runs_bit_identical_to_rust_built() { let rust_built = crate::test_fixtures::sink_free_sma_cross_signal(); let json = blueprint_to_json(&rust_built).expect("serializes"); - let loaded = blueprint_from_json(&json, &|t| aura_std::std_vocabulary(t)).expect("loads"); + let loaded = blueprint_from_json(&json, &|t| aura_vocabulary::std_vocabulary(t)).expect("loads"); let trace_rust = run_recording(rust_built); let trace_loaded = run_recording(loaded); @@ -316,7 +317,7 @@ mod tests { fn serializer_and_loader_are_inverse() { let original = crate::test_fixtures::sink_free_sma_cross_signal(); let json = blueprint_to_json(&original).expect("serializes"); - let loaded = blueprint_from_json(&json, &|t| aura_std::std_vocabulary(t)).expect("loads"); + let loaded = blueprint_from_json(&json, &|t| aura_vocabulary::std_vocabulary(t)).expect("loads"); // serialize -> load -> serialize is byte-stable (canonical round-trip identity) assert_eq!(json, blueprint_to_json(&loaded).expect("re-serializes")); } @@ -339,7 +340,7 @@ mod tests { vec![OutField { node: 0, field: 0, name: "bias".into() }], ); let json = blueprint_to_json(&outer).expect("serializes"); - let loaded = blueprint_from_json(&json, &|t| aura_std::std_vocabulary(t)).expect("loads"); + let loaded = blueprint_from_json(&json, &|t| aura_vocabulary::std_vocabulary(t)).expect("loads"); assert_eq!(json, blueprint_to_json(&loaded).expect("re-serializes")); // the nested composite survived as a composite, not flattened assert!(json.contains(r#"{"composite":{"name":"sma_cross""#), "nested composite preserved"); @@ -370,7 +371,7 @@ mod tests { assert_ne!(plain_json, doced_json, "the doc is canonical-byte-bearing"); assert!(doced_json.contains("why this graph"), "doc serialized: {doced_json}"); assert!(!plain_json.contains("\"doc\""), "absent doc emits no key: {plain_json}"); - let loaded = blueprint_from_json(&doced_json, &|t| aura_std::std_vocabulary(t)).expect("loads"); + let loaded = blueprint_from_json(&doced_json, &|t| aura_vocabulary::std_vocabulary(t)).expect("loads"); assert_eq!(loaded.doc(), Some("why this graph: the spread detects trend turns")); assert_eq!(doced_json, blueprint_to_json(&loaded).expect("re-serializes"), "round-trip byte-stable"); assert_eq!( @@ -395,7 +396,7 @@ mod tests { let tapped_json = blueprint_to_json(&tapped).expect("serializes"); assert_ne!(plain_json, tapped_json, "taps are canonical-byte-bearing"); assert!(!plain_json.contains("\"taps\""), "absent taps emit no key: {plain_json}"); - let loaded = blueprint_from_json(&tapped_json, &|t| aura_std::std_vocabulary(t)).expect("loads"); + let loaded = blueprint_from_json(&tapped_json, &|t| aura_vocabulary::std_vocabulary(t)).expect("loads"); assert_eq!(loaded.taps(), tapped.taps()); assert_eq!(tapped_json, blueprint_to_json(&loaded).expect("re-serializes"), "round-trip byte-stable"); } @@ -431,14 +432,14 @@ mod tests { let json = r#"{"format_version":1,"blueprint":{"name":"x","nodes":[{"primitive":{"type":"NoSuchNode"}}]}}"#; // `.err().unwrap()` (not `.unwrap_err()`): the Ok type `Composite` holds a // build closure and is not `Debug`, which `unwrap_err`'s bound would require. - let err = blueprint_from_json(json, &|t| aura_std::std_vocabulary(t)).err().unwrap(); + let err = blueprint_from_json(json, &|t| aura_vocabulary::std_vocabulary(t)).err().unwrap(); assert!(matches!(err, LoadError::UnknownNodeType(t) if t == "NoSuchNode")); } #[test] fn unsupported_version_fails_named() { let json = r#"{"format_version":2,"blueprint":{"name":"x","nodes":[]}}"#; - let err = blueprint_from_json(json, &|t| aura_std::std_vocabulary(t)).err().unwrap(); + let err = blueprint_from_json(json, &|t| aura_vocabulary::std_vocabulary(t)).err().unwrap(); assert!(matches!(err, LoadError::UnsupportedVersion { found: 2, supported: 1 })); } @@ -466,7 +467,7 @@ mod tests { assert_ne!(with_unknown, canonical, "probe must actually inject unknown keys"); // tolerated, not refused - let loaded = blueprint_from_json(&with_unknown, &|t| aura_std::std_vocabulary(t)) + let loaded = blueprint_from_json(&with_unknown, &|t| aura_vocabulary::std_vocabulary(t)) .expect("an unknown optional field is tolerated, not refused"); // the unknown keys did not leak into the graph: re-serialization equals the @@ -474,7 +475,7 @@ mod tests { assert_eq!(blueprint_to_json(&loaded).expect("re-serializes"), canonical); // and the loaded graph runs bit-identically to the plain canonical one (C1). - let plain = blueprint_from_json(&canonical, &|t| aura_std::std_vocabulary(t)).expect("loads"); + let plain = blueprint_from_json(&canonical, &|t| aura_vocabulary::std_vocabulary(t)).expect("loads"); assert_eq!( run_recording(loaded), run_recording(plain), @@ -655,9 +656,9 @@ mod tests { } // The resolver used by the gang-serde tests below (mirrors the inline - // `&|t| aura_std::std_vocabulary(t)` closure the rest of this module uses). + // `&|t| aura_vocabulary::std_vocabulary(t)` closure the rest of this module uses). fn fixture_resolver() -> impl Fn(&str) -> Option { - |t: &str| aura_std::std_vocabulary(t) + |t: &str| aura_vocabulary::std_vocabulary(t) } // Shared topology: two open SMAs feeding a `Sub`. `ganged_fixture_named` diff --git a/crates/aura-engine/src/builder.rs b/crates/aura-engine/src/builder.rs index 4474a9b..2d1a285 100644 --- a/crates/aura-engine/src/builder.rs +++ b/crates/aura-engine/src/builder.rs @@ -344,7 +344,9 @@ mod tests { use crate::test_fixtures::sma_cross as hand_sma_cross; use crate::{Composite, OutField, Role, Target}; use aura_core::{Firing, ScalarKind}; - use aura_std::{Bias, Recorder, SimBroker, Sma, Sub}; + use aura_backtest::SimBroker; + use aura_std::{Recorder, Sma, Sub}; + use aura_strategy::Bias; use std::sync::mpsc; /// The `sma_cross` sub-composite authored through the builder. diff --git a/crates/aura-engine/src/construction.rs b/crates/aura-engine/src/construction.rs index ed48c31..dacc0c4 100644 --- a/crates/aura-engine/src/construction.rs +++ b/crates/aura-engine/src/construction.rs @@ -472,7 +472,7 @@ pub fn replay( mod tests { use super::{GraphSession, Op, OpError}; use aura_core::{BindOpError, Scalar, ScalarKind}; - use aura_std::std_vocabulary; + use aura_vocabulary::std_vocabulary; fn session(name: &str) -> GraphSession<'static> { GraphSession::new(name, &std_vocabulary) @@ -736,7 +736,7 @@ mod tests { Op::Tap { from: "fast.value".into(), as_name: "fast_ma".into() }, Op::Expose { from: "sub.value".into(), as_name: "bias".into() }, ]; - let flat = super::replay("g", ops, &aura_std::std_vocabulary) + let flat = super::replay("g", ops, &aura_vocabulary::std_vocabulary) .expect("replays") .compile_with_params(&[Scalar::i64(2), Scalar::i64(4)]) .expect("compiles"); @@ -949,7 +949,7 @@ mod tests { let finalize = ops.len(); // `.err()` not `.unwrap_err()`: the Ok arm `Composite` holds build closures // and is not `Debug`. - let (idx, _err) = super::replay("g", ops, &aura_std::std_vocabulary) + let (idx, _err) = super::replay("g", ops, &aura_vocabulary::std_vocabulary) .err() .expect("a cyclic op-list must be rejected (DAG invariant 5 / C9)"); // An eager realisation attributes the fault to the closing connect op; a @@ -976,7 +976,7 @@ mod tests { Op::Expose { from: "s.value".into(), as_name: "out".into() }, ]; assert!( - super::replay("g", ops, &aura_std::std_vocabulary).is_err(), + super::replay("g", ops, &aura_vocabulary::std_vocabulary).is_err(), "a self-loop op-list must be rejected (DAG invariant 5 / C9)" ); } @@ -990,7 +990,7 @@ mod tests { ]; // `.err().unwrap()` rather than `.unwrap_err()`: the Ok arm `Composite` is // not `Debug` (it holds build closures), which `unwrap_err` would require. - let err = super::replay("g", ops, &aura_std::std_vocabulary).err().unwrap(); + let err = super::replay("g", ops, &aura_vocabulary::std_vocabulary).err().unwrap(); assert_eq!(err, (1, OpError::UnknownNodeType("Nope".into()))); } @@ -1004,7 +1004,8 @@ mod tests { fn replay_built_signal_compiles_identically_to_graphbuilder() { use crate::GraphBuilder; use aura_core::Scalar; - use aura_std::{Bias, Sma, Sub}; + use aura_std::{Sma, Sub}; + use aura_strategy::Bias; // param space of the flat root: fast.length(i64), slow.length(i64), // bias.scale(f64) — same vector applied to both sides, so it cancels. @@ -1023,7 +1024,7 @@ mod tests { Op::Connect { from: "sub.value".into(), to: "bias.signal".into() }, Op::Expose { from: "bias.bias".into(), as_name: "bias".into() }, ]; - let replay_flat = super::replay("root", ops, &aura_std::std_vocabulary) + let replay_flat = super::replay("root", ops, &aura_vocabulary::std_vocabulary) .expect("replay resolves") .compile_with_params(¶ms) .expect("replay compiles"); diff --git a/crates/aura-engine/src/graph_model.rs b/crates/aura-engine/src/graph_model.rs index 1c193a5..d9da496 100644 --- a/crates/aura-engine/src/graph_model.rs +++ b/crates/aura-engine/src/graph_model.rs @@ -321,7 +321,8 @@ mod tests { use aura_core::{ Cell, FieldSpec, Node, NodeSchema, PortSpec, PrimitiveBuilder, Scalar, }; - use aura_std::{Bias, Recorder, Sma, Sub}; + use aura_std::{Recorder, Sma, Sub}; + use aura_strategy::Bias; use std::sync::mpsc; /// A bare node whose only purpose is to back a `PrimitiveBuilder` in a test. diff --git a/crates/aura-engine/src/harness.rs b/crates/aura-engine/src/harness.rs index 7f4dd3e..ebc36ed 100644 --- a/crates/aura-engine/src/harness.rs +++ b/crates/aura-engine/src/harness.rs @@ -676,7 +676,9 @@ mod tests { // PortSpec / NodeSchema name the fixtures' declared signatures, brought in here // (production code reads them via the carried signatures, never naming the types). use aura_core::{FieldSpec, NodeSchema, PortSpec}; - use aura_std::{Bias, Recorder, Sma, SimBroker, Sub, When}; + use aura_backtest::SimBroker; + use aura_std::{Recorder, Sma, Sub, When}; + use aura_strategy::Bias; use std::sync::mpsc; /// Build an f64 source stream from (timestamp, value) points. diff --git a/crates/aura-engine/src/report.rs b/crates/aura-engine/src/report.rs index 0504c42..58677bd 100644 --- a/crates/aura-engine/src/report.rs +++ b/crates/aura-engine/src/report.rs @@ -312,7 +312,9 @@ mod tests { use super::*; use crate::{Edge, FlatGraph, Harness, SourceSpec, Target, VecSource}; use aura_core::{Firing, NodeSchema, PortSpec, ScalarKind}; - use aura_std::{Bias, Recorder, SimBroker, Sma, Sub}; + use aura_backtest::SimBroker; + use aura_std::{Recorder, Sma, Sub}; + use aura_strategy::Bias; use std::sync::mpsc; #[test] diff --git a/crates/aura-engine/src/test_fixtures.rs b/crates/aura-engine/src/test_fixtures.rs index ce63926..5b0a7d1 100644 --- a/crates/aura-engine/src/test_fixtures.rs +++ b/crates/aura-engine/src/test_fixtures.rs @@ -6,7 +6,9 @@ use crate::{BlueprintNode, Composite, Edge, OutField, Role, Target}; use aura_core::{Firing, Scalar, ScalarKind, Timestamp}; -use aura_std::{Bias, Recorder, SimBroker, Sma, Sub}; +use aura_backtest::SimBroker; +use aura_std::{Recorder, Sma, Sub}; +use aura_strategy::Bias; use std::sync::mpsc; /// Seven synthetic F64 ticks driving the harness; deterministic input fixture. diff --git a/crates/aura-engine/tests/blueprint_serde_e2e.rs b/crates/aura-engine/tests/blueprint_serde_e2e.rs index aebc759..fd6309a 100644 --- a/crates/aura-engine/tests/blueprint_serde_e2e.rs +++ b/crates/aura-engine/tests/blueprint_serde_e2e.rs @@ -1,7 +1,7 @@ //! End-to-end coverage for blueprint serialization (C24, cycle 0087): a //! param-generic `Composite` is projected to canonical, versioned JSON //! (`blueprint_to_json`) and reconstructed from it (`blueprint_from_json`) through -//! an **injected** node-vocabulary resolver (`aura_std::std_vocabulary`). +//! an **injected** node-vocabulary resolver (`aura_vocabulary::std_vocabulary`). //! //! The in-module tests in `blueprint_serde.rs` reach into crate internals //! (`crate::test_fixtures::sink_free_sma_cross_signal`, the crate-private @@ -19,7 +19,9 @@ use aura_engine::{ blueprint_from_json, blueprint_identity_json, blueprint_to_json, BlueprintNode, Composite, Edge, LoadError, OutField, Role, Target, VecSource, BLUEPRINT_FORMAT_VERSION, }; -use aura_std::{std_vocabulary, Bias, Recorder, Sma, Sub}; +use aura_std::{Recorder, Sma, Sub}; +use aura_strategy::Bias; +use aura_vocabulary::std_vocabulary; /// Seven synthetic F64 ticks (mirrors the crate-private `synthetic_prices`): /// short enough that the fast (2) and slow (4) SMA windows warm up within the @@ -102,7 +104,7 @@ fn run_recording(signal: Composite) -> Vec<(Timestamp, Vec)> { /// Property (C24 acceptance, through the public seam): a blueprint authored via the /// exported `Composite` builder, serialized to JSON, then loaded back through -/// `blueprint_from_json` + the injected `aura_std::std_vocabulary` and run, records +/// `blueprint_from_json` + the injected `aura_vocabulary::std_vocabulary` and run, records /// a `bias` trace **byte-identical** to the Rust-built twin's run — proven entirely /// through `aura_engine`/`aura_std` public exports (the World/cdylib seam C24 /// serves). The serialization round-trip is behaviour-preserving (C1): same input, diff --git a/crates/aura-engine/tests/construction_e2e.rs b/crates/aura-engine/tests/construction_e2e.rs index 4af79a6..649c9f8 100644 --- a/crates/aura-engine/tests/construction_e2e.rs +++ b/crates/aura-engine/tests/construction_e2e.rs @@ -7,7 +7,7 @@ //! (`crate::GraphBuilder`, `crate::CompileError`, `super::replay`). These tests //! use only the **exported** surface — `aura_engine::{replay, Op, OpError, //! GraphBuilder, Composite, FlatGraph, Scalar, ScalarKind}` plus the injected -//! `aura_std::std_vocabulary` — the exact seam the iteration-2 CLI (`aura graph +//! `aura_vocabulary::std_vocabulary` — the exact seam the iteration-2 CLI (`aura graph //! build`/`introspect`) and the World consume. A refactor that made `Op`, //! `OpError`, `replay`, or a needed re-export (`ScalarKind`, `Scalar`) //! unreachable across the crate boundary would break that consumer while leaving @@ -15,7 +15,9 @@ //! addition to the per-property invariants below. use aura_engine::{replay, GraphBuilder, Op, OpError, Scalar, ScalarKind}; -use aura_std::{std_vocabulary, Bias, Sma, Sub}; +use aura_std::{Sma, Sub}; +use aura_strategy::Bias; +use aura_vocabulary::std_vocabulary; /// The flat root's open param point: fast.length(i64), slow.length(i64), /// bias.scale(f64), in param-space traversal order. The same vector is applied to @@ -45,7 +47,7 @@ fn signal_ops() -> Vec { } /// Property (C24 acceptance-1, through the public seam): an op-script replayed via -/// the exported `replay` + the injected `aura_std::std_vocabulary` compiles to a +/// the exported `replay` + the injected `aura_vocabulary::std_vocabulary` compiles to a /// `FlatGraph` whose index-wired topology (`edges`) and lowered bound sources /// (`sources`) are **identical** to the same signal hand-wired on the exported /// `GraphBuilder` surface and compiled with the same param point. The two diff --git a/crates/aura-engine/tests/ger40_breakout.rs b/crates/aura-engine/tests/ger40_breakout.rs index 389ca84..6a0bf5d 100644 --- a/crates/aura-engine/tests/ger40_breakout.rs +++ b/crates/aura-engine/tests/ger40_breakout.rs @@ -32,7 +32,9 @@ use std::sync::mpsc; use aura_core::{NodeSchema, Scalar, ScalarKind, Timestamp}; use aura_engine::{Edge, FlatGraph, Harness, Source, SourceSpec, Target, VecSource}; -use aura_std::{And, Delay, EqConst, Gt, Latch, Recorder, Resample, Session, SimBroker}; +use aura_backtest::SimBroker; +use aura_market::{Resample, Session}; +use aura_std::{And, Delay, EqConst, Gt, Latch, Recorder}; use chrono::TimeZone; use chrono_tz::Europe::Berlin; diff --git a/crates/aura-engine/tests/list_sweep_e2e.rs b/crates/aura-engine/tests/list_sweep_e2e.rs index 4b342e5..be00e3b 100644 --- a/crates/aura-engine/tests/list_sweep_e2e.rs +++ b/crates/aura-engine/tests/list_sweep_e2e.rs @@ -14,7 +14,9 @@ use aura_engine::{ f64_field, summarize, sweep, BlueprintNode, Composite, Edge, ListSpace, OutField, ParamSpec, Role, RunManifest, RunReport, Scalar, SweepError, Target, VecSource, }; -use aura_std::{Bias, Recorder, SimBroker, Sma, Sub}; +use aura_backtest::SimBroker; +use aura_std::{Recorder, Sma, Sub}; +use aura_strategy::Bias; /// Seven synthetic F64 ticks — the same fixture shape as `random_sweep_e2e.rs`, /// short enough that small SMA windows warm up deterministically. diff --git a/crates/aura-engine/tests/ohlc_from_blueprint_data.rs b/crates/aura-engine/tests/ohlc_from_blueprint_data.rs index ab68929..43c6279 100644 --- a/crates/aura-engine/tests/ohlc_from_blueprint_data.rs +++ b/crates/aura-engine/tests/ohlc_from_blueprint_data.rs @@ -11,7 +11,8 @@ use std::sync::mpsc; use aura_core::{Firing, Scalar, ScalarKind, Timestamp}; use aura_engine::{blueprint_from_json, BlueprintNode, Composite, Edge, Role, Target, VecSource}; -use aura_std::{std_vocabulary, Recorder}; +use aura_std::Recorder; +use aura_vocabulary::std_vocabulary; // value = (high - low) + (close - open): every column is load-bearing, so any // mis-pairing of roles to sources (or a wrong merge tie-break) changes the diff --git a/crates/aura-engine/tests/r_sma_e2e.rs b/crates/aura-engine/tests/r_sma_e2e.rs index 3f4b7a5..e3d8e3d 100644 --- a/crates/aura-engine/tests/r_sma_e2e.rs +++ b/crates/aura-engine/tests/r_sma_e2e.rs @@ -27,10 +27,8 @@ use aura_core::{AnyColumn, Ctx, Node, Scalar, ScalarKind, Timestamp}; use aura_engine::{PositionAction, RMetrics, derive_position_events, summarize_r}; -use aura_std::{ - ConstantCost, CostSum, FixedStop, PM_FIELD_NAMES, PM_RECORD_KINDS, PM_WIDTH, - PositionManagement, VolSlippageCost, -}; +use aura_backtest::{PM_FIELD_NAMES, PM_RECORD_KINDS, PM_WIDTH, PositionManagement}; +use aura_strategy::{ConstantCost, CostSum, FixedStop, VolSlippageCost}; // The indices `report.rs::summarize_r` reads the dense record by. Re-declared here // (the consumer's `r_col` module is private to `aura-engine`) so the guard test can @@ -267,7 +265,7 @@ fn net_of_cost_is_charged_per_r_so_a_wider_stop_dilutes_it() { assert!(tight_cost > wide_cost, "a tighter stop must pay more R per fixed price-unit cost"); } -/// Drive the REAL `aura_std::ConstantCost(c)` node over a recorded PM `ledger`, +/// Drive the REAL `aura_strategy::ConstantCost(c)` node over a recorded PM `ledger`, /// node-by-node off the producer's own `closed`/`open`/`entry_price`/`stop_price` /// columns — the actual cost producer the run-path graph taps (not an algebraic stand-in /// like `const_cost_stream`). Returns the node's 3-wide `[cost_in_r, cum_cost_in_r, @@ -336,7 +334,7 @@ fn net_r_equity_final_sample_agrees_with_summarize_r_net_total() { ); } -/// Drive the REAL `aura_std::VolSlippageCost(k)` node over a recorded PM `ledger` +/// Drive the REAL `aura_strategy::VolSlippageCost(k)` node over a recorded PM `ledger` /// with a constant `vol` per cycle — the run-path's vol-slippage producer. Returns /// the node's 3-wide `[cost_in_r, cum_cost_in_r, open_cost_in_r]` rows, co-temporal /// 1:1 with `ledger`. @@ -367,7 +365,7 @@ fn vol_slippage_node_stream( .collect() } -/// Drive the REAL `aura_std::CostSum(n)` aggregator over `n` co-temporal cost +/// Drive the REAL `aura_strategy::CostSum(n)` aggregator over `n` co-temporal cost /// streams, summing them per-field — the run-path's cost-graph output node. fn cost_sum_node_stream(streams: &[&[(Timestamp, Vec)]]) -> Vec<(Timestamp, Vec)> { let n = streams.len(); diff --git a/crates/aura-engine/tests/random_sweep_e2e.rs b/crates/aura-engine/tests/random_sweep_e2e.rs index a4f5222..664ab14 100644 --- a/crates/aura-engine/tests/random_sweep_e2e.rs +++ b/crates/aura-engine/tests/random_sweep_e2e.rs @@ -18,7 +18,9 @@ use aura_engine::{ f64_field, summarize, sweep, BlueprintNode, Composite, Edge, OutField, ParamRange, ParamSpec, RandomSpace, Role, RunManifest, RunReport, Scalar, Space, SweepError, Target, VecSource, }; -use aura_std::{Bias, Recorder, SimBroker, Sma, Sub}; +use aura_backtest::SimBroker; +use aura_std::{Recorder, Sma, Sub}; +use aura_strategy::Bias; /// Seven synthetic F64 ticks (mirrors the crate-private `synthetic_prices`): /// short enough that small SMA windows warm up, so every run yields finite, diff --git a/crates/aura-engine/tests/reopen_rebuild_e2e.rs b/crates/aura-engine/tests/reopen_rebuild_e2e.rs index 2d25cfa..16cdde6 100644 --- a/crates/aura-engine/tests/reopen_rebuild_e2e.rs +++ b/crates/aura-engine/tests/reopen_rebuild_e2e.rs @@ -13,7 +13,8 @@ use aura_core::{Scalar, ScalarKind}; use aura_engine::{Composite, Role, Target}; -use aura_std::{Bias, Sma}; +use aura_std::Sma; +use aura_strategy::Bias; /// A single bound `Sma`, wired from a root role so it compiles standalone. fn one_bound_sma() -> Composite { diff --git a/crates/aura-engine/tests/rsi_from_blueprint_data.rs b/crates/aura-engine/tests/rsi_from_blueprint_data.rs index d1b376e..3e11156 100644 --- a/crates/aura-engine/tests/rsi_from_blueprint_data.rs +++ b/crates/aura-engine/tests/rsi_from_blueprint_data.rs @@ -1,7 +1,7 @@ //! Acceptance proof for issue #236: an **RSI-class** signal — the classic //! gain/loss split of the price change and the smoothed **ratio** of average gain //! to average loss — composes *purely from blueprint data* through the injected -//! `aura_std::std_vocabulary` and runs to hand-computable RS values. This is the +//! `aura_vocabulary::std_vocabulary` and runs to hand-computable RS values. This is the //! property that pins the four std-vocabulary gaps the issue names as a single //! honest behaviour: `Div`, a `Const` source, `Abs`, and pairwise `Max`/`Min`. //! @@ -24,7 +24,8 @@ use std::sync::mpsc; use aura_core::{Firing, Scalar, ScalarKind, Timestamp}; use aura_engine::{blueprint_from_json, BlueprintNode, Composite, Edge, Role, Target, VecSource}; -use aura_std::{std_vocabulary, Recorder}; +use aura_std::Recorder; +use aura_vocabulary::std_vocabulary; // The RSI-class signal as blueprint data. Raw price fans out to a zero `Const` // (its clock is the price role), a `Delay[1]`, and a `Sub`; `delta = price - prev` diff --git a/crates/aura-engine/tests/streaming_reduction_equivalence.rs b/crates/aura-engine/tests/streaming_reduction_equivalence.rs index 22f20d6..0db868d 100644 --- a/crates/aura-engine/tests/streaming_reduction_equivalence.rs +++ b/crates/aura-engine/tests/streaming_reduction_equivalence.rs @@ -6,7 +6,8 @@ use aura_core::{AnyColumn, Ctx, Node, Scalar, ScalarKind, Timestamp}; use aura_engine::{summarize, summarize_r}; -use aura_std::{GatedRecorder, SeriesReducer, PM_RECORD_KINDS, PM_WIDTH}; +use aura_backtest::{PM_RECORD_KINDS, PM_WIDTH}; +use aura_std::{GatedRecorder, SeriesReducer}; use std::sync::mpsc; const CLOSED: usize = 0; diff --git a/crates/aura-engine/tests/streaming_reduction_memory.rs b/crates/aura-engine/tests/streaming_reduction_memory.rs index 880a657..394c5d7 100644 --- a/crates/aura-engine/tests/streaming_reduction_memory.rs +++ b/crates/aura-engine/tests/streaming_reduction_memory.rs @@ -12,7 +12,8 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc; use aura_core::{AnyColumn, Ctx, Node, Scalar, ScalarKind, Timestamp}; -use aura_std::{GatedRecorder, PM_RECORD_KINDS, PM_WIDTH}; +use aura_backtest::{PM_RECORD_KINDS, PM_WIDTH}; +use aura_std::GatedRecorder; struct CountingAlloc; static LIVE: AtomicUsize = AtomicUsize::new(0); diff --git a/crates/aura-engine/tests/when_e2e.rs b/crates/aura-engine/tests/when_e2e.rs index 68d16be..5beaddc 100644 --- a/crates/aura-engine/tests/when_e2e.rs +++ b/crates/aura-engine/tests/when_e2e.rs @@ -21,7 +21,8 @@ use std::sync::mpsc; use aura_core::{Firing, Scalar, ScalarKind, Timestamp}; use aura_engine::{GraphBuilder, VecSource}; -use aura_std::{Abs, Gt, Recorder, Resample, When}; +use aura_market::Resample; +use aura_std::{Abs, Gt, Recorder, When}; /// A deterministic `f64` tick stream, no timestamps/randomness beyond a fixed /// literal sequence. diff --git a/crates/aura-ingest/Cargo.toml b/crates/aura-ingest/Cargo.toml index fdd3790..32528d8 100644 --- a/crates/aura-ingest/Cargo.toml +++ b/crates/aura-ingest/Cargo.toml @@ -25,6 +25,9 @@ aura-engine = { path = "../aura-engine" } zip = "2" # the integration tests bootstrap a sample harness + fold a RunReport aura-std = { path = "../aura-std" } +aura-market = { path = "../aura-market" } +aura-strategy = { path = "../aura-strategy" } +aura-backtest = { path = "../aura-backtest" } # chrono / chrono-tz build the Berlin-local-wall-clock window bounds + the # Session node's timezone for the real GER40 session-breakout example/test # (examples/ger40_breakout_real.rs, tests/ger40_breakout_real.rs). Pinned to diff --git a/crates/aura-ingest/examples/shared/breakout_real.rs b/crates/aura-ingest/examples/shared/breakout_real.rs index aa10aa9..ff8198b 100644 --- a/crates/aura-ingest/examples/shared/breakout_real.rs +++ b/crates/aura-ingest/examples/shared/breakout_real.rs @@ -43,7 +43,9 @@ use aura_engine::{ join_on_ts, summarize, Composite, Edge, FlatGraph, GraphBuilder, Harness, RunManifest, RunReport, SourceSpec, Target, }; -use aura_std::{And, Delay, EqConst, Gt, Latch, Recorder, Resample, Session, SimBroker}; +use aura_backtest::SimBroker; +use aura_market::{Resample, Session}; +use aura_std::{And, Delay, EqConst, Gt, Latch, Recorder}; use chrono::TimeZone; use chrono_tz::Europe::Berlin; diff --git a/crates/aura-ingest/tests/real_bars.rs b/crates/aura-ingest/tests/real_bars.rs index fa11a39..5b1a2a8 100644 --- a/crates/aura-ingest/tests/real_bars.rs +++ b/crates/aura-ingest/tests/real_bars.rs @@ -13,7 +13,9 @@ use aura_engine::{ VecSource, }; use aura_ingest::load_m1_window; -use aura_std::{Bias, Recorder, SimBroker, Sma, Sub}; +use aura_backtest::SimBroker; +use aura_std::{Recorder, Sma, Sub}; +use aura_strategy::Bias; use data_server::{DataServer, DEFAULT_DATA_PATH}; /// Bootstrap the cycle-0007 two-sink signal-quality harness (mirrors diff --git a/crates/aura-ingest/tests/streaming_seam.rs b/crates/aura-ingest/tests/streaming_seam.rs index 5e517c1..4d3f934 100644 --- a/crates/aura-ingest/tests/streaming_seam.rs +++ b/crates/aura-ingest/tests/streaming_seam.rs @@ -13,7 +13,9 @@ use aura_engine::{ Target, }; use aura_ingest::{M1Field, M1FieldSource}; -use aura_std::{Bias, Recorder, SimBroker, Sma, Sub}; +use aura_backtest::SimBroker; +use aura_std::{Recorder, Sma, Sub}; +use aura_strategy::Bias; use data_server::loader::CHUNK_SIZE; use data_server::{DataServer, DEFAULT_DATA_PATH}; diff --git a/crates/aura-market/Cargo.toml b/crates/aura-market/Cargo.toml new file mode 100644 index 0000000..8b651da --- /dev/null +++ b/crates/aura-market/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "aura-market" +edition.workspace = true +version.workspace = true +license.workspace = true +publish.workspace = true + +[dependencies] +aura-core = { path = "../aura-core" } +chrono = { version = "0.4", default-features = false, features = ["clock"] } +chrono-tz = { version = "0.10", default-features = false } diff --git a/crates/aura-market/src/lib.rs b/crates/aura-market/src/lib.rs new file mode 100644 index 0000000..fc0d57d --- /dev/null +++ b/crates/aura-market/src/lib.rs @@ -0,0 +1,8 @@ +//! `aura-market` — the market-vocabulary node layer (C28): session anchoring and +//! bar resampling over market data streams. Depends only on `aura-core`. + +mod resample; +mod session; + +pub use resample::Resample; +pub use session::{Session, SessionFrankfurt}; diff --git a/crates/aura-std/src/resample.rs b/crates/aura-market/src/resample.rs similarity index 100% rename from crates/aura-std/src/resample.rs rename to crates/aura-market/src/resample.rs diff --git a/crates/aura-std/src/session.rs b/crates/aura-market/src/session.rs similarity index 100% rename from crates/aura-std/src/session.rs rename to crates/aura-market/src/session.rs diff --git a/crates/aura-registry/Cargo.toml b/crates/aura-registry/Cargo.toml index ce5d1ec..d9bf920 100644 --- a/crates/aura-registry/Cargo.toml +++ b/crates/aura-registry/Cargo.toml @@ -24,3 +24,5 @@ serde_json = { workspace = true } # the referential-tier test's generic param-space fixture (a real vocabulary # resolver + a zero-arg node, not hand-rolled). aura-std = { path = "../aura-std" } +aura-strategy = { path = "../aura-strategy" } +aura-vocabulary = { path = "../aura-vocabulary" } diff --git a/crates/aura-registry/src/lib.rs b/crates/aura-registry/src/lib.rs index 6237789..81dae25 100644 --- a/crates/aura-registry/src/lib.rs +++ b/crates/aura-registry/src/lib.rs @@ -1799,7 +1799,7 @@ mod tests { use aura_research::{Axis, DocRef}; let reg = Registry::open(temp_family_dir("referential_tier")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); // A minimal fixture composite with one OPEN param, built from a // zero-arg `aura-std` node (`Bias`) so `std_vocabulary` can actually @@ -1812,7 +1812,7 @@ mod tests { // vocabulary-loadable composite" the test needs. let composite = Composite::new( "fixture", - vec![aura_std::Bias::builder().named("b").into()], + vec![aura_strategy::Bias::builder().named("b").into()], vec![], vec![], vec![], @@ -1942,7 +1942,7 @@ mod tests { fn bias_fixture() -> aura_engine::Composite { aura_engine::Composite::new( "fixture", - vec![aura_std::Bias::builder().named("b").into()], + vec![aura_strategy::Bias::builder().named("b").into()], vec![], vec![], vec![], @@ -1966,7 +1966,7 @@ mod tests { #[test] fn identity_index_lookup_backfills_and_resolves() { let reg = Registry::open(temp_family_dir("identity_backfill")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); let (blueprint_json, content_id, identity_id) = seed_blueprint(®, &bias_fixture()); // no index yet: the lookup answers via the scan fallback... @@ -1983,7 +1983,7 @@ mod tests { #[test] fn identity_index_verified_hit_answers_without_a_store_walk() { let reg = Registry::open(temp_family_dir("identity_hit_no_walk")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); let (blueprint_json, _content_id, identity_id) = seed_blueprint(®, &bias_fixture()); // backfill the index, then poison the store: a DIRECTORY named like @@ -2003,7 +2003,7 @@ mod tests { #[test] fn identity_index_legacy_store_backfills_in_one_pass() { let reg = Registry::open(temp_family_dir("identity_legacy_backfill")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); let (_json_a, content_a, identity_a) = seed_blueprint(®, &bias_fixture()); let (_json_b, content_b, identity_b) = seed_blueprint(®, &delay_fixture()); assert_ne!(identity_a, identity_b, "fixtures must be identity-distinct"); @@ -2023,7 +2023,7 @@ mod tests { #[test] fn identity_index_stale_lines_degrade_to_scan_and_heal() { let reg = Registry::open(temp_family_dir("identity_stale_heals")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); let (json_a, content_a, identity_a) = seed_blueprint(®, &bias_fixture()); let (_json_b, content_b, _identity_b) = seed_blueprint(®, &delay_fixture()); @@ -2052,7 +2052,7 @@ mod tests { #[test] fn identity_index_unloadable_under_roster_stays_unmatched() { let reg = Registry::open(temp_family_dir("identity_unloadable")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); let (_json, _content_id, identity_id) = seed_blueprint(®, &bias_fixture()); reg.find_blueprint_by_identity(&identity_id, &resolve).expect("backfill"); @@ -2067,7 +2067,7 @@ mod tests { #[test] fn identity_index_garbage_line_does_not_break_resolution() { let reg = Registry::open(temp_family_dir("identity_garbage_line")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); let (blueprint_json, _content_id, identity_id) = seed_blueprint(®, &bias_fixture()); // a wholly-garbage index file must not break resolution (a @@ -2089,7 +2089,7 @@ mod tests { #[test] fn identity_index_twin_store_converges_and_stops_growing() { let reg = Registry::open(temp_family_dir("identity_twin_converges")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); // Two same-identity twins: the one-node Bias composite, built with // different debug names. Debug symbols are identity-blind, so the two @@ -2097,7 +2097,7 @@ mod tests { let (_json_a, content_a, identity) = seed_blueprint(®, &bias_fixture()); let twin = aura_engine::Composite::new( "fixture_twin", - vec![aura_std::Bias::builder().named("b_twin").into()], + vec![aura_strategy::Bias::builder().named("b_twin").into()], vec![], vec![], vec![], @@ -2145,7 +2145,7 @@ mod tests { use aura_std::Sma; let reg = Registry::open(temp_family_dir("bound_axis_tier")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); // A fixture composite with ONE bound param and NO open param, so the // reverse full-coverage check (every OPEN param must be bound by an @@ -2234,7 +2234,7 @@ mod tests { use aura_engine::{blueprint_to_json, Composite}; let reg = Registry::open(temp_family_dir("coverage_tier")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); // A fixture composite with TWO open params, from two zero-arg `Bias` // nodes so `std_vocabulary` can load it on round-trip (the sibling test @@ -2243,8 +2243,8 @@ mod tests { let composite = Composite::new( "fixture", vec![ - aura_std::Bias::builder().named("b1").into(), - aura_std::Bias::builder().named("b2").into(), + aura_strategy::Bias::builder().named("b1").into(), + aura_strategy::Bias::builder().named("b2").into(), ], vec![], vec![], @@ -2307,14 +2307,14 @@ mod tests { use aura_engine::{blueprint_to_json, Composite, Role, Target}; let reg = Registry::open(temp_family_dir("binding_keys")); - let resolve = |t: &str| aura_std::std_vocabulary(t); + let resolve = |t: &str| aura_vocabulary::std_vocabulary(t); // The referential fixture composite (see // referential_tier_resolves_refs_and_checks_axes), plus ONE input // role so a binding key has something to name. let composite = Composite::new( "fixture", - vec![aura_std::Bias::builder().named("b").into()], + vec![aura_strategy::Bias::builder().named("b").into()], vec![], vec![Role { name: "price".to_string(), diff --git a/crates/aura-std/Cargo.toml b/crates/aura-std/Cargo.toml index 62a8746..a0c8658 100644 --- a/crates/aura-std/Cargo.toml +++ b/crates/aura-std/Cargo.toml @@ -14,3 +14,7 @@ aura-core = { path = "../aura-core" } # zone + DST transitions. chrono = { version = "0.4", default-features = false, features = ["clock"] } chrono-tz = { version = "0.10", default-features = false } + +[dev-dependencies] +aura-strategy = { path = "../aura-strategy" } +aura-backtest = { path = "../aura-backtest" } diff --git a/crates/aura-std/src/lib.rs b/crates/aura-std/src/lib.rs index 1f1a7a6..4f55fe0 100644 --- a/crates/aura-std/src/lib.rs +++ b/crates/aura-std/src/lib.rs @@ -20,12 +20,7 @@ mod abs; mod add; mod and; -mod bias; -mod carry_cost; mod const_node; -mod constant_cost; -mod cost; -mod cost_sum; mod cumsum; mod delay; mod div; @@ -35,42 +30,24 @@ mod gated_recorder; mod gt; mod latch; mod lincomb; -mod longonly; mod max; mod min; mod mul; -mod position_management; mod recorder; -mod resample; mod rolling_max; mod rolling_min; mod scale; mod select; mod series_reducer; -mod session; mod sign; -mod sim_broker; -mod sizer; mod sma; mod sqrt; -mod stop_rule; mod sub; -mod vocabulary; -mod vol_slippage_cost; -mod vol_tf_stop; mod when; pub use abs::Abs; pub use add::Add; pub use and::And; -pub use bias::Bias; -pub use carry_cost::CarryCost; pub use const_node::Const; -pub use constant_cost::ConstantCost; -pub use cost::{ - cost_node_builder, cost_port, intern_port, ChargeMode, CostNode, CostRunner, - COST_FIELD_NAMES, COST_WIDTH, GEOMETRY_WIDTH, -}; -pub use cost_sum::CostSum; pub use cumsum::CumSum; pub use delay::Delay; pub use div::Div; @@ -80,30 +57,17 @@ pub use gated_recorder::GatedRecorder; pub use gt::Gt; pub use latch::Latch; pub use lincomb::LinComb; -pub use longonly::LongOnly; pub use max::Max; pub use min::Min; pub use mul::Mul; -pub use position_management::{ - ExitReason, FIELD_NAMES as PM_FIELD_NAMES, PositionManagement, RECORD_KINDS as PM_RECORD_KINDS, - WIDTH as PM_WIDTH, -}; pub use recorder::Recorder; -pub use resample::Resample; pub use rolling_max::RollingMax; pub use rolling_min::RollingMin; pub use scale::Scale; pub use select::Select; pub use series_reducer::SeriesReducer; -pub use session::{Session, SessionFrankfurt}; pub use sign::Sign; -pub use sim_broker::SimBroker; -pub use sizer::Sizer; pub use sma::Sma; pub use sqrt::Sqrt; -pub use stop_rule::FixedStop; pub use sub::Sub; -pub use vocabulary::{std_vocabulary, std_vocabulary_types}; -pub use vol_slippage_cost::VolSlippageCost; -pub use vol_tf_stop::VolTfStop; pub use when::When; diff --git a/crates/aura-std/src/sma.rs b/crates/aura-std/src/sma.rs index 2acfb20..2e9c97d 100644 --- a/crates/aura-std/src/sma.rs +++ b/crates/aura-std/src/sma.rs @@ -202,7 +202,9 @@ mod tests { #[test] fn labels_carry_identifying_params() { - use crate::{Add, Bias, LinComb, Recorder, SimBroker, Sub}; + use crate::{Add, LinComb, Recorder, Sub}; + use aura_strategy::Bias; + use aura_backtest::SimBroker; use aura_core::{Firing, ScalarKind}; // the load-bearing payoff: two SMAs disambiguate by window @@ -221,7 +223,9 @@ mod tests { #[test] fn nodes_declare_expected_params() { - use crate::{Add, Bias, LinComb, Recorder, SimBroker, Sub}; + use crate::{Add, LinComb, Recorder, Sub}; + use aura_strategy::Bias; + use aura_backtest::SimBroker; use aura_core::{Firing, ParamSpec, ScalarKind}; // single scalar knobs (declared on the param-generic builder, pre-build) assert_eq!( diff --git a/crates/aura-strategy/Cargo.toml b/crates/aura-strategy/Cargo.toml new file mode 100644 index 0000000..ce30138 --- /dev/null +++ b/crates/aura-strategy/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "aura-strategy" +edition.workspace = true +version.workspace = true +license.workspace = true +publish.workspace = true + +[dependencies] +aura-core = { path = "../aura-core" } diff --git a/crates/aura-std/src/bias.rs b/crates/aura-strategy/src/bias.rs similarity index 100% rename from crates/aura-std/src/bias.rs rename to crates/aura-strategy/src/bias.rs diff --git a/crates/aura-std/src/carry_cost.rs b/crates/aura-strategy/src/carry_cost.rs similarity index 100% rename from crates/aura-std/src/carry_cost.rs rename to crates/aura-strategy/src/carry_cost.rs diff --git a/crates/aura-std/src/constant_cost.rs b/crates/aura-strategy/src/constant_cost.rs similarity index 100% rename from crates/aura-std/src/constant_cost.rs rename to crates/aura-strategy/src/constant_cost.rs diff --git a/crates/aura-std/src/cost.rs b/crates/aura-strategy/src/cost.rs similarity index 99% rename from crates/aura-std/src/cost.rs rename to crates/aura-strategy/src/cost.rs index 967b387..e43d080 100644 --- a/crates/aura-std/src/cost.rs +++ b/crates/aura-strategy/src/cost.rs @@ -91,7 +91,7 @@ pub enum ChargeMode { /// /// ``` /// use aura_core::Ctx; -/// use aura_std::{CostNode, CostRunner}; +/// use aura_strategy::{CostNode, CostRunner}; /// /// pub struct HalfSpreadCost { /// half_spread: f64, diff --git a/crates/aura-std/src/cost_sum.rs b/crates/aura-strategy/src/cost_sum.rs similarity index 100% rename from crates/aura-std/src/cost_sum.rs rename to crates/aura-strategy/src/cost_sum.rs diff --git a/crates/aura-strategy/src/lib.rs b/crates/aura-strategy/src/lib.rs new file mode 100644 index 0000000..fc382d8 --- /dev/null +++ b/crates/aura-strategy/src/lib.rs @@ -0,0 +1,28 @@ +//! `aura-strategy` — the strategy-definition node layer (C28): bias, stop rules, +//! sizing, and the cost-model machinery (measured in R). Depends only on +//! `aura-core`. + +mod bias; +mod carry_cost; +mod constant_cost; +mod cost; +mod cost_sum; +mod longonly; +mod sizer; +mod stop_rule; +mod vol_slippage_cost; +mod vol_tf_stop; + +pub use bias::Bias; +pub use carry_cost::CarryCost; +pub use constant_cost::ConstantCost; +pub use cost::{ + cost_node_builder, cost_port, intern_port, ChargeMode, CostNode, CostRunner, + COST_FIELD_NAMES, COST_WIDTH, GEOMETRY_WIDTH, +}; +pub use cost_sum::CostSum; +pub use longonly::LongOnly; +pub use sizer::Sizer; +pub use stop_rule::FixedStop; +pub use vol_slippage_cost::VolSlippageCost; +pub use vol_tf_stop::VolTfStop; diff --git a/crates/aura-std/src/longonly.rs b/crates/aura-strategy/src/longonly.rs similarity index 100% rename from crates/aura-std/src/longonly.rs rename to crates/aura-strategy/src/longonly.rs diff --git a/crates/aura-std/src/sizer.rs b/crates/aura-strategy/src/sizer.rs similarity index 100% rename from crates/aura-std/src/sizer.rs rename to crates/aura-strategy/src/sizer.rs diff --git a/crates/aura-std/src/stop_rule.rs b/crates/aura-strategy/src/stop_rule.rs similarity index 100% rename from crates/aura-std/src/stop_rule.rs rename to crates/aura-strategy/src/stop_rule.rs diff --git a/crates/aura-std/src/vol_slippage_cost.rs b/crates/aura-strategy/src/vol_slippage_cost.rs similarity index 100% rename from crates/aura-std/src/vol_slippage_cost.rs rename to crates/aura-strategy/src/vol_slippage_cost.rs diff --git a/crates/aura-std/src/vol_tf_stop.rs b/crates/aura-strategy/src/vol_tf_stop.rs similarity index 100% rename from crates/aura-std/src/vol_tf_stop.rs rename to crates/aura-strategy/src/vol_tf_stop.rs diff --git a/crates/aura-vocabulary/Cargo.toml b/crates/aura-vocabulary/Cargo.toml new file mode 100644 index 0000000..157ebab --- /dev/null +++ b/crates/aura-vocabulary/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "aura-vocabulary" +edition.workspace = true +version.workspace = true +license.workspace = true +publish.workspace = true + +[dependencies] +aura-core = { path = "../aura-core" } +aura-std = { path = "../aura-std" } +aura-market = { path = "../aura-market" } +aura-strategy = { path = "../aura-strategy" } +aura-backtest = { path = "../aura-backtest" } + +[dev-dependencies] +toml = "0.8" diff --git a/crates/aura-std/src/vocabulary.rs b/crates/aura-vocabulary/src/lib.rs similarity index 92% rename from crates/aura-std/src/vocabulary.rs rename to crates/aura-vocabulary/src/lib.rs index e19e352..eb3486b 100644 --- a/crates/aura-std/src/vocabulary.rs +++ b/crates/aura-vocabulary/src/lib.rs @@ -1,10 +1,10 @@ //! The closed, compiled-in dispatch from a serialized node **type identity** to -//! its `aura-std` builder factory — the load-side counterpart to the type label +//! its node-crate builder factory — the load-side counterpart to the type label //! a blueprint serializes (`PrimitiveBuilder::label`). This is **not** a dynamic //! registry (domain invariant 9): it is a `match` the crate that *owns* the //! nodes writes, over its own closed, compiled-in vocabulary (C24 — nodes are //! referenced "by compiled-in type identity", never a by-name marketplace). The -//! engine cannot hold this table (it does not depend on `aura-std`); a loader +//! engine cannot hold this table (it does not depend on the node crates); a loader //! takes it as an injected resolver, and a project `cdylib` later supplies its //! own (C16) through the same seam. //! @@ -17,11 +17,13 @@ //! rather than guessing. Serialising structural-axis construction args is a //! later, additive extension (#156/C20). -use crate::{ - Abs, Add, And, Bias, CarryCost, Const, ConstantCost, CumSum, Delay, Div, Ema, EqConst, - FixedStop, Gt, Latch, LongOnly, Max, Min, Mul, PositionManagement, Resample, RollingMax, - RollingMin, Scale, Select, SessionFrankfurt, Sign, Sizer, Sma, Sqrt, Sub, VolSlippageCost, When, +use aura_backtest::PositionManagement; +use aura_market::{Resample, SessionFrankfurt}; +use aura_std::{ + Abs, Add, And, Const, CumSum, Delay, Div, Ema, EqConst, Gt, Latch, Max, Min, Mul, RollingMax, + RollingMin, Scale, Select, Sign, Sma, Sqrt, Sub, When, }; +use aura_strategy::{Bias, CarryCost, ConstantCost, FixedStop, LongOnly, Sizer, VolSlippageCost}; use aura_core::PrimitiveBuilder; /// The single roster source (#160): one `"TypeId" => Type` line per zero-arg @@ -37,7 +39,7 @@ macro_rules! std_vocabulary_roster { ($($type_id:literal => $ty:ty),+ $(,)?) => { /// Resolve a serialized node type identity (the `PrimitiveBuilder::label`, /// e.g. `"SMA"`) to a fresh, unbound builder from the node's own factory. - /// Returns `None` for any identity outside the zero-arg `aura-std` + /// Returns `None` for any identity outside the zero-arg node /// vocabulary. pub fn std_vocabulary(type_id: &str) -> Option { Some(match type_id { diff --git a/crates/aura-vocabulary/tests/c28_layering.rs b/crates/aura-vocabulary/tests/c28_layering.rs new file mode 100644 index 0000000..01a0067 --- /dev/null +++ b/crates/aura-vocabulary/tests/c28_layering.rs @@ -0,0 +1,62 @@ +//! C28 structural fitness: the node crates obey the ladder import direction. +//! The compiler only rejects import cycles; an acyclic-but-outward dependency +//! (e.g. `aura-std` -> `aura-market`) would compile silently. This test reads +//! each node crate's `[dependencies]` table and asserts its intra-workspace edges +//! stay within the inner set C28 permits for that layer. `[dev-dependencies]` are +//! C28-exempt (tests may cross layers) and are deliberately not inspected. + +use std::path::PathBuf; + +fn workspace_root() -> PathBuf { + // aura-vocabulary/ + /../.. = workspace root (the repo idiom for reaching it). + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..").join("..") +} + +/// The `aura-*` keys under `[dependencies]` (NOT `[dev-dependencies]`) of a crate. +fn prod_intra_workspace_deps(crate_name: &str) -> Vec { + let manifest = workspace_root() + .join("crates") + .join(crate_name) + .join("Cargo.toml"); + let text = std::fs::read_to_string(&manifest) + .unwrap_or_else(|e| panic!("read {}: {e}", manifest.display())); + let doc: toml::Value = toml::from_str(&text).expect("Cargo.toml parses as TOML"); + match doc.get("dependencies").and_then(|d| d.as_table()) { + Some(deps) => deps + .keys() + .filter(|k| k.starts_with("aura-")) + .cloned() + .collect(), + None => Vec::new(), + } +} + +#[test] +fn node_crates_obey_the_c28_import_direction() { + // (crate, the intra-workspace [dependencies] C28 permits for its layer) + let allowed: &[(&str, &[&str])] = &[ + ("aura-std", &["aura-core"]), // engine + ("aura-market", &["aura-core"]), // market + ("aura-strategy", &["aura-core"]), // strategy + ("aura-backtest", &["aura-core"]), // backtest (may gain aura-strategy when it imports one) + ( + "aura-vocabulary", + &[ + "aura-core", + "aura-std", + "aura-market", + "aura-strategy", + "aura-backtest", + ], + ), + ]; + for (crate_name, permitted) in allowed { + for dep in prod_intra_workspace_deps(crate_name) { + assert!( + permitted.contains(&dep.as_str()), + "C28 import-direction violation: `{crate_name}` [dependencies] on `{dep}`, \ + outside its permitted inner set {permitted:?}" + ); + } + } +} diff --git a/docs/design/INDEX.md b/docs/design/INDEX.md index 5693f06..0ac9974 100644 --- a/docs/design/INDEX.md +++ b/docs/design/INDEX.md @@ -2684,23 +2684,29 @@ cleanly by layer, so the layering is realized only partially: The stratification supplies the *second* metric consumer (measurement) that the deferral was waiting on, so retiring #147 and cutting this edge are one coupled decision — reserved to the user, since it reverses a ratified deferral. -- The interweaving is mostly *inside* crates. `aura-std` holds four layers in one - roster: engine (arithmetic/logic/rolling + the generic sinks), market - (`session.rs`, `resample.rs`), strategy (`bias.rs`/`stop_rule.rs`/`sizer.rs` + - the cost nodes) and backtest (`sim_broker.rs`, `position_management.rs`); - `aura-analysis` holds backtest reductions and generic hurdle math together. No - crate exists yet for *measurement* (its run verb is the additive shape dispatch, - #286) or *execution* (unbuilt — the C10/C13 edge only). Under this model the - `aura-registry → aura-research` edge is column-internal and legal. +- The `aura-std` four-layer roster is now cut by layer (phase 4, #288): `aura-std` + holds the engine nodes only (arithmetic/logic/rolling + the generic sinks); + `aura-market` (`session`, `resample`), `aura-strategy` (`bias`/`stop_rule`/ + `sizer` + the cost nodes) and `aura-backtest` (`sim_broker`, + `position_management`) carry the outer rungs, each depending only on `aura-core`; + the closed node roster moved to `aura-vocabulary`. The remaining in-crate + interweave is `aura-analysis`, which still holds backtest reductions and generic + hurdle math together (phase 5). No crate exists yet for *measurement* (its run + verb is the additive shape dispatch, #286) or *execution* (unbuilt — the C10/C13 + edge only). Under this model the `aura-registry → aura-research` edge is + column-internal and legal. - Phased realization (each independently shippable; behaviour byte-identical except the purely additive shape dispatch): (1) this contract; (2) cut the `engine → analysis` edge — coupled to the #147 decision above; (3) the #286 shape dispatch plus the per-run scaffold as a library (seeds an `aura-backtest` crate, gives *measurement* its run verb, removes the measured O(cycles) run-time - retention); (4) split the `aura-std` roster along engine / market / - strategy+backtest; (5) split `aura-analysis` into generic statistics and - backtest metrics; (6) generify the column's metric interface (demand-driven — - this is #147). Crate names provisional; full evidence on #286 and the milestone. + retention); (4) split the `aura-std` roster along engine / market / strategy / + backtest — **done** (#288: four `aura-core`-only node crates, the closed roster + moved to `aura-vocabulary`, the ladder direction enforced by a structural test); + (5) split `aura-analysis` into generic statistics and backtest metrics; (6) + generify the column's metric interface (demand-driven — this is #147). Crate + names now realized (`aura-market`/`aura-strategy`/`aura-backtest`/ + `aura-vocabulary`); full evidence on #288, #286 and the milestone. ---