use std::collections::HashMap;
use std::path::Path;
use firstpass_core::{Attempt, Config as RoutingConfig, DeferredVerdict, TaskKind, Trace, Verdict};
use crate::calibrate::gate_score;
use crate::store::{self, StoreError};
#[derive(Debug)]
pub struct CandidatePolicy {
pub ladder: Vec<String>,
pub serve_threshold: Option<f64>,
}
impl CandidatePolicy {
pub fn from_toml(toml: &str) -> Result<Self, String> {
let config = RoutingConfig::parse(toml).map_err(|e| e.to_string())?;
let ladder = config
.routes
.into_iter()
.next()
.map(|r| r.ladder)
.unwrap_or_default();
Ok(Self {
ladder,
serve_threshold: config.escalation.serve_threshold,
})
}
}
fn would_serve(attempt: &Attempt, policy: &CandidatePolicy) -> bool {
match policy.serve_threshold {
Some(t) => gate_score(&attempt.gates, attempt.verdict) >= t,
None => attempt.verdict == Verdict::Pass,
}
}
fn attempt_cost(a: &Attempt) -> f64 {
a.cost_usd + a.gates.iter().map(|g| g.cost_usd).sum::<f64>()
}
enum ReplayResult {
Unevaluable,
Evaluated {
cost: f64,
served_model: Option<String>,
logged_served_model: Option<String>,
},
}
fn replay_trace(trace: &Trace, policy: &CandidatePolicy) -> ReplayResult {
let logged_served_model = trace.final_.served_rung.and_then(|rung| {
trace
.attempts
.iter()
.find(|a| a.rung == rung)
.map(|a| a.model.clone())
});
let mut total_cost = 0.0f64;
let mut served_model: Option<String> = None;
for model in &policy.ladder {
let Some(attempt) = trace.attempts.iter().find(|a| &a.model == model) else {
return ReplayResult::Unevaluable;
};
total_cost += attempt_cost(attempt);
if would_serve(attempt, policy) {
served_model = Some(model.clone());
break;
}
}
ReplayResult::Evaluated {
cost: total_cost,
served_model,
logged_served_model,
}
}
fn splitmix64(state: &mut u64) -> u64 {
*state = state.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = *state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
#[inline]
fn rand_usize(rng: &mut u64, n: usize) -> usize {
(splitmix64(rng) % n as u64) as usize
}
fn bootstrap_mean_ci(values: &[f64], n_resamples: usize, seed: u64) -> (f64, f64) {
if values.is_empty() {
return (0.0, 0.0);
}
let n = values.len();
let mut rng = seed;
let mut means: Vec<f64> = (0..n_resamples)
.map(|_| {
let s: f64 = (0..n).map(|_| values[rand_usize(&mut rng, n)]).sum();
s / n as f64
})
.collect();
means.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let lo_idx = (n_resamples as f64 * 0.025) as usize;
let hi_idx = ((n_resamples as f64 * 0.975) as usize).min(n_resamples - 1);
(means[lo_idx], means[hi_idx])
}
fn bootstrap_failure_ci(correct: &[bool], n_resamples: usize, seed: u64) -> (f64, f64) {
if correct.is_empty() {
return (0.0, 0.0);
}
let n = correct.len();
let mut rng = seed;
let mut rates: Vec<f64> = (0..n_resamples)
.map(|_| {
let fails = (0..n).filter(|_| !correct[rand_usize(&mut rng, n)]).count();
fails as f64 / n as f64
})
.collect();
rates.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let lo_idx = (n_resamples as f64 * 0.025) as usize;
let hi_idx = ((n_resamples as f64 * 0.975) as usize).min(n_resamples - 1);
(rates[lo_idx], rates[hi_idx])
}
#[derive(Debug, Clone)]
pub struct OpeReport {
pub n_traces: usize,
pub n_evaluable: usize,
pub coverage: f64,
pub est_cost_per_request: f64,
pub logged_cost_per_request: f64,
pub est_served_failure: Option<f64>,
pub n_correctness_known: usize,
pub escalation_rate: f64,
pub ci_cost: (f64, f64),
pub ci_served_failure: Option<(f64, f64)>,
}
impl OpeReport {
#[must_use]
pub fn render(&self) -> String {
let mut out = format!(
"traces: {n_traces} evaluable: {n_evaluable} coverage: {cov:.3}\n\
n_correctness_known: {n_known}\n\
est cost/request: ${est:.6} (logged: ${logged:.6})\n\
cost CI [2.5%, 97.5%]: [${clo:.6}, ${chi:.6}]\n\
escalation rate: {esc:.4}\n",
n_traces = self.n_traces,
n_evaluable = self.n_evaluable,
cov = self.coverage,
n_known = self.n_correctness_known,
est = self.est_cost_per_request,
logged = self.logged_cost_per_request,
clo = self.ci_cost.0,
chi = self.ci_cost.1,
esc = self.escalation_rate,
);
match self.est_served_failure {
Some(f) => {
let (lo, hi) = self.ci_served_failure.unwrap_or((f, f));
out.push_str(&format!(
"est served-failure: {f:.4} CI [{lo:.4}, {hi:.4}]\n"
));
}
None => {
out.push_str(
"est served-failure: n/a (no deferred feedback on same-rung evaluable traces)\n",
);
}
}
out.push_str(
"\nreplay of logged outcomes (direct method); \
rungs never logged are not guessed — see coverage.\n",
);
out
}
}
struct EvalPoint {
candidate_cost: f64,
logged_cost: f64,
correctness: Option<bool>,
escalated: bool,
}
fn build_report(n_traces: usize, points: Vec<EvalPoint>) -> OpeReport {
let n_evaluable = points.len();
let coverage = if n_traces == 0 {
1.0
} else {
n_evaluable as f64 / n_traces as f64
};
if points.is_empty() {
return OpeReport {
n_traces,
n_evaluable: 0,
coverage,
est_cost_per_request: 0.0,
logged_cost_per_request: 0.0,
est_served_failure: None,
n_correctness_known: 0,
escalation_rate: 0.0,
ci_cost: (0.0, 0.0),
ci_served_failure: None,
};
}
let est_cost = mean(&points, |p| p.candidate_cost);
let logged_cost = mean(&points, |p| p.logged_cost);
let escalation_rate = points.iter().filter(|p| p.escalated).count() as f64 / n_evaluable as f64;
let known: Vec<bool> = points.iter().filter_map(|p| p.correctness).collect();
let n_correctness_known = known.len();
let est_served_failure = if known.is_empty() {
None
} else {
Some(known.iter().filter(|&&c| !c).count() as f64 / known.len() as f64)
};
let costs: Vec<f64> = points.iter().map(|p| p.candidate_cost).collect();
let ci_cost = bootstrap_mean_ci(&costs, 1000, 42);
let ci_served_failure = if known.is_empty() {
None
} else {
Some(bootstrap_failure_ci(&known, 1000, 43))
};
OpeReport {
n_traces,
n_evaluable,
coverage,
est_cost_per_request: est_cost,
logged_cost_per_request: logged_cost,
est_served_failure,
n_correctness_known,
escalation_rate,
ci_cost,
ci_served_failure,
}
}
fn mean(points: &[EvalPoint], f: impl Fn(&EvalPoint) -> f64) -> f64 {
if points.is_empty() {
return 0.0;
}
points.iter().map(f).sum::<f64>() / points.len() as f64
}
pub fn ope_from_store(
db_path: impl AsRef<Path>,
tenant: &str,
policy: &CandidatePolicy,
) -> Result<OpeReport, StoreError> {
let traces = store::load_tenant_traces(&db_path, tenant).unwrap_or_default();
let n_traces = traces.len();
let mut points: Vec<EvalPoint> = Vec::with_capacity(n_traces);
for trace in &traces {
let deferred = store::load_deferred(&db_path, &trace.trace_id.to_string())?;
let replay = replay_trace(trace, policy);
let ReplayResult::Evaluated {
cost,
served_model,
logged_served_model,
} = replay
else {
continue; };
let correctness = match (&served_model, &logged_served_model) {
(Some(cm), Some(lm)) if cm == lm => deferred
.last()
.map(|dv: &DeferredVerdict| dv.verdict == Verdict::Pass),
_ => None,
};
let first_model = policy.ladder.first();
let escalated = match (&served_model, first_model) {
(Some(m), Some(first)) => m != first,
(None, Some(_)) => true, _ => false,
};
points.push(EvalPoint {
candidate_cost: cost,
logged_cost: trace.final_.total_cost_usd,
correctness,
escalated,
});
}
Ok(build_report(n_traces, points))
}
#[derive(Debug, Clone)]
pub struct IpsReport {
pub n_traces: usize,
pub n_with_propensity: usize,
pub candidate_start_rung: u32,
pub ips_cost: f64,
pub snips_cost: f64,
pub ess: f64,
pub ci_ips_cost: (f64, f64),
pub ips_served_failure: Option<f64>,
pub snips_served_failure: Option<f64>,
pub n_correctness_known: usize,
pub ci_ips_served_failure: Option<(f64, f64)>,
pub dr_cost: f64,
pub ci_dr_cost: (f64, f64),
}
impl IpsReport {
#[must_use]
pub fn render(&self) -> String {
let mut out = format!(
"traces: {n} n_with_propensity: {nwp} candidate_start_rung: {sr}\n\
IPS cost/request: ${ips:.6}\n\
SNIPS cost/request: ${snips:.6}\n\
IPS cost CI [2.5%, 97.5%]: [${clo:.6}, ${chi:.6}]\n\
effective sample size (ESS): {ess:.1}\n\
n_correctness_known: {nck}\n",
n = self.n_traces,
nwp = self.n_with_propensity,
sr = self.candidate_start_rung,
ips = self.ips_cost,
snips = self.snips_cost,
clo = self.ci_ips_cost.0,
chi = self.ci_ips_cost.1,
ess = self.ess,
nck = self.n_correctness_known,
);
out.push_str(&format!(
"DR cost/request: ${dr:.6}\n\
DR cost CI [2.5%, 97.5%]: [${drlo:.6}, ${drhi:.6}]\n",
dr = self.dr_cost,
drlo = self.ci_dr_cost.0,
drhi = self.ci_dr_cost.1,
));
match self.ips_served_failure {
Some(f) => {
let sf_snips = self.snips_served_failure.unwrap_or(f);
let (lo, hi) = self.ci_ips_served_failure.unwrap_or((f, f));
out.push_str(&format!(
"IPS served-failure: {f:.4} SNIPS: {sf_snips:.4} CI [{lo:.4}, {hi:.4}]\n"
));
}
None => {
out.push_str(
"IPS served-failure: n/a (no deferred feedback on matched-start traces)\n",
);
}
}
out.push_str(
"\nIPS/SNIPS/DR valid only for candidates over the same logged ladder with \
propensity-logged traffic. Traces without propensity excluded. \
DR reward model: per-(task-kind, rung) empirical mean — coarse; see ponytail comment. \
Direct-method replay remains for ladder/threshold changes.\n",
);
out
}
}
struct DmModel {
bucket: HashMap<(TaskKind, u32), f64>,
rung_mean: HashMap<u32, f64>,
global_mean: f64,
}
impl DmModel {
fn build(traces: &[Trace]) -> Self {
let mut bucket_acc: HashMap<(TaskKind, u32), (f64, u32)> = HashMap::new();
let mut rung_acc: HashMap<u32, (f64, u32)> = HashMap::new();
let mut global_sum = 0.0f64;
let mut global_n = 0u32;
for trace in traces {
if trace.policy.propensity.is_none() {
continue; }
let Some(first) = trace.attempts.first() else {
continue;
};
let rung = first.rung;
let cost = trace.final_.total_cost_usd;
let ctx = trace.request.features.task_kind;
let be = bucket_acc.entry((ctx, rung)).or_default();
be.0 += cost;
be.1 += 1;
let re = rung_acc.entry(rung).or_default();
re.0 += cost;
re.1 += 1;
global_sum += cost;
global_n += 1;
}
let bucket = bucket_acc
.into_iter()
.map(|(k, (s, n))| (k, s / n as f64))
.collect();
let rung_mean = rung_acc
.into_iter()
.map(|(k, (s, n))| (k, s / n as f64))
.collect();
let global_mean = if global_n > 0 {
global_sum / global_n as f64
} else {
0.0
};
Self {
bucket,
rung_mean,
global_mean,
}
}
fn predict(&self, task_kind: TaskKind, rung: u32) -> f64 {
self.bucket
.get(&(task_kind, rung))
.copied()
.or_else(|| self.rung_mean.get(&rung).copied())
.unwrap_or(self.global_mean)
}
}
pub fn ips_from_store(
db_path: impl AsRef<Path>,
tenant: &str,
candidate_start_rung: u32,
) -> Result<IpsReport, StoreError> {
let traces = store::load_tenant_traces(&db_path, tenant).unwrap_or_default();
let n_traces = traces.len();
struct IpsPoint {
weight: f64,
cost: f64,
correctness: Option<bool>,
task_kind: TaskKind,
logged_rung: u32,
}
let mut points: Vec<IpsPoint> = Vec::with_capacity(n_traces);
let mut n_with_propensity = 0usize;
for trace in &traces {
let Some(p) = trace.policy.propensity else {
continue; };
if p <= 0.0 {
continue; }
n_with_propensity += 1;
let logged_start = trace.attempts.first().map(|a| a.rung);
let indicator = f64::from(logged_start == Some(candidate_start_rung));
let w = indicator / p;
let correctness = if w > 0.0 {
let deferred = store::load_deferred(&db_path, &trace.trace_id.to_string())?;
deferred
.last()
.map(|dv: &DeferredVerdict| dv.verdict == Verdict::Pass)
} else {
None
};
points.push(IpsPoint {
weight: w,
cost: trace.final_.total_cost_usd,
correctness,
task_kind: trace.request.features.task_kind,
logged_rung: logged_start.unwrap_or(0),
});
}
let n = n_with_propensity as f64;
let sum_w: f64 = points.iter().map(|p| p.weight).sum();
let sum_w2: f64 = points.iter().map(|p| p.weight * p.weight).sum();
let sum_wc: f64 = points.iter().map(|p| p.weight * p.cost).sum();
let ips_cost = if n > 0.0 { sum_wc / n } else { 0.0 };
let snips_cost = if sum_w > 0.0 { sum_wc / sum_w } else { 0.0 };
let ess = if sum_w2 > 0.0 {
sum_w * sum_w / sum_w2
} else {
0.0
};
let wc_values: Vec<f64> = points.iter().map(|p| p.weight * p.cost).collect();
let ci_ips_cost = bootstrap_mean_ci(&wc_values, 1000, 42);
let known: Vec<(f64, bool)> = points
.iter()
.filter_map(|p| p.correctness.map(|c| (p.weight, c)))
.collect();
let n_correctness_known = known.len();
let (ips_served_failure, snips_served_failure, ci_ips_served_failure) = if known.is_empty() {
(None, None, None)
} else {
let n_known = known.len() as f64;
let sum_wf: f64 = known.iter().filter(|(_, c)| !c).map(|(w, _)| w).sum();
let sum_wk: f64 = known.iter().map(|(w, _)| w).sum();
let ips_f = sum_wf / n_known;
let snips_f = if sum_wk > 0.0 { sum_wf / sum_wk } else { 0.0 };
let wf_vals: Vec<f64> = known
.iter()
.map(|(w, c)| if !c { *w } else { 0.0 })
.collect();
let ci = bootstrap_mean_ci(&wf_vals, 1000, 43);
(Some(ips_f), Some(snips_f), Some(ci))
};
let dm = DmModel::build(&traces);
let dr_vals: Vec<f64> = points
.iter()
.map(|pt| {
let dm_cand = dm.predict(pt.task_kind, candidate_start_rung);
let dm_logged = dm.predict(pt.task_kind, pt.logged_rung);
dm_cand + pt.weight * (pt.cost - dm_logged)
})
.collect();
let dr_cost = if dr_vals.is_empty() {
0.0
} else {
dr_vals.iter().sum::<f64>() / dr_vals.len() as f64
};
let ci_dr_cost = bootstrap_mean_ci(&dr_vals, 1000, 44);
Ok(IpsReport {
n_traces,
n_with_propensity,
candidate_start_rung,
ips_cost,
snips_cost,
ess,
ci_ips_cost,
ips_served_failure,
snips_served_failure,
n_correctness_known,
ci_ips_served_failure,
dr_cost,
ci_dr_cost,
})
}
#[cfg(test)]
mod tests {
use firstpass_core::{
Features, FinalOutcome, GENESIS_HASH, GateResult, Mode, PolicyRef, RequestInfo, Score,
ServedFrom, TaskKind, Verdict,
};
use super::*;
use crate::store;
fn make_trace(tenant: &str, rung: u32, model: &str, pass_score: f64, cost_usd: f64) -> Trace {
let verdict = if pass_score >= 0.5 {
Verdict::Pass
} else {
Verdict::Fail
};
let attempt = firstpass_core::Attempt {
rung,
model: model.to_owned(),
provider: "anthropic".to_owned(),
in_tokens: 10,
out_tokens: 5,
cost_usd,
latency_ms: 12,
gates: vec![GateResult {
gate_id: "gate@v1".to_owned(),
verdict,
score: Some(Score::clamped(pass_score)),
cost_usd: 0.0,
ms: 10,
reason: None,
evidence_ref: None,
}],
verdict,
};
let mut trace = Trace {
trace_id: uuid::Uuid::now_v7(),
prev_hash: GENESIS_HASH.to_owned(),
tenant_id: tenant.to_owned(),
session_id: "s1".to_owned(),
ts: jiff::Timestamp::now(),
mode: Mode::Enforce,
policy: PolicyRef {
id: "test@v0".to_owned(),
explore: false,
propensity: None,
},
request: RequestInfo {
api: "anthropic.messages".to_owned(),
prompt_hash: "deadbeef".to_owned(),
features: Features::new(TaskKind::Other),
},
attempts: vec![attempt],
deferred: Vec::new(),
final_: FinalOutcome {
served_rung: Some(rung),
served_from: ServedFrom::Attempt,
total_cost_usd: cost_usd,
gate_cost_usd: 0.0,
total_latency_ms: 12,
escalations: 0,
counterfactual_baseline_usd: cost_usd,
savings_usd: 0.0,
},
};
trace.recompute_savings();
trace
}
fn make_escalated_trace(tenant: &str, haiku_cost: f64, sonnet_cost: f64) -> Trace {
let haiku = firstpass_core::Attempt {
rung: 0,
model: "haiku".to_owned(),
provider: "anthropic".to_owned(),
in_tokens: 10,
out_tokens: 5,
cost_usd: haiku_cost,
latency_ms: 10,
gates: vec![GateResult {
gate_id: "g".to_owned(),
verdict: Verdict::Fail,
score: Some(Score::clamped(0.3)),
cost_usd: 0.0,
ms: 5,
reason: None,
evidence_ref: None,
}],
verdict: Verdict::Fail,
};
let sonnet = firstpass_core::Attempt {
rung: 1,
model: "sonnet".to_owned(),
provider: "anthropic".to_owned(),
in_tokens: 10,
out_tokens: 5,
cost_usd: sonnet_cost,
latency_ms: 20,
gates: vec![GateResult {
gate_id: "g".to_owned(),
verdict: Verdict::Pass,
score: Some(Score::clamped(0.9)),
cost_usd: 0.0,
ms: 5,
reason: None,
evidence_ref: None,
}],
verdict: Verdict::Pass,
};
let total = haiku_cost + sonnet_cost;
let mut trace = Trace {
trace_id: uuid::Uuid::now_v7(),
prev_hash: GENESIS_HASH.to_owned(),
tenant_id: tenant.to_owned(),
session_id: "s2".to_owned(),
ts: jiff::Timestamp::now(),
mode: Mode::Enforce,
policy: PolicyRef {
id: "test@v0".to_owned(),
explore: false,
propensity: None,
},
request: RequestInfo {
api: "anthropic.messages".to_owned(),
prompt_hash: "beef".to_owned(),
features: Features::new(TaskKind::Other),
},
attempts: vec![haiku, sonnet],
deferred: Vec::new(),
final_: FinalOutcome {
served_rung: Some(1),
served_from: ServedFrom::Attempt,
total_cost_usd: total,
gate_cost_usd: 0.0,
total_latency_ms: 30,
escalations: 1,
counterfactual_baseline_usd: total,
savings_usd: 0.0,
},
};
trace.recompute_savings();
trace
}
fn deferred_pass(gate: &str) -> firstpass_core::DeferredVerdict {
firstpass_core::DeferredVerdict {
gate_id: gate.to_owned(),
verdict: Verdict::Pass,
score: None,
reported_at: jiff::Timestamp::now(),
reporter: "test".to_owned(),
}
}
fn deferred_fail(gate: &str) -> firstpass_core::DeferredVerdict {
firstpass_core::DeferredVerdict {
gate_id: gate.to_owned(),
verdict: Verdict::Fail,
score: None,
reported_at: jiff::Timestamp::now(),
reporter: "test".to_owned(),
}
}
fn tmp_db() -> std::path::PathBuf {
std::env::temp_dir().join(format!("fp-ope-{}.db", uuid::Uuid::now_v7()))
}
#[tokio::test]
async fn candidate_equals_logged_matches_exactly() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
let mut ids = Vec::new();
for _ in 0..10 {
let t = make_trace("tenant-a", 0, "haiku", 0.8, 0.001);
ids.push(t.trace_id.to_string());
tx.try_send(t).unwrap();
}
drop(tx);
handle.await.unwrap();
for id in &ids {
store::append_deferred(&db, id, &deferred_pass("out")).unwrap();
}
let policy = CandidatePolicy {
ladder: vec!["haiku".to_owned()],
serve_threshold: None,
};
let report = ope_from_store(&db, "tenant-a", &policy).unwrap();
assert_eq!(report.n_traces, 10);
assert_eq!(report.n_evaluable, 10);
assert!((report.coverage - 1.0).abs() < 1e-9);
assert!((report.est_cost_per_request - 0.001).abs() < 1e-9);
assert!((report.logged_cost_per_request - 0.001).abs() < 1e-9);
assert_eq!(report.n_correctness_known, 10);
assert!((report.est_served_failure.unwrap() - 0.0).abs() < 1e-9);
assert!((report.escalation_rate - 0.0).abs() < 1e-9);
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn cheaper_candidate_reduces_cost_and_escalation() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
for _ in 0..5 {
tx.try_send(make_escalated_trace("t", 0.001, 0.01)).unwrap();
}
drop(tx);
handle.await.unwrap();
let policy = CandidatePolicy {
ladder: vec!["haiku".to_owned()],
serve_threshold: None,
};
let report = ope_from_store(&db, "t", &policy).unwrap();
assert_eq!(report.n_evaluable, 5);
assert!((report.coverage - 1.0).abs() < 1e-9);
assert!(
(report.est_cost_per_request - 0.001).abs() < 1e-9,
"got {}",
report.est_cost_per_request
);
assert!((report.logged_cost_per_request - 0.011).abs() < 1e-9);
assert_eq!(report.n_correctness_known, 0);
assert!(report.est_served_failure.is_none());
assert!((report.escalation_rate - 1.0).abs() < 1e-9);
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn unlogged_model_makes_trace_unevaluable() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
for _ in 0..3 {
tx.try_send(make_trace("t", 0, "haiku", 0.8, 0.001))
.unwrap();
}
for _ in 0..3 {
tx.try_send(make_trace("t", 0, "sonnet", 0.8, 0.01))
.unwrap();
}
drop(tx);
handle.await.unwrap();
let policy = CandidatePolicy {
ladder: vec!["newmodel".to_owned(), "haiku".to_owned()],
serve_threshold: None,
};
let report = ope_from_store(&db, "t", &policy).unwrap();
assert_eq!(report.n_traces, 6);
assert_eq!(report.n_evaluable, 0);
assert!((report.coverage - 0.0).abs() < 1e-9);
assert!(report.est_served_failure.is_none());
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn different_rung_served_correctness_unknown() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
let t = make_escalated_trace("t", 0.001, 0.01);
let tid = t.trace_id.to_string();
tx.try_send(t).unwrap();
drop(tx);
handle.await.unwrap();
store::append_deferred(&db, &tid, &deferred_pass("out")).unwrap();
let policy = CandidatePolicy {
ladder: vec!["haiku".to_owned(), "sonnet".to_owned()],
serve_threshold: Some(0.1), };
let report = ope_from_store(&db, "t", &policy).unwrap();
assert_eq!(report.n_evaluable, 1);
assert_eq!(report.n_correctness_known, 0, "different rung => UNKNOWN");
assert!(report.est_served_failure.is_none());
assert!((report.est_cost_per_request - 0.001).abs() < 1e-9);
assert!((report.escalation_rate - 0.0).abs() < 1e-9);
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn bootstrap_ci_deterministic_and_sane() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
let mut ids = Vec::new();
for i in 0..30u32 {
let cost = if i % 2 == 0 { 0.001 } else { 0.002 };
let t = make_trace("t", 0, "m", 0.9, cost);
ids.push(t.trace_id.to_string());
tx.try_send(t).unwrap();
}
drop(tx);
handle.await.unwrap();
for (i, id) in ids.iter().enumerate() {
let dv = if i < 15 {
deferred_pass("o")
} else {
deferred_fail("o")
};
store::append_deferred(&db, id, &dv).unwrap();
}
let policy = CandidatePolicy {
ladder: vec!["m".to_owned()],
serve_threshold: None,
};
let r1 = ope_from_store(&db, "t", &policy).unwrap();
let r2 = ope_from_store(&db, "t", &policy).unwrap();
assert_eq!(r1.ci_cost, r2.ci_cost, "CI must be deterministic");
assert_eq!(r1.ci_served_failure, r2.ci_served_failure);
let (lo, hi) = r1.ci_cost;
assert!(
lo <= r1.est_cost_per_request + 1e-9,
"CI lo {lo} > est {}",
r1.est_cost_per_request
);
assert!(
hi >= r1.est_cost_per_request - 1e-9,
"CI hi {hi} < est {}",
r1.est_cost_per_request
);
assert!(lo <= hi, "CI must be ordered");
if let Some((flo, fhi)) = r1.ci_served_failure {
let f = r1.est_served_failure.unwrap();
assert!(flo <= f + 1e-9, "failure CI lo {flo} > est {f}");
assert!(fhi >= f - 1e-9, "failure CI hi {fhi} < est {f}");
assert!(flo <= fhi);
}
let _ = std::fs::remove_file(&db);
}
#[test]
fn empty_store_returns_zero_trace_report() {
let policy = CandidatePolicy {
ladder: vec!["m".to_owned()],
serve_threshold: None,
};
let db = std::path::Path::new("/nonexistent/fp-ope-empty.db");
let report = ope_from_store(db, "t", &policy).unwrap();
assert_eq!(report.n_traces, 0);
assert_eq!(report.n_evaluable, 0);
assert!((report.coverage - 1.0).abs() < 1e-9);
assert!(report.est_served_failure.is_none());
}
#[tokio::test]
async fn same_rung_deferred_correctness_attributed() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
let t_pass = make_trace("t", 0, "m", 0.9, 0.001);
let t_fail = make_trace("t", 0, "m", 0.9, 0.001);
let (id_pass, id_fail) = (t_pass.trace_id.to_string(), t_fail.trace_id.to_string());
tx.try_send(t_pass).unwrap();
tx.try_send(t_fail).unwrap();
drop(tx);
handle.await.unwrap();
store::append_deferred(&db, &id_pass, &deferred_pass("out")).unwrap();
store::append_deferred(&db, &id_fail, &deferred_fail("out")).unwrap();
let policy = CandidatePolicy {
ladder: vec!["m".to_owned()],
serve_threshold: None,
};
let r = ope_from_store(&db, "t", &policy).unwrap();
assert_eq!(r.n_evaluable, 2);
assert_eq!(r.n_correctness_known, 2);
assert!((r.est_served_failure.unwrap() - 0.5).abs() < 1e-9);
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn high_threshold_forces_escalation_and_higher_cost() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
let t = make_trace("t", 0, "haiku", 0.7, 0.001); tx.try_send(t).unwrap();
drop(tx);
handle.await.unwrap();
let policy = CandidatePolicy {
ladder: vec!["haiku".to_owned()],
serve_threshold: Some(0.8), };
let r = ope_from_store(&db, "t", &policy).unwrap();
assert_eq!(r.n_evaluable, 1);
assert!((r.est_cost_per_request - 0.001).abs() < 1e-9); assert_eq!(r.n_correctness_known, 0); assert!((r.escalation_rate - 1.0).abs() < 1e-9);
let _ = std::fs::remove_file(&db);
}
#[test]
fn from_toml_extracts_first_route_and_threshold() {
let toml = r#"
[[route]]
match = {}
mode = "enforce"
ladder = ["anthropic/claude-haiku-4-5", "anthropic/claude-sonnet-5"]
[escalation]
serve_threshold = 0.75
"#;
let p = CandidatePolicy::from_toml(toml).unwrap();
assert_eq!(
p.ladder,
["anthropic/claude-haiku-4-5", "anthropic/claude-sonnet-5"]
);
assert!((p.serve_threshold.unwrap() - 0.75).abs() < 1e-9);
}
#[test]
fn from_toml_no_threshold_is_none() {
let toml = "[[route]]\nmatch = {}\nmode = \"enforce\"\nladder = [\"m\"]\n";
let p = CandidatePolicy::from_toml(toml).unwrap();
assert!(p.serve_threshold.is_none());
}
fn make_propensity_trace(
tenant: &str,
rung: u32,
cost_usd: f64,
propensity: Option<f64>,
) -> Trace {
let attempt = firstpass_core::Attempt {
rung,
model: "m".to_owned(),
provider: "anthropic".to_owned(),
in_tokens: 10,
out_tokens: 5,
cost_usd,
latency_ms: 5,
gates: vec![],
verdict: Verdict::Pass,
};
let mut trace = Trace {
trace_id: uuid::Uuid::now_v7(),
prev_hash: GENESIS_HASH.to_owned(),
tenant_id: tenant.to_owned(),
session_id: "s".to_owned(),
ts: jiff::Timestamp::now(),
mode: Mode::Enforce,
policy: PolicyRef {
id: "bandit@v1+eps".to_owned(),
explore: rung != 0,
propensity,
},
request: RequestInfo {
api: "anthropic.messages".to_owned(),
prompt_hash: "ph".to_owned(),
features: Features::new(TaskKind::Other),
},
attempts: vec![attempt],
deferred: Vec::new(),
final_: FinalOutcome {
served_rung: Some(rung),
served_from: ServedFrom::Attempt,
total_cost_usd: cost_usd,
gate_cost_usd: 0.0,
total_latency_ms: 5,
escalations: 0,
counterfactual_baseline_usd: cost_usd,
savings_usd: 0.0,
},
};
trace.recompute_savings();
trace
}
#[tokio::test]
async fn ips_correctness_from_known_logging_policy() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
for _ in 0..45 {
tx.try_send(make_propensity_trace("t", 0, 0.001, Some(0.9)))
.unwrap();
}
for _ in 0..5 {
tx.try_send(make_propensity_trace("t", 1, 0.010, Some(0.1)))
.unwrap();
}
drop(tx);
handle.await.unwrap();
let report = ips_from_store(&db, "t", 1).unwrap();
assert_eq!(report.n_traces, 50);
assert_eq!(report.n_with_propensity, 50);
assert!(
(report.ips_cost - 0.010).abs() < 1e-9,
"IPS cost={} expected 0.010",
report.ips_cost
);
assert!(
(report.snips_cost - 0.010).abs() < 1e-9,
"SNIPS cost={} expected 0.010",
report.snips_cost
);
assert!(
report.ess.is_finite() && report.ess > 0.0,
"ESS must be positive"
);
assert!(
(report.ess - 5.0).abs() < 1e-9,
"ESS={} expected 5.0",
report.ess
);
assert_eq!(report.n_correctness_known, 0);
assert!(report.ips_served_failure.is_none());
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn ips_excludes_traces_without_propensity() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
for _ in 0..5 {
tx.try_send(make_propensity_trace("t", 0, 0.001, Some(0.9)))
.unwrap();
}
for _ in 0..5 {
tx.try_send(make_propensity_trace("t", 0, 0.001, None))
.unwrap();
}
drop(tx);
handle.await.unwrap();
let report = ips_from_store(&db, "t", 0).unwrap();
assert_eq!(report.n_traces, 10);
assert_eq!(
report.n_with_propensity, 5,
"only traces with propensity count"
);
let expected_ips = 0.001_f64 / 0.9;
assert!(
(report.ips_cost - expected_ips).abs() < 1e-9,
"IPS={} expected {expected_ips}",
report.ips_cost
);
let _ = std::fs::remove_file(&db);
}
#[test]
fn ips_empty_store_returns_zero_report() {
let db = std::path::Path::new("/nonexistent/fp-ips-empty.db");
let report = ips_from_store(db, "t", 0).unwrap();
assert_eq!(report.n_traces, 0);
assert_eq!(report.n_with_propensity, 0);
assert_eq!(report.ips_cost, 0.0);
assert_eq!(report.snips_cost, 0.0);
assert_eq!(report.ess, 0.0);
assert!(report.ips_served_failure.is_none());
assert_eq!(report.dr_cost, 0.0);
assert_eq!(report.ci_dr_cost, (0.0, 0.0));
}
fn make_propensity_trace_ce(rung: u32, cost: f64, p: Option<f64>) -> Trace {
let mut t = make_propensity_trace("t", rung, cost, p);
t.request.features.task_kind = TaskKind::CodeEdit;
t
}
#[tokio::test]
async fn dr_degenerate_propensities_equals_dm_and_ips() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
for _ in 0..5 {
tx.try_send(make_propensity_trace("t", 1, 0.010, Some(1.0)))
.unwrap();
}
drop(tx);
handle.await.unwrap();
let r = ips_from_store(&db, "t", 1).unwrap();
assert!(
(r.dr_cost - 0.010).abs() < 1e-9,
"DR={} expected 0.010",
r.dr_cost
);
assert!(
(r.dr_cost - r.ips_cost).abs() < 1e-9,
"DR should equal IPS; DR={} IPS={}",
r.dr_cost,
r.ips_cost
);
assert!(
(r.dr_cost - r.snips_cost).abs() < 1e-9,
"DR should equal SNIPS; DR={} SNIPS={}",
r.dr_cost,
r.snips_cost
);
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn dr_correction_recovers_true_cost_under_correct_propensities() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
for _ in 0..9 {
tx.try_send(make_propensity_trace("t", 0, 0.001, Some(0.9)))
.unwrap();
}
tx.try_send(make_propensity_trace("t", 1, 0.010, Some(0.1)))
.unwrap();
drop(tx);
handle.await.unwrap();
let r = ips_from_store(&db, "t", 1).unwrap();
assert!(
(r.dr_cost - 0.010).abs() < 1e-9,
"DR={} expected 0.010 (not the naive logged mean 0.0019)",
r.dr_cost
);
assert!(
(r.dr_cost - r.ips_cost).abs() < 1e-9,
"DR should equal IPS under correct propensities; DR={} IPS={}",
r.dr_cost,
r.ips_cost
);
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn dr_sparse_bucket_fallback_no_nan() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
for _ in 0..5 {
tx.try_send(make_propensity_trace_ce(0, 0.001, Some(0.5)))
.unwrap();
}
for _ in 0..5 {
tx.try_send(make_propensity_trace("t", 1, 0.020, Some(0.5)))
.unwrap();
}
drop(tx);
handle.await.unwrap();
let r = ips_from_store(&db, "t", 1).unwrap();
assert!(
r.dr_cost.is_finite(),
"DR must be finite even when a context bucket is empty (got NaN/inf)"
);
assert!(
(r.dr_cost - 0.020).abs() < 1e-9,
"DR={} expected 0.020",
r.dr_cost
);
let _ = std::fs::remove_file(&db);
}
#[tokio::test]
async fn dr_ci_present_and_sane() {
let db = tmp_db();
let (tx, handle) = store::open(&db).unwrap();
for i in 0..20u32 {
let cost = if i % 2 == 0 { 0.001 } else { 0.002 };
tx.try_send(make_propensity_trace("t", 1, cost, Some(0.5)))
.unwrap();
}
drop(tx);
handle.await.unwrap();
let r1 = ips_from_store(&db, "t", 1).unwrap();
let r2 = ips_from_store(&db, "t", 1).unwrap();
assert_eq!(r1.ci_dr_cost, r2.ci_dr_cost, "DR CI must be deterministic");
let (lo, hi) = r1.ci_dr_cost;
assert!(lo.is_finite() && hi.is_finite(), "DR CI must be finite");
assert!(lo <= hi, "DR CI must be ordered: lo={lo} hi={hi}");
assert!(
lo <= r1.dr_cost + 1e-9,
"DR CI lo {lo} > dr_cost {}",
r1.dr_cost
);
assert!(
hi >= r1.dr_cost - 1e-9,
"DR CI hi {hi} < dr_cost {}",
r1.dr_cost
);
let _ = std::fs::remove_file(&db);
}
}