Brummel f7c809e5ce refactor(cli): retire the r-sma demo builder — topology now lives only as data (#159 cut 1b)
Cut 1b of the hard-wired demo retirement — the removal half. With the proven
example shipped in cut 1, delete the r-sma builder and its whole transitive
closure so no production function constructs the r-sma topology any more; it
exists only as data (crates/aura-cli/examples/r_sma{,_open}.json).

Deleted: sma_signal (the builder), r_sma_graph, run_r_sma (aura run --harness
r-sma), r_sma_sweep_family (aura sweep --strategy r-sma), the synthetic inline
r-sma walkforward/mc machinery (r_sma_space/r_sma_sweep_over/run_oos_r/
run_mc_r_bootstrap/mc_r_bootstrap_report + the walkforward_family RSma arm), both
fixture emitters, the round-trip + cut-1 byte-fidelity tests, the R_SMA_FAST/
SLOW/BIAS_SCALE consts, and the Strategy::RSma / HarnessKind::RSma / McArgs::RealR
variants. The three dissolved-verb synth sites (generalize/walkforward/mc
--strategy r-sma --real) now embed the shipped open example via include_str!
instead of building it — byte-safe, guarded by the unchanged dissolved-verb
real-archive goldens. The two now-redundant fixtures move to the examples
(deleted, ~40 readers repointed). The --cost-* flags on `aura run` retire with
the harness (their sole consumer was run_r_sma; cost-model coverage survives
engine/std/composites-level).

The retired demo surfaces (--harness r-sma, sweep/walkforward/mc --strategy r-sma
inline) have working data successors: aura run examples/r_sma.json, aura sweep
examples/r_sma_open.json --axis …, and the --strategy r-sma --real campaign path.

Deviation from the plan, noted: StopArm collapsed to StopRule in wrap_r's
signature (its only other variant, Open, died with r_sma_graph) — cleaner than
the planned vestigial single-variant enum; behaviour-preserving, touching
campaign_run.rs and the r-breakout/r-meanrev call sites.

Follow-up (not this cut): wrap_r's cost-node-building branch is now unreachable
(nothing passes Some(CostConfig) after run_r_sma's deletion) yet clippy-clean —
a latent cleanup for when the inline cost surface fully retires.

The stage1-r param-suffix remapping (r_sma_friendly_name + the FAST/SLOW/
STOP_LENGTH/STOP_K_SUFFIX consts) went dead and was removed, closing #167 by
deletion.

Verification (own, not the workflow's report): full `cargo test --workspace`
green; `cargo clippy --workspace --all-targets -- -D warnings` clean, no
dead-code residue; the cut-1 grade anchor (shipped_r_sma_example_reproduces_the_
builtin_grade) and the dissolved-verb real goldens (generalize/walkforward/mc
_dissolves_through_the_campaign_path) stay byte-identical. A first workflow
attempt was discarded after a subagent's `git checkout -- main.rs` recovery
silently reverted earlier tasks' edits (filed on the plugin tracker as
Brummel/Skills#23); this landing is the hardened re-run, verified by hand.

closes #167
refs #159
2026-07-07 17:41:59 +02:00

aura

aura is a "game engine for traders." It is a Rust framework — and a playground — for authoring trading strategies as composable dataflow nodes, backtesting them deterministically and massively in parallel, validating them (sweep / Monte-Carlo / walk-forward), and freezing a validated strategy into a standalone bot with a broker connection. Its differentiator is the World: a program that constructs and orchestrates whole families of backtests, not the single run.

This README is a discoverability map of the shipped aura CLI — what commands exist and what they do. It deliberately keeps per-flag detail light; the two authoritative sources for exact syntax are always:

  • aura <command> --help — the exhaustive flag grammar.
  • The design ledger (docs/design/INDEX.md) and glossary (docs/glossary.md) — the concepts and invariants behind the surface.

Build & run

aura is a Cargo workspace. Build everything and you get one binary named aura:

cargo build --workspace          # binary at target/debug/aura
cargo build --workspace --release  # optimized, at target/release/aura

Invoke it as aura <command> … (examples below use the plain name).

Concepts in one breath

  • Blueprint — a serialized signal graph as data: a param-generic price → bias node graph. A blueprint file (blueprint.json) is the unit a downstream consumer loads and drives verbs over.
  • Open vs. closed — a blueprint with unbound (free) numeric knobs is open; one with every knob bound is closed. Different verbs want different states (see each verb below).
  • Family — the set of runs one verb produces over a blueprint (a sweep grid, a Monte-Carlo seed set, a walk-forward window sequence). Families are persisted in a content-addressed store and can be listed, ranked, and reproduced.
  • Axis — one named, sweepable knob of a blueprint (e.g. graph.fast.length), bound with a comma-separated value list.

Running & orchestrating a loaded blueprint

These verbs all take the blueprint file as their first positional argument and drive a family of runs over it. (Each verb also has a legacy built-in form selected by --strategy/--harness instead of a .json path, for the engine's own bundled example strategies — see --help.)

Command Purpose
aura run <bp.json> Run one backtest of a closed blueprint and print its report. An open (free-knob) blueprint is refused with a clean error — bind it, or use sweep.
aura sweep <bp.json> --list-axes Discover the blueprint's open, sweepable knobs. Prints each as <name>:<kind>. Run this first to learn the axis names.
aura sweep <bp.json> --axis <name>=<csv> [--axis …] Run a grid family over the named axes and persist it.
aura mc <bp.json> --seeds <n> Run a Monte-Carlo family of n seeded realizations. Wants a closed blueprint (the inverse of sweep).
aura walkforward <bp.json> --axis <name>=<csv> [--axis …] Run an in-sample-refit walk-forward family — rolling optimize + out-of-sample test across windows, stitched into one verdict + parameter stability. --select chooses the per-window objective.
aura runs families List every persisted family (id, kind, member count).
aura runs family <id> [rank <metric>] List one family's members, optionally ranked best-first by an R metric (e.g. sqn_normalized, expectancy_r).
aura reproduce <family-id> Re-derive every member of a persisted family from the content-addressed store and check it is bit-identical (the C18/C1 determinism guarantee).

Important contract — every open knob is mandatory. On sweep and walkforward, the knobs enumerated by --list-axes are all required: you must supply an --axis for each open knob. There is no default value — pin a knob you don't want to vary with a single-value axis (--axis name=4). Omitting one is a clean error naming the missing knob, not a silent default.

Use aura <cmd> --help for the full data-window (--real/--from/--to), naming (--name/--trace), and selection (--select) flags.

Authoring & introspecting topology

A blueprint is authored declaratively from a JSON op-list: an ordered list of by-identifier construction ops replayed against the standard node vocabulary.

Command Purpose
aura graph build Read an op-list document on stdin, build the blueprint, and print its canonical JSON to stdout (no trailing newline — it is the content-addressed artifact).
aura graph introspect --vocabulary List every node type available to op-lists.
aura graph introspect --node <T> Show one type's input ports, output fields, and param paths (with the bind-value form).
aura graph introspect --unwired Read a partial op-list on stdin and list its still-open interior slots.
aura graph introspect --content-id Read an op-list on stdin and print the SHA-256 content id of the blueprint it would build.
aura graph introspect --identity-id Read an op-list on stdin and print the SHA-256 identity id — the topology's debug-name-blind id, so two documents (or an op-script and a Rust-built blueprint) expressing the same topology print the same id. Combinable with --content-id (both ids, one per line, content id first).

Op-list shape

Each element is one op, tagged by "op". Node params are bound with the typed Scalar form — a tagged, capitalized-kind object: {"I64": 5}, {"F64": 1.5}, {"Bool": true}. A worked example (an SMA-crossover → bias signal):

[
  {"op":"source","role":"price","kind":"F64"},
  {"op":"add","type":"SMA","name":"fast","bind":{"length":{"I64":2}}},
  {"op":"add","type":"SMA","name":"slow","bind":{"length":{"I64":4}}},
  {"op":"add","type":"Sub"},
  {"op":"add","type":"Bias"},
  {"op":"feed","role":"price","into":["fast.series","slow.series"]},
  {"op":"connect","from":"fast.value","to":"sub.lhs"},
  {"op":"connect","from":"slow.value","to":"sub.rhs"},
  {"op":"connect","from":"sub.value","to":"bias.signal"},
  {"op":"expose","from":"bias.bias","as":"bias"}
]

Piping this document into aura graph build emits a blueprint.json you can then feed to run / sweep / mc / walkforward above:

aura graph build < crossover.ops.json > crossover.bp.json
aura sweep crossover.bp.json --list-axes

The op kinds are source, input, add, feed, connect, and expose. See aura graph introspect --node <T> for a type's exact ports and the op-script grammar in the design ledger for the full semantics.

Where to go deeper

  • aura <command> --help — exhaustive, always-current flag grammar.
  • docs/design/INDEX.md — the design ledger: architecture, invariants, the World.
  • docs/glossary.md — canonical terminology (blueprint, family, axis, sweep / Monte-Carlo / walk-forward, R, content-id, …).
S
Description
No description provided
Readme 18 MiB
Languages
Rust 68.9%
JavaScript 24.4%
HTML 6%
Shell 0.6%
CSS 0.1%