From 50d3db70285aa09909757483d723f0cad5846fc1 Mon Sep 17 00:00:00 2001 From: Brummel Date: Mon, 6 Jul 2026 14:56:16 +0200 Subject: [PATCH] =?UTF-8?q?feat(cli):=20finalize=20the=20risk-regime=20axi?= =?UTF-8?q?s=20=E2=80=94=20ledger=20note=20+=20clippy-clean=20regime=20che?= =?UTF-8?q?ck=20(#210=20T5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The last slice of the risk-regime structural axis. The sugar parity (`translate_sweep` emitting `risk: vec![]`, absent-serializing) and the real-data two-regime e2e landed in the earlier slices (the loop's self-correction and its e2e phase), so this closes the remaining pieces: - design-ledger note: the risk regime realizes the StopRule structural axis at the campaign-document level — kept-separate keying, compared-not-selected (the R-unit argument), the C18 stamp, absent-parity, and the deferred trace gap (#212). - clippy: `validate_campaign`'s regime check reads `k <= 0.0 || k.is_nan()` instead of `!(k > 0.0)` (neg_cmp_op_on_partial_ord), behaviour-identical. Full workspace suite green; clippy clean. refs #210 --- crates/aura-research/src/lib.rs | 5 +++-- docs/design/INDEX.md | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/aura-research/src/lib.rs b/crates/aura-research/src/lib.rs index e10f8a3..41bede2 100644 --- a/crates/aura-research/src/lib.rs +++ b/crates/aura-research/src/lib.rs @@ -766,8 +766,9 @@ pub fn validate_campaign(doc: &CampaignDoc) -> Vec { } for (i, r) in doc.risk.iter().enumerate() { let RiskRegime::Vol { length, k } = r; - // length < 1 catches 0 and negatives; !(k > 0.0) catches k <= 0 AND NaN. - if *length < 1 || !(*k > 0.0) { + // length < 1 catches 0 and negatives; `k <= 0 || NaN` catches a + // non-positive or non-finite multiplier (clippy-clean vs `!(k > 0.0)`). + if *length < 1 || *k <= 0.0 || k.is_nan() { faults.push(DocFault::BadRegime { index: i }); } } diff --git a/docs/design/INDEX.md b/docs/design/INDEX.md index ff3e1bf..8aa9d28 100644 --- a/docs/design/INDEX.md +++ b/docs/design/INDEX.md @@ -938,6 +938,26 @@ dedicated `aura-composites` crate, so `aura-engine`'s runtime dependency stays `aura-core`-only and `aura-std` is an `aura-engine` `[dev-dependencies]` (the graph stays acyclic). +**Realization (2026-07-06 — the risk regime as a structural campaign axis, #210).** +The `StopRule{Fixed,Vol}` structural axis is realized at the campaign-document +level as `CampaignDoc.risk: [RiskRegime]` (a serializable, content-addressable +mirror of the runtime enum — `aura-research`, sole variant `Vol{length,k}`, the +fixed-stop rule additive when needed). It is a **kept-separate** matrix axis, a +peer of instruments and windows: the executor keys the nominee map by +`(strategy, window, regime)`, so generalize aggregates across instruments +*within* a regime, never across regimes. Regimes are therefore **compared** at +presentation, never argmax-**selected** across — a cross-regime E[R] argmax would +compare R-multiples in different R units (the stop defines 1R), so the legacy +verbs' `--stop-length`/`--stop-k` joint stop grid is retired as a campaign +methodology (finding the best regime = the same walk-forward / worst-case-R +validation, run once per regime, and picking the most robust — a comparison, not +a search). Each member manifest stamps its resolved stop (default included), +closing the C18 gap; absent/empty `risk` = one implicit default regime, +absent-serializing for content-id parity. Deferred (documented): regime-aware +**trace** persistence — the trace re-run and cell-key dir naming still assume the +default stop, since `CellRealization` carries no regime (`#212`); the core +run/stamp/generalize path is unaffected. + **Realization (cycle 0066).** SQN is the operational single-number objective for ranking an r-sma sweep family by signal quality — C12 **axis-2 (argmax-metric)** over the C18 family store. `metric_cmp` (`aura-registry`) learns the