affaan-m/ECC · error

minimum win rate must be between 0 and 1

Error message

minimum win rate must be between 0 and 1

What it means

`PromotionPolicy::validate` requires `min_win_rate` to be finite and within the inclusive range 0.0..=1.0, since it represents a fraction of wins. Values like 1.5, -0.1, or NaN are statistically meaningless and are rejected.

Solutions

  1. Express the win rate as a fraction between 0.0 and 1.0 (0.85, not 85) before calling `compare`
  2. If your config uses percentages, divide by 100.0 at load time and validate the range
  3. Use `0.0..=1.0` `contains` checks in your own config loader to fail early with a clear message

Example fix

// before
let policy = PromotionPolicy { min_win_rate: 85.0, .. };
let comparison = policy.compare(&samples)?;
// after
let policy = PromotionPolicy { min_win_rate: 0.85, .. };
let comparison = policy.compare(&samples)?;
Defensive patterns

Strategy: validation

Validate before calling

fn win_rate_is_valid(min_win_rate: f64) -> bool {
    min_win_rate.is_finite() && (0.0..=1.0).contains(&min_win_rate)
}

Type guard

fn fraction_f64(v: f64) -> Option<f64> {
    if v.is_finite() && (0.0..=1.0).contains(&v) { Some(v) } else { None }
}

Try / catch

match policy.compare(&samples) {
    Ok(comparison) => comparison,
    Err(e) if e.to_string().contains("win rate must be between 0 and 1") => {
        eprintln!("min_win_rate out of range (did you pass a percentage?): {e}");
        // retry assuming percentage input
        PromotionPolicy { min_win_rate: policy.min_win_rate / 100.0, ..policy }.compare(&samples)?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Constructing a `PromotionPolicy` with `min_win_rate` outside [0.0, 1.0] (e.g. 1.5 meaning '150%', a negative rate, or NaN) and calling `compare` or `validate`.

Common situations: Users expressing the threshold as a percentage (85 for 85%) instead of a fraction (0.85); copy-pasting thresholds from percent-based tooling; unset/NaN sentinels from config.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/7649881b0433c2e3. Report an issue: GitHub.

Appendix: source

Thrown at ecc2/src/harness_eval.rs:514

    pub passed: bool,
    pub sample_count: usize,
    pub candidate_mean: f64,
    pub baseline_mean: f64,
    pub mean_delta: f64,
    pub win_rate: f64,
    pub failures: Vec<String>,
}

impl PromotionPolicy {
    pub fn validate(self) -> Result<()> {
        if self.min_samples == 0 {
            bail!("minimum samples must be positive");
        }
        if !self.min_mean_delta.is_finite() {
            bail!("minimum mean delta must be finite");
        }
        if !self.min_win_rate.is_finite() || !(0.0..=1.0).contains(&self.min_win_rate) {
            bail!("minimum win rate must be between 0 and 1");
        }
        Ok(())
    }

    pub fn compare(self, samples: &[PairedSample]) -> Result<Comparison> {
        self.validate()?;
        if samples.is_empty() {
            bail!("samples cannot be empty");
        }
        if samples
            .iter()
            .map(|sample| sample.seed)
            .collect::<BTreeSet<_>>()
            .len()
            != samples.len()
        {
            bail!("sample seeds must be unique");
        }

View on GitHub (pinned to 8321021c54)