diff --git a/crates/aura-cli/src/main.rs b/crates/aura-cli/src/main.rs index aa581f7..bc392e7 100644 --- a/crates/aura-cli/src/main.rs +++ b/crates/aura-cli/src/main.rs @@ -24,7 +24,7 @@ use aura_engine::{ }; use aura_registry::{ check_r_metric, group_families, mc_member_reports, optimize_deflated, - optimize_plateau, rank_by, sweep_member_reports, walkforward_member_reports, FamilyKind, + optimize_plateau, rank_by, sweep_member_reports, walkforward_member_reports, Family, FamilyKind, FamilyMember, Generalization, NameKind, PlateauMode, Registry, RunTraces, DEFLATION_BLOCK_LEN, DEFLATION_N_RESAMPLES, }; @@ -1031,6 +1031,22 @@ fn point_from_params(space: &[ParamSpec], params: &[(String, Scalar)]) -> Vec Family { + let members = reg.load_family_members().unwrap_or_else(|e| { + eprintln!("aura: {e}"); + std::process::exit(1); + }); + group_families(members).into_iter().find(|f| f.id == id).unwrap_or_else(|| { + // reproduce is an action, not a lookup: an unknown id is a hard error (distinct + // from `runs family `'s treat-as-empty exit 0). + eprintln!("aura: no such family '{id}'"); + std::process::exit(1); + }) +} + /// Re-derive every member of a persisted sweep family from the content-addressed store /// and compare to the stored result, against an explicit registry (testable seam). fn reproduce_family_in( @@ -1039,18 +1055,8 @@ fn reproduce_family_in( data: &DataSource, env: &project::Env, ) -> ReproduceReport { - let members = reg.load_family_members().unwrap_or_else(|e| { - eprintln!("aura: {e}"); - std::process::exit(1); - }); - let Some(family) = group_families(members).into_iter().find(|f| f.id == id) else { - // reproduce is an action, not a lookup: an unknown id is a hard error (distinct - // from `runs family `'s treat-as-empty exit 0). - eprintln!("aura: no such family '{id}'"); - std::process::exit(1); - }; + let family = load_family_or_exit(reg, id); let pip = data.pip_size(); - let window = data.full_window(env); let mut outcomes = Vec::new(); for member in &family.members { let stored = &member.report; @@ -1123,7 +1129,19 @@ fn reproduce_family_in( let w = window_of(&s).expect("non-empty OOS window"); (s, w) } - _ => (data.run_sources(env), window), + // Sweep / plain-run members: a Real source reopens the exact per-member + // window the manifest recorded, the same `windowed_sources` loader + // WalkForward uses above (and `CliMemberRunner` uses at mint time, #229) + // — never a fresh full-archive probe, which need not match the window the + // family was minted over. Synthetic keeps the pre-#229 full-window path + // (byte-identical: `data.full_window` is a pure, no-IO computation). + _ => match data { + DataSource::Real { .. } => { + let (from, to) = stored.manifest.window; + (data.windowed_sources(from, to, env), (from, to)) + } + DataSource::Synthetic => (data.run_sources(env), data.full_window(env)), + }, }; let rerun = run_blueprint_member( reload(), @@ -1144,10 +1162,24 @@ fn reproduce_family_in( /// `aura reproduce `: re-derive a persisted sweep family from the /// content-addressed blueprint store and verify each member reproduces bit-identically -/// (C18 "re-derives full results on demand"). Synthetic data this cycle (deterministic); -/// recorded-dataset reproduction rides the DataServer seam (#124). +/// (C18 "re-derives full results on demand"). The data source is reconstructed from +/// the family's own manifest (#229) — a hardcoded `DataSource::Synthetic` here would +/// re-derive a real-data family over the wrong stream; see `reproduce_family_in`'s +/// per-member window loader for how the reconstructed source is actually used. fn reproduce_family(id: &str, env: &project::Env) { - let rep = reproduce_family_in(&env.registry(), id, &DataSource::Synthetic, env); + let reg = env.registry(); + let family = load_family_or_exit(®, id); + // Reconstruct the DataSource the family was minted over: `None` instrument + // (every synthetic-family member, pre-#229 lines) stays the built-in synthetic + // stream; a real instrument reopens the same local archive `--real` runs use, + // via the same named-data refusal (exit 1) on a missing sidecar/archive. + let data = match family.members.first().and_then(|m| m.report.manifest.instrument.clone()) { + None => DataSource::Synthetic, + Some(symbol) => { + DataSource::from_choice(DataChoice::Real { symbol, from_ms: None, to_ms: None }, env) + } + }; + let rep = reproduce_family_in(®, id, &data, env); let total = rep.outcomes.len(); let ok = rep.outcomes.iter().filter(|(_, b)| *b).count(); for (label, identical) in &rep.outcomes {