From 70a045cde9529eab6d9bbcb737866eadb9415aac Mon Sep 17 00:00:00 2001 From: Brummel Date: Thu, 9 Jul 2026 10:01:33 +0200 Subject: [PATCH] test: red for the false C1 refusal on non-default regime trace persist Two RED tests pinning the lossy record boundary: CellRealization carries no regime, so persist_campaign_traces' drift-alarm re-run hardcodes the default vol-stop and false-fails C1 for any campaign with a non-default risk regime + persist taps (facet A), and campaign_cell_key has no regime discriminator so two regimes' traces would collide in one dir (facet B, masked by A's refusal today). refs #219, refs #212 --- crates/aura-cli/tests/research_docs.rs | 177 +++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/crates/aura-cli/tests/research_docs.rs b/crates/aura-cli/tests/research_docs.rs index 039c293..fae0e18 100644 --- a/crates/aura-cli/tests/research_docs.rs +++ b/crates/aura-cli/tests/research_docs.rs @@ -1897,6 +1897,183 @@ fn campaign_run_real_e2e_two_regimes_each_stamp_their_own_stop() { expect_for("-r1-", 8, 1.2); } +/// RED (#219 / #212): the campaign trace-persist re-run must reproduce the +/// nominee it recorded, INCLUDING when the cell ran under a non-default risk +/// regime. `run_blueprint_member` stamps the regime-resolved stop into the +/// member manifest (`stop_length`/`stop_k`), but `persist_campaign_traces` +/// rebuilds the re-run's `point` only from the SIGNAL blueprint's param space +/// (the SMA lengths) and hardcodes the DEFAULT `Vol { R_SMA_STOP_LENGTH, +/// R_SMA_STOP_K }` (3, 2.0) for the stop (campaign_run.rs). For a non-default +/// regime the re-run's stop differs from the recorded run's stop, its metrics +/// diverge, and the C1 drift alarm returns a FALSE "trace re-run diverged from +/// the recorded nominee (C1 violation)" refusal — exit 1 on a run that is in +/// fact perfectly deterministic. The record boundary (`CellRealization`) drops +/// the regime; the fix threads it through so the re-run binds the cell's OWN +/// stop. Every other persist e2e in this file is regime-less (default risk), +/// which is exactly why the bug shipped unnoticed. Gated on the local GER40 +/// archive like its siblings; skips on a data-less host. +#[test] +fn campaign_persist_non_default_regime_does_not_false_fail_c1() { + let _fixture = project_lock(); + let dir = built_project(); + let runs_dir = dir.join("runs"); + std::fs::remove_dir_all(&runs_dir).ok(); + let _cleanup = ScratchGuard(vec![ + ScratchPath::Dir(runs_dir.clone()), + ScratchPath::File(dir.join("regime-persist.process.json")), + ScratchPath::File(dir.join("regime-persist.campaign.json")), + ]); + let bp_id = seed_blueprint(dir, "campaign-persist-regime-seed"); + let proc_id = + register_process_doc(dir, "regime-persist.process.json", SWEEP_ONLY_PROCESS_DOC); + let base = campaign_doc_json( + &bp_id, + &proc_id, + (1725148800000, 1727740799999), + "\"equity\", \"r_equity\"", + "\"family_table\"", + ); + // A non-default regime: length != 3 or k != 2.0. Vol { 5, 3.0 } is a 50% + // wider stop over a longer ATR window — its exits, R rows, and metrics + // differ from the default the persist re-run hardcodes. + let with_regime = base.replacen( + "\"seed\": 7,", + "\"seed\": 7,\n \"risk\": [ { \"vol\": { \"length\": 5, \"k\": 3.0 } } ],", + 1, + ); + assert_ne!(with_regime, base, "replacen must actually match the fixture's seed field"); + write_doc(dir, "regime-persist.campaign.json", &with_regime); + let (out, code) = run_code_in(dir, &["campaign", "run", "regime-persist.campaign.json"]); + + // Skip on a data-less machine: the member-data refusal, never a panic. + if code == Some(1) + && (out.contains("no recorded geometry") || out.contains("no data for instrument")) + { + eprintln!("skip: no local GER40 data for the campaign regime-persist e2e"); + return; + } + + // The symptom, pinned exactly: the persist re-run hardcodes the default + // stop and false-fails the C1 drift alarm for the non-default regime. + assert!( + !out.contains("trace re-run diverged from the recorded nominee (C1 violation)"), + "the persist re-run must bind the cell's own regime stop, not false-fail C1: {out}" + ); + assert_eq!( + code, + Some(0), + "a deterministic non-default-regime campaign persists cleanly: {out}" + ); + + // The nominee's taps actually landed (not merely that the refusal was + // suppressed): traces///equity.json exists. + let record_line = out + .lines() + .find(|l| l.starts_with("{\"campaign_run\":")) + .expect("the always-on final campaign_run line"); + let v: serde_json::Value = + serde_json::from_str(record_line).expect("campaign_run line parses as JSON"); + let trace_name = v["campaign_run"]["trace_name"] + .as_str() + .expect("persist_taps non-empty => the record carries trace_name"); + let cell_key = format!("{}-GER40-w0", &bp_id[..8]); + let cell_dir = runs_dir.join("traces").join(trace_name).join(&cell_key); + assert!( + cell_dir.join("equity.json").is_file(), + "the non-default-regime nominee's equity tap persists at {}", + cell_dir.display() + ); +} + +/// RED (#212 — the trace-dir collision facet of the same #219 record gap): two +/// risk regimes over the SAME (strategy, instrument, window) cell must persist +/// their traces into DISTINCT directories. `campaign_cell_key` names dirs +/// `strategy8-instrument-w{window_ordinal}` with NO regime discriminator +/// (campaign_run.rs), so both regimes' nominees resolve to the identical +/// `strategy8-GER40-w0` member dir and the second write clobbers the first. +/// NOTE (masking): today this fails EARLIER — at the same false C1 refusal as +/// its sibling above, because the persist re-run's hardcoded default stop +/// diverges from each non-default regime's recorded nominee. Once the regime is +/// threaded so the re-run stops false-failing, THIS assertion (two distinct +/// on-disk trace dirs, one per regime) becomes the live guard that the cell key +/// gained its `-r{ordinal}` discriminator — without it the two regimes collide +/// into one dir. Gated on the local GER40 archive; skips on a data-less host. +#[test] +fn campaign_persist_two_regimes_land_in_distinct_trace_dirs() { + let _fixture = project_lock(); + let dir = built_project(); + let runs_dir = dir.join("runs"); + std::fs::remove_dir_all(&runs_dir).ok(); + let _cleanup = ScratchGuard(vec![ + ScratchPath::Dir(runs_dir.clone()), + ScratchPath::File(dir.join("tworegimes-persist.process.json")), + ScratchPath::File(dir.join("tworegimes-persist.campaign.json")), + ]); + let bp_id = seed_blueprint(dir, "campaign-persist-two-regimes-seed"); + let proc_id = register_process_doc( + dir, + "tworegimes-persist.process.json", + SWEEP_ONLY_PROCESS_DOC, + ); + let base = campaign_doc_json( + &bp_id, + &proc_id, + (1725148800000, 1727740799999), + "\"equity\"", + "\"family_table\"", + ); + let with_regimes = base.replacen( + "\"seed\": 7,", + "\"seed\": 7,\n \"risk\": [ { \"vol\": { \"length\": 5, \"k\": 3.0 } }, \ + { \"vol\": { \"length\": 8, \"k\": 1.2 } } ],", + 1, + ); + assert_ne!(with_regimes, base, "replacen must actually match the fixture's seed field"); + write_doc(dir, "tworegimes-persist.campaign.json", &with_regimes); + let (out, code) = run_code_in(dir, &["campaign", "run", "tworegimes-persist.campaign.json"]); + + // Skip on a data-less machine: the member-data refusal, never a panic. + if code == Some(1) + && (out.contains("no recorded geometry") || out.contains("no data for instrument")) + { + eprintln!("skip: no local GER40 data for the two-regime persist e2e"); + return; + } + + // Precondition (facet A): neither regime's persist re-run may false-fail C1. + assert!( + !out.contains("trace re-run diverged from the recorded nominee (C1 violation)"), + "the persist re-run must bind each cell's own regime stop, not false-fail C1: {out}" + ); + assert_eq!(code, Some(0), "a two-regime campaign persists both cells cleanly: {out}"); + + // The guard (facet B): each regime's equity tap lands in its OWN dir under + // traces//, so there are TWO distinct tap-bearing dirs, not one. + let record_line = out + .lines() + .find(|l| l.starts_with("{\"campaign_run\":")) + .expect("the always-on final campaign_run line"); + let v: serde_json::Value = + serde_json::from_str(record_line).expect("campaign_run line parses as JSON"); + let trace_name = v["campaign_run"]["trace_name"] + .as_str() + .expect("persist_taps non-empty => the record carries trace_name"); + let family_dir = runs_dir.join("traces").join(trace_name); + let mut tap_dirs: Vec = std::fs::read_dir(&family_dir) + .expect("trace family dir exists") + .filter_map(|e| e.ok()) + .filter(|e| e.path().join("equity.json").is_file()) + .map(|e| e.file_name().to_string_lossy().into_owned()) + .collect(); + tap_dirs.sort(); + tap_dirs.dedup(); + assert_eq!( + tap_dirs.len(), + 2, + "two regimes over one cell persist into two distinct trace dirs, got {tap_dirs:?}" + ); +} + /// Property: an UNPRODUCIBLE tap requested alongside a producible one degrades /// gracefully, never a crash or a silently-dropped whole request. `net_r_equity` /// is in the closed tap vocabulary (`validate_campaign` accepts it) but has no