From 20511d5d5c645a5c006607ab11cec56075cb24e0 Mon Sep 17 00:00:00 2001 From: Brummel Date: Wed, 17 Jun 2026 16:09:36 +0200 Subject: [PATCH] =?UTF-8?q?test:=20red=20for=20#83=20=E2=80=94=20Registry:?= =?UTF-8?q?:load=20must=20read=20a=20legacy=20pre-0047=20bare-float=20para?= =?UTF-8?q?ms=20line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RED test pinning the real defect of bug F5 (surfaced by the milestone "The World, part II" fieldtest). Registry::load cannot deserialize a runs.jsonl line written before the cycle-0047 typed-Scalar params migration, where each param value is a bare JSON float (e.g. ["sma_cross.fast",2.0]) rather than the tagged {"F64":2.0}. The test feeds a minimal autonomous legacy line and asserts it loads — the bare float read back via the documented f64 coercion — instead of erroring at the first param. Fails RED at the diagnosed cause (Parse "expected value" on the bare float). GREEN side (back-compat read, no change to the typed-Scalar forward format) follows. refs #83 --- crates/aura-registry/src/lib.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/aura-registry/src/lib.rs b/crates/aura-registry/src/lib.rs index 002f25a..d847202 100644 --- a/crates/aura-registry/src/lib.rs +++ b/crates/aura-registry/src/lib.rs @@ -236,6 +236,31 @@ mod tests { let _ = fs::remove_file(&path); } + /// A `runs.jsonl` line written before the cycle-0047 typed-`Scalar` params + /// migration carries each param value as a **bare JSON number** (`2.0`), + /// where the current format tags it (`{"F64":2.0}`). `load()` is the durable + /// C18 read-path and must stay back-compatible across that wire-shape change: + /// a legacy bare-float line must still load, the bare float read back as the + /// documented `f64` coercion — not erroring at the first param. (The current + /// typed shape is already covered by the round-trip test.) + #[test] + fn load_reads_a_legacy_bare_float_params_line() { + let path = temp_path("legacy_bare_float"); + let _ = fs::remove_file(&path); + // An autonomous, minimal legacy line: a single bare-float param is the + // whole trigger (the rest of the RunReport is in the current shape). This + // mirrors the real pre-0047 store, where the first param `2.0` is where + // the typed-Scalar deserializer first chokes. + let legacy = r#"{"manifest":{"commit":"c","params":[["sma_cross.fast",2.0]],"window":[1,2],"seed":0,"broker":"b"},"metrics":{"total_pips":0.0,"max_drawdown":0.0,"exposure_sign_flips":0}}"#; + fs::write(&path, format!("{legacy}\n")).expect("write legacy line"); + let reg = Registry::open(&path); + let reports = reg.load().expect("a legacy bare-float params line must still load"); + assert_eq!(reports.len(), 1); + // the bare float reads back as the documented f64 coercion + assert_eq!(reports[0].manifest.params, vec![("sma_cross.fast".to_string(), Scalar::f64(2.0))]); + let _ = fs::remove_file(&path); + } + #[test] fn rank_by_orders_best_first_per_metric() { let reports = vec![