Split the aura-std roster along the C28 ladder into layer-aligned crates #288
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 4 of the Stratification milestone. See contract C28 and its Status
block in the design ledger (
docs/design/INDEX.md) for the trading-ladder modeland the phase enumeration; #286 ratified C28 (Phase 1) and gave the measurement
layer its bare run verb (Phase 3).
Situation
C28's import rule binds crate structure, not only graph composition: an inner
ladder layer never imports an outer one. Today
aura-stdbundles nodes fromseveral ladder layers in a single crate — engine-layer arithmetic / logic /
rolling blocks and sinks, market-layer session-anchoring and bar-resampling
geometry, and strategy-layer bias / stop-rule / position-management nodes. While
these share one crate the C28 import direction is structurally unenforceable:
nothing stops a layer-1 block from reaching a layer-3 one, because they compile
in the same unit.
Goal
Distribute the
aura-stdroster across layer-aligned crates so the C28 importdirection is enforced by crate boundaries. Behaviour-preserving — node logic is
unchanged; this is a structural cut, not a feature. The exact crate set, their
names, and the per-node roster assignment are derived against C28 and the current
workspace crate graph during spec production and recorded here as decision-log
comments before the spec is written.
Scope
RunReport<M>+ the registry metric/deflation-vocabularygenericity), which is the separate coupled block for cutting the
aura-engine→aura-analysisedge (milestone Phases 2 and 6).aura runshape dispatch from Phase 3 (#286) already lets ameasurement-shaped blueprint run without the strategy scaffold; this phase
changes no run behaviour, only where node code lives.
Design decisions (specify Step 1.5 — derived, not user-settled)
Recon of the
aura-stdroster and its intra-crate + workspace import graph (enginecommit
34ff539) settles the split shape below. These are derived orchestratordecisions under the C28 layer model (
docs/design/INDEX.md), recorded forafter-the-fact audit and veto; none was settled by user preference.
Verified ground. The only production intra-crate coupling in
aura-stdis(a) the four cost nodes →
cost.rs(all within the strategy layer) and (b)vocabulary.rs→ every node (the closed-roster dispatch table). Every other node isan
aura-core-only leaf: no productionuse crate::crosses a layer boundary —sim_broker.rs/position_management.rsimport no strategy or market node, andcost.rsimports noposition_management(the "PM-geometry" coupling is a sharedfield-layout / R convention, not a Rust
use). So the four ladder layers in theroster are cycle-free when cut into separate crates.
Crate split (D1/D2). Four node crates, each depending only on
aura-core:aura-std— kept as the engine-layer node crate: arithmetic / logic /comparison / rolling-window nodes, the generic combinators (
When,LinComb,Select,Const), the registers (Delay,Latch), and the generic sinks(
Recorder,GatedRecorder,SeriesReducer). C28 names "the domain-free part ofaura-std" as engine-layer, so these stay put.
aura-market(new) —Session/SessionFrankfurt,Resample(C28 filessession anchoring and bar resampling under market).
aura-strategy(new) —Bias,LongOnly,FixedStop,VolTfStop,Sizer, andthe cost-model machinery (
cost.rstrait/runner +ConstantCost,CarryCost,VolSlippageCost,CostSum). C28 files bias / stops / sizing / cost understrategy.
aura-backtest(new) —SimBroker,PositionManagement/ExitReason(C28 filesthe SimBroker and position-management under backtest).
Ambiguous placements resolved.
Resample→ market (OHLC / bar vocabulary, andC28's explicit "bar resampling").
SimBroker→ backtest (C28's explicit "theSimBroker … under backtest", over its market-flavoured pip vocabulary).
Latch→engine (a generic RTL SR-latch register; feeding SimBroker's exposure is
composition, not classification). The
cost.rstrait/runner → strategy (a genericadapter, but C28 files cost-model nodes under strategy and it carries no production
backtest import).
Considered and rejected: a combined
strategy+backtestcrate. The C28 phase-4line reads "engine / market / strategy+backtest", readable as one combined crate.
Rejected: the nodes are fully decoupled (verified — no cost↔PM production import), so
nothing technical forces the weld; C28 already ratifies strategy (layer 4) and
backtest (layer 5) as distinct rungs, and phase 5 routes the backtest metrics (out
of
aura-analysis) to a backtest home — so a distinctaura-backtestcrate is thetarget regardless. Combining would only defer a split the contract already mandates.
(Lower churn is the sole argument for combining, and effort is a tiebreaker at most.)
The closed-vocabulary roster (D3).
vocabulary.rs'sstd_vocabulary/std_vocabulary_types(thestd_vocabulary_roster!single-source macro, #160) namesnodes across all four layers, so it cannot stay in engine-layer
aura-std(thatwould import outward). It moves to a new thin
aura-vocabularycrate depending on thefour node crates; the macro invocation's node paths update to the new crates,
preserving the single-source no-drift property. Production reaches it only through
aura-cli'sproject::Env::resolve; the engine / registry test suites reach it as adev-dependency (C28-exempt). Consumers change the import path
aura_std::std_vocabulary→aura_vocabulary::std_vocabulary, call sites unchanged.A dedicated crate (over folding the roster into
aura-composites) keepsaura-engine's dev-dependency on the roster cycle-free, sinceaura-vocabularydepends on no crate that reaches back to
aura-engine.Scope note. The
wrap_rper-run scaffold stays inaura-clithis phase. The C28phase-3 line attributes seeding an
aura-backtestscaffold library to phase 3, but34ff539shipped only the shape dispatch + barerun_measurement. This phase movesthe backtest nodes; extracting the scaffold library is deferred so phase 4 stays a
pure node-roster split. Behaviour is byte-identical throughout (a structural cut).
Spec auto-signed (specify Step 6, /boss)
The design (the
aura-stdlayer-crate split — decisions in comment3875) was auto-signed on a
grounding-checkPASS under
/boss, with no human in the loop: an independent fresh-contextreview ratified all load-bearing assumptions about current behaviour — the
cross-layer production decoupling of the roster,
std_vocabulary's productionreach confined to
aura-cli's resolve seam, theaura-engine/aura-registrydev-dependency status, and the closed-roster macro's relocatability — against
currently-green tests and a clean
cargo check --workspace. No golden is edited;behaviour stays byte-identical. The design is settled and ready for plan
production. A user reply vetoes this signature.
Planner resolutions (specify → planner, derived)
Plan-recon surfaced four byte-level questions the spec left open; resolved here so
no implementer improvises.
aura-market. No[workspace.dependencies]chrono entry exists —aura-std/aura-engine/aura-ingesteach pin it directly.aura-marketmirrors that direct-pin style (
chrono+chrono-tz, same versions/features asaura-std); no new workspace-level entry is introduced (that would be an unscopedchange beyond this phase).
aura-std's ownsma.rstest. Its#[cfg(test)]module referencescrate::{Bias, SimBroker}, which relocate toaura-strategy/aura-backtest.Resolution: add
aura-strategy+aura-backtesttoaura-std's[dev-dependencies](test-only cross-layer edges are C28-exempt and cycle-free —the new crates depend only on
aura-core), and rewrite the two test imports.This corrects the draft's "aura-std manifest unchanged": its
[dependencies]isunchanged; its
[dev-dependencies]gains two entries.c28_layeringstructural test's parser. No workspace-leveltoml;aura-clipinstoml = "0.8".aura-vocabularytakes the same pin as a[dev-dependencies]entry. The test inspects each node crate's[dependencies]table only —
[dev-dependencies]are C28-exempt and deliberately not checked.env!("CARGO_MANIFEST_DIR")joined with/../..to reach the workspace root, thencrates/<name>/Cargo.tomlper neighbour.A cycle-close audit item, noted for later: the C28 Status block
(
docs/design/INDEX.md, point 4 and the "aura-std holds four layers" paragraph)describes this split as pending; landing this phase makes that prose current and it
is updated as part of the phase.
Phase 4 implemented — awaiting review + merge
The
aura-stdroster split is implemented on branchissue-288-std-split(commit
b39fd63):aura-stdis reduced to the engine nodes;aura-market,aura-strategy,aura-backtestcarry the outer rungs (each depending only onaura-core); the closed roster moved toaura-vocabulary. Node modules movedbyte-identically (verified 0-change renames); consumers were rewired by import
path only. The full workspace suite is green (1448 tests, 0 failed),
clippy -D warningsis clean, and a new structural test(
aura-vocabulary/tests/c28_layering.rs) enforces the C28 import direction —catching the acyclic-but-outward edge the compiler misses. The C28 Status block
(
docs/design/INDEX.md) is updated to mark phase 4 done.The work awaits review and the ratified merge; the commit carries
closes #288.