From fb145f5a151ac62d652ee267c5c2c709cb034af5 Mon Sep 17 00:00:00 2001 From: Brummel Date: Fri, 10 Jul 2026 18:53:01 +0200 Subject: [PATCH] fix(cli): reproduce re-derives the stop regime from the member manifest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reproduce_family_in hardcoded the default StopRule::Vol{3,2.0} at both the param-space probe and the member re-run, so a family minted under a non-default vol-stop (campaign risk-regime cell, or wf/mc/generalize with --stop-length/--stop-k) spuriously reported DIVERGED. New stop_rule_from_params re-derives StopRule::Vol from the manifest's stamped stop_length/stop_k, falling back to the defaults when the keys are absent (pre-stamp members) — the same one-directional widening point_from_params applies to missing manifest params, mirroring campaign_run's stop_rule_for_regime None arm. The stop rides outside the wrapped param space, so point_from_params could never recover it. Verified: RED test green, full workspace suite green (independent mini-verify), clippy -D warnings clean. closes #233 --- crates/aura-cli/src/main.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/aura-cli/src/main.rs b/crates/aura-cli/src/main.rs index 2f0731b..83ae95b 100644 --- a/crates/aura-cli/src/main.rs +++ b/crates/aura-cli/src/main.rs @@ -1031,6 +1031,22 @@ fn point_from_params(space: &[ParamSpec], params: &[(String, Scalar)]) -> Vec StopRule { + let length = params.iter().find(|(n, _)| n == "stop_length").map(|(_, s)| s.as_i64()); + let k = params.iter().find(|(n, _)| n == "stop_k").map(|(_, s)| s.as_f64()); + match (length, k) { + (Some(length), Some(k)) => StopRule::Vol { length, k }, + _ => StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, + } +} + /// Look up a persisted family by id, or exit 1 (unknown id / registry load failure) — /// the single place `reproduce_family` and `reproduce_family_in` resolve a family, so /// the two exit-1 error phrasings can't drift out of sync between the call sites. @@ -1092,8 +1108,8 @@ fn reproduce_family_in( let (tx_ex, _) = mpsc::channel(); let (tx_r, _) = mpsc::channel(); let (tx_req, _) = mpsc::channel(); - let space = - wrap_r(reload(), tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true, SYNTHETIC_PIP_SIZE).param_space(); + let stop = stop_rule_from_params(&stored.manifest.params); + let space = wrap_r(reload(), tx_eq, tx_ex, tx_r, tx_req, stop, true, SYNTHETIC_PIP_SIZE).param_space(); let point = point_from_params(&space, &stored.manifest.params); // A MonteCarlo member carries no tuning params (the params-join is empty), so its // reproduce line would print a BLANK member label; the seed IS its realization @@ -1153,7 +1169,7 @@ fn reproduce_family_in( pip, &hash, env, - StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, + stop, ); outcomes.push((label, rerun.metrics == stored.metrics)); }