refactor: split aura-analysis into statistics and backtest metrics

C28 phase 5 (Stratification): the backtest reductions - RunMetrics, RMetrics,
summarize_r, r_metrics_from_rs, and the position-event table - move verbatim
into aura-backtest::metrics, beside the position_management producer whose
record layout they read (the r_col/cost_col lockstep contract is now
intra-crate; its stale "aura-std" comment corrected). aura-analysis is reduced
to the domain-free half: the multiple-comparison hurdle math (inv_norm_cdf,
expected_max_of_normals) and the selection-provenance types
(FamilySelection/SelectionMode - kept beside the statistics so
RunManifest.selection embeds a foundation-grade type), [dependencies] = serde
only.

The engine re-export surface is name-unchanged (report.rs re-imports from both
crates), so no indirect consumer needed a source edit; aura-backtest moves from
aura-engine's dev-dependencies into [dependencies] as a commented TRANSIENT
widening of the C28 violation, removed by the phase-2 edge cut on this branch.
The campaign drift guard imports its pinned types from their new source
crates. Behaviour-preserving: 1448/0 tests, clippy -D warnings clean, serde
shapes byte-identical (C18), moved code traceable via git copy detection.

closes #291
This commit is contained in:
2026-07-20 12:23:17 +02:00
parent b39fd63396
commit 94aaa4cde8
11 changed files with 1140 additions and 1093 deletions
+18 -12
View File
@@ -2667,14 +2667,16 @@ 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 `aura-engine → aura-analysis`: `report.rs:20`
re-exports the R-metrics, the position-event table, the hurdle math, and the
selection-provenance types (`RMetrics`/`RunMetrics`/`summarize_r`/
`r_metrics_from_rs`, `PositionEvent`/`PositionAction`/`derive_position_events`,
`inv_norm_cdf`/`expected_max_of_normals`, `FamilySelection`/`SelectionMode`),
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.
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
@@ -2689,9 +2691,11 @@ cleanly by layer, so the layering is realized only partially:
`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
the closed node roster moved to `aura-vocabulary`. The `aura-analysis`
interweave is resolved (phase 5, #291): the backtest reductions live in
`aura-backtest::metrics` beside their `position_management` producer, and
`aura-analysis` is reduced to domain-free statistics + selection provenance
(`[dependencies]` = serde only). 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.
@@ -2703,7 +2707,9 @@ cleanly by layer, so the layering is realized only partially:
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)
(5) split `aura-analysis` into generic statistics and backtest metrics
**done** (#291: metrics moved to `aura-backtest::metrics`, `aura-analysis`
reduced to the domain-free half, engine re-export surface name-unchanged); (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.