test: red for the enumerated family id rejected by load_family (#298)

Registry::load_family_members() exposes the bare name factor while
aura_runner::reproduce::load_family exact-matches only the derived C18
handle '{family}-{run}' — the natural list-then-reproduce workflow
dead-ends on its first attempt (found by the #295 fieldtest; predates
the extraction byte-identically). The test pins: the enumerated
identity of an unambiguous single-run family resolves through
load_family to the same family the canonical handle names.

refs #298
This commit is contained in:
2026-07-21 07:18:59 +02:00
parent 9df217d868
commit 78e68e6002
+66
View File
@@ -232,3 +232,69 @@ pub fn reproduce_family(id: &str, env: &Env) -> Result<(), RunnerError> {
}
Ok(())
}
#[cfg(test)]
mod tests {
use aura_backtest::{RunMetrics, RunReport};
use aura_core::{Scalar, Timestamp};
use aura_engine::RunManifest;
use aura_registry::{FamilyKind, Registry};
use super::load_family;
/// A registry over a fresh per-test directory (the #258 tag-keyed pattern:
/// fixed name under the build-tree tmp anchor, pre-create wipe).
fn temp_registry(tag: &str) -> Registry {
let dir = std::path::Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../../target/tmp"))
.join(format!("aura-runner-reproduce-{tag}"));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).expect("create temp registry dir");
Registry::open(dir.join("runs.jsonl"))
}
/// One minimal persisted member (the aura-registry test fixture shape).
fn minimal_report() -> RunReport {
RunReport {
manifest: RunManifest {
commit: "c".to_string(),
params: vec![("p".to_string(), Scalar::f64(1.0))],
defaults: vec![],
window: (Timestamp(1), Timestamp(2)),
seed: 0,
broker: "b".to_string(),
selection: None,
instrument: None,
topology_hash: None,
project: None,
},
metrics: RunMetrics { total_pips: 1.0, max_drawdown: 0.5, bias_sign_flips: 0, r: None },
}
}
/// One id vocabulary across enumeration and reproduction (C18, #298): the
/// family-identity string a consumer lifts off the registry's own member
/// enumeration (`FamilyRunRecord.family`) resolves through the reproduce
/// lookup when it is unambiguous (a single stored run for the name), and
/// reaches the same family the canonical derived handle
/// (`"{family}-{run}"`, C18) names. Today the lookup exact-matches the
/// derived handle only, so the natural list-then-reproduce library
/// workflow dead-ends on `no such family`.
///
/// Deliberately NOT pinned here: the ambiguous case (a name with more
/// than one stored run) and name/handle collision precedence — those
/// semantics are the fix's to settle (refuse-don't-guess).
#[test]
fn load_family_accepts_the_enumerated_family_identity() {
let reg = temp_registry("enumerated-id");
reg.append_family("f", FamilyKind::Sweep, &[minimal_report()]).expect("append family");
let members = reg.load_family_members().expect("enumerate members");
let enumerated = members[0].family.clone();
let canonical = members[0].family_id();
let family = load_family(&reg, &enumerated).unwrap_or_else(|e| {
panic!("the enumerated family identity '{enumerated}' must resolve: {}", e.message)
});
assert_eq!(family.id, canonical);
}
}