refactor: cut the engine's backtest-metrics edge via RunReport<M>

C28 phase 2 (Stratification); realizes item 1 of the deferred #147. The
engine's production surface no longer names a backtest-metric type:

- RunReport becomes generic over its metric payload M; sweep/mc/walkforward/
  blueprint thread the parameter (SweepPoint<M>, SweepFamily<M>, WindowRun<M>,
  WalkForwardResult<M>). RunManifest stays concrete and engine-owned (its
  selection: Option<FamilySelection> embeds the foundation-grade analysis type).
- summarize and the MC assembly (McDraw/McFamily/McAggregate/RBootstrap/
  r_bootstrap/monte_carlo) move to aura-backtest - McAggregate::from_draws reads
  RunMetrics fields by name, so generifying it is the phase-6 metric-vocabulary
  abstraction (#147 item 2), still deferred; wholesale relocation is the honest
  cut. The concrete instantiation lives in aura-backtest as
  `type RunReport = aura_engine::RunReport<RunMetrics>` + sibling aliases.
- the statistics kernel (MetricStats/quantile/resample_block/SplitMix64) moves
  to the aura-analysis foundation; the engine re-imports it (inner->foundation,
  legal) and re-exports it so existing consumers stay source-compatible.

Dependency inversion in one commit: aura-engine drops aura-backtest from
[dependencies] (back to dev-deps for its SimBroker/RunMetrics test fixtures);
aura-backtest gains aura-engine. Cycle-free for lib targets - the cycle closes
only through the engine's dev-dep edge, the pattern aura-vocabulary already
uses. aura-backtest reaches the kernel transitively through the engine
re-export, so no aura-backtest -> aura-analysis edge exists (the C28 ladder
permits backtest -> {core, engine} only). run_indexed / SplitMix64::next_f64
widened pub(crate) -> pub for cross-crate use.

Consumers (registry/campaign/cli/composites/ingest/bench) rewired by import
path only, no call-site logic changed. The c28_layering structural test extends
to the full ladder: aura-analysis (no aura-* deps), aura-engine ⊆ {core,
analysis}, aura-backtest ⊆ {core, engine}.

Behaviour-preserving: 1448/0 tests, clippy -D warnings clean, serde shapes
byte-identical (C18 - RunReport<M> keeps field order manifest,metrics; the
CLI pre-serialized-splice contract unchanged), moved code traceable via git
rename detection. Cycle-introduced broken intra-doc links fixed.

closes #292
This commit is contained in:
2026-07-20 13:25:07 +02:00
parent 94aaa4cde8
commit a56ab7859d
45 changed files with 768 additions and 593 deletions
+26 -21
View File
@@ -2666,26 +2666,27 @@ measurement and backtest instead of baked in R-only — this is #147).
shell", #286).** This contract states the *target*. At HEAD the crates cut by
mechanical role (vocabulary / reductions / documents / orchestration / CLI), not
cleanly by layer, so the layering is realized only partially:
- The dependency *direction* already nearly obeys the rule. The one hard
production violation is the engine's re-export of the backtest metrics —
since the #291 split, `aura-engine → aura-backtest`: `report.rs` re-exports
the R-metrics and the position-event table (`RMetrics`/`RunMetrics`/
`summarize_r`/`r_metrics_from_rs`, `PositionEvent`/`PositionAction`/
`derive_position_events`), and the generic-statistics kernel in `mc.rs`
carries R/bias-typed fields (`McAggregate.bias_sign_flips`, `RBootstrap.e_r`)
inside otherwise domain-free structs. The `aura-engine → aura-analysis` edge
is no longer a violation: post-#291 that crate holds only domain-free
statistics + selection provenance (`FamilySelection` for
`RunManifest.selection`), foundation-grade under this contract.
- **That violation is the exact surface of the deliberately-deferred #147.**
Cutting it cleanly needs the metric genericity (`RunReport<M>` plus abstracting
the registry deflation vocabulary) that #136 ratified *deferring* (user-ratified
2026-06-27: the registry `Metric`/`metric_cmp`/deflation vocabulary "stays in
the registry by design … forcing genericity would be a one-implementor
abstraction", deferred to the World/C21 layer — see the C16 realization note).
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 dependency *direction* now obeys the rule across the engine stack. The
`aura-engine → aura-backtest` production violation is cut (phase 2, #292):
`RunReport` is generic over its metric payload `M` (the engine names no
concrete metric type), the pip/R reductions and the MC assembly (`summarize`,
`McAggregate`/`RBootstrap`/`monte_carlo`) moved to `aura-backtest`, and the
statistics kernel (`MetricStats`/`quantile`/`resample_block`/`SplitMix64`)
moved to the `aura-analysis` foundation. The engine's `[dependencies]` are now
`aura-core` + `aura-analysis` only; the backtest layer instantiates
`M = RunMetrics` (`aura-backtest → aura-engine`, an outer→inner edge). The
ladder direction is enforced for the engine/backtest/analysis rungs by the
structural test (`c28_layering`, seven-row table).
- **#147 split, partially retired (user-ratified 2026-07-20).** Item 1 — the
metric genericity `RunReport<M>` — shipped as phase 2 above (#292). Item 2 —
abstracting the registry `Metric`/`metric_cmp`/deflation vocabulary — stays
deferred: the registry sits in the process column, whose trading-awareness
this contract permits (`aura-registry → aura-research`, column-internal and
legal), and the tree still holds exactly one metric consumer — a measurement
run reports tap names, not metrics. It lifts when measurement supplies its
first deflatable metric (a tap-to-scalar reduction carrying its own null
model, #290); the original one-implementor rationale (#136, user-ratified
2026-06-27) holds until then. See #147 for the full disposition.
- 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`/
@@ -2701,7 +2702,11 @@ cleanly by layer, so the layering is realized only partially:
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
engine's backtest-metrics edge via `RunReport<M>`**done** (#292:
metric-generic run record, the pip/R reductions + MC assembly relocated to
`aura-backtest`, the statistics kernel to `aura-analysis`, dependency
inversion, ladder enforced by the structural test; realizes item 1 of #147);
(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 /