test(cli): pin the exact walkforward grade — byte-identity anchor (#210)
The third verb dissolution (walkforward) reroutes the inline per-window IS-refit (`walkforward_family` -> `select_winner` -> OOS run -> stitch/pool) through the campaign `std::walk_forward` stage. Two summary fields have no campaign equivalent today: `stitched_total_pips` (the runner discards the raw OOS pip curve, `oos_equity: vec![]`) and pooled `oos_r` (only a following `std::monte_carlo` stage produces it). Before the executor work that closes those gaps, this pins the EXACT current grade of a fixed 2025 GER40 invocation so the dissolution must reproduce it byte-for-byte (the acceptance gate). The grid is deliberately multi-point (fast 3,5 x slow 12,20): it makes the per-window winner selection non-degenerate (`param_stability` varies across the 9 windows), so a winner-pick divergence between the inline and campaign refit cannot ship green — the same gap the generalize anchor closed for its sibling shape-only test. Deterministic (C1); gated on the local GER40 archive, skips cleanly on a data refusal. refs #210
This commit is contained in:
@@ -3637,6 +3637,64 @@ fn generalize_real_e2e_pins_the_exact_current_grade() {
|
||||
assert_eq!(per[1][1].as_f64(), Some(0.005795903617609842), "USDJPY expectancy R: {grade_line}");
|
||||
}
|
||||
|
||||
/// Characterization pin (byte-identity anchor for the walkforward dissolution,
|
||||
/// #210). The current `aura walkforward` runs its per-window IS-refit inline
|
||||
/// (`walkforward_family` -> `select_winner` -> OOS run -> stitch/pool); the
|
||||
/// dissolution reroutes the same rolling IS-sweep -> OOS-run -> deflation through
|
||||
/// the campaign `std::walk_forward` stage, and must retain the OOS pip curve the
|
||||
/// campaign runner currently discards (`oos_equity: vec![]`) to reproduce
|
||||
/// `stitched_total_pips`, plus reconstruct pooled `oos_r`. The multi-point grid
|
||||
/// (fast 3,5 x slow 12,20) makes the per-window winner selection non-degenerate --
|
||||
/// `param_stability` varies across windows -- so a winner-pick divergence between
|
||||
/// the inline and campaign refit cannot ship green. This pins the EXACT current
|
||||
/// grade of the identical invocation over a fixed 2025 GER40 window; after the
|
||||
/// dissolution the same command must reproduce these bytes (the acceptance gate).
|
||||
/// Gated on the shared GER40 archive; skips cleanly on a data refusal.
|
||||
#[test]
|
||||
fn walkforward_real_e2e_pins_the_exact_current_grade() {
|
||||
const FROM_MS: &str = "1735689600000";
|
||||
const TO_MS: &str = "1767225599000";
|
||||
let cwd = temp_cwd("walkforward-exact-grade");
|
||||
let out = std::process::Command::new(env!("CARGO_BIN_EXE_aura"))
|
||||
.args([
|
||||
"walkforward", "--strategy", "r-sma", "--real", "GER40",
|
||||
"--fast", "3,5", "--slow", "12,20", "--stop-length", "14", "--stop-k", "2.0",
|
||||
"--from", FROM_MS, "--to", TO_MS,
|
||||
])
|
||||
.current_dir(&cwd)
|
||||
.output()
|
||||
.expect("spawn aura");
|
||||
if out.status.code() == Some(1) {
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(
|
||||
stderr.contains("no local data") || stderr.contains("no recorded geometry"),
|
||||
"exit 1 must be a data refusal, got: {stderr}"
|
||||
);
|
||||
eprintln!("skip: no local GER40 data");
|
||||
return;
|
||||
}
|
||||
assert_eq!(out.status.code(), Some(0), "exit: {:?}", out.status);
|
||||
let stdout = String::from_utf8(out.stdout).expect("utf-8 stdout");
|
||||
let grade_line = stdout
|
||||
.lines()
|
||||
.find(|l| l.starts_with("{\"walkforward\":"))
|
||||
.unwrap_or_else(|| panic!("the walkforward summary line: {stdout}"));
|
||||
let v: serde_json::Value = serde_json::from_str(grade_line).expect("summary line parses as JSON");
|
||||
let wf = &v["walkforward"];
|
||||
assert_eq!(wf["windows"].as_u64(), Some(9), "window count: {grade_line}");
|
||||
// EXACT floats -- the byte-identity anchor the dissolution must preserve.
|
||||
// stitched_total_pips is retained only if the campaign runner keeps the OOS curve.
|
||||
assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-10398606.666650848), "stitched OOS pips: {grade_line}");
|
||||
let r = &wf["oos_r"];
|
||||
assert_eq!(r["n_trades"].as_u64(), Some(20681), "pooled OOS trade count: {grade_line}");
|
||||
assert_eq!(r["expectancy_r"].as_f64(), Some(-0.002397100685333715), "pooled OOS expectancy R: {grade_line}");
|
||||
// param_stability varies across windows -> the per-window IS-refit picks
|
||||
// different winners; pinning the means locks the winner-selection equivalence.
|
||||
let ps = wf["param_stability"].as_array().expect("param_stability is an array");
|
||||
assert_eq!(ps[0]["mean"].as_f64(), Some(3.888888888888889), "fast-MA refit mean: {grade_line}");
|
||||
assert_eq!(ps[1]["mean"].as_f64(), Some(17.333333333333332), "slow-MA refit mean: {grade_line}");
|
||||
}
|
||||
|
||||
/// Property: `aura generalize` is now thin sugar over the one campaign path — a
|
||||
/// successful run durably auto-registers exactly one generated process document,
|
||||
/// one generated campaign document (carrying the `--name` handle and the stop as
|
||||
|
||||
Reference in New Issue
Block a user