use serde::{Deserialize, Serialize};
use serde_json::Value;
use super::join::Ratio;
use super::receipt::RunId;
use super::replicate::{log_ratio_bound_or_point, ArmOrder, ReplicatePair};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ArmId {
A,
B,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub enum DeltaKind {
Config {
flag: String,
},
Code,
}
impl DeltaKind {
#[must_use]
pub fn declared_keys(&self) -> Vec<&str> {
match self {
Self::Config { flag } => vec![flag.as_str()],
Self::Code => Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Arm {
pub id: ArmId,
pub commit: String,
pub sha256: String,
pub effective_config: Value,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigDiff {
pub key: String,
pub a: Value,
pub b: Value,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AbReplicate {
pub arm: ArmId,
pub agg: f64,
pub dec: Option<f64>,
pub prefill: Option<f64>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct AbRecord {
pub run_id: RunId,
pub started_utc: String,
pub host: String,
pub delta_kind: DeltaKind,
pub prediction: String,
pub arms: [Arm; 2],
pub interleaved: bool,
pub order: Vec<ArmId>,
pub effective_config_diff: Vec<ConfigDiff>,
pub replicates: Vec<AbReplicate>,
pub interval: Option<Ratio>,
}
impl AbRecord {
pub fn parse(text: &str) -> Result<Self, String> {
serde_json::from_str(text).map_err(|e| format!("parsing AbRecord: {e}"))
}
pub fn validate(&self) -> Result<(), String> {
self.validate_arms()?;
if !self.interleaved {
return Err(
"PP-32: interleaved=false — the two arms must alternate within one harness \
invocation. Thermal state, warm caches and free VRAM drift across a sweep, and \
a block of A followed by a block of B measures the drift as well as the change"
.to_string(),
);
}
self.validate_order()?;
self.validate_config_diff()?;
if self.prediction.trim().is_empty() {
return Err(
"PP-32: prediction is empty — §10 is 'predict, then verify', and a prediction \
recorded after the run is a description"
.to_string(),
);
}
self.validate_interval()
}
#[must_use]
pub fn derived_interval(&self) -> Option<Ratio> {
log_ratio_bound_or_point(&self.replicate_pairs()?)
}
fn replicate_pairs(&self) -> Option<Vec<ReplicatePair>> {
if self.order.len() < 2 || self.replicates.len() != self.order.len() {
return None;
}
let mut pairs = Vec::with_capacity(self.order.len() / 2);
for (k, chunk) in self.order.as_chunks::<2>().0.iter().enumerate() {
let (first, second) = (chunk[0], chunk[1]);
if first == second {
return None;
}
let (a, b) = (&self.replicates[2 * k], &self.replicates[2 * k + 1]);
if a.arm != first || b.arm != second {
return None;
}
let (control, change) = if first == ArmId::A { (a, b) } else { (b, a) };
pairs.push(ReplicatePair {
subject: change.agg,
comparator: control.agg,
order: if first == ArmId::A {
ArmOrder::ComparatorFirst
} else {
ArmOrder::SubjectFirst
},
});
}
Some(pairs)
}
fn validate_arms(&self) -> Result<(), String> {
if self.arms[0].id != ArmId::A || self.arms[1].id != ArmId::B {
return Err(format!(
"PP-32: arms are [{:?}, {:?}], expected [A, B]",
self.arms[0].id, self.arms[1].id
));
}
for arm in &self.arms {
if arm.sha256.len() != 64
|| !arm
.sha256
.bytes()
.all(|b| b.is_ascii_hexdigit() && !b.is_ascii_uppercase())
{
return Err(format!(
"PP-32: arm {:?} sha256 {:?} is not 64 lowercase hex characters",
arm.id, arm.sha256
));
}
}
if self.delta_kind == DeltaKind::Code && self.arms[0].sha256 == self.arms[1].sha256 {
return Err(
"PP-32: delta_kind=code but both arms carry the same sha256 — a code delta needs \
two binaries, and one binary run twice measures noise"
.to_string(),
);
}
Ok(())
}
fn validate_order(&self) -> Result<(), String> {
if self.order.len() < 2 {
return Err(format!(
"PP-32: order has {} entries — an A/B record needs at least one of each",
self.order.len()
));
}
if let Some(i) = self.order.windows(2).position(|w| w[0] == w[1]) {
return Err(format!(
"PP-32: order is not strictly alternating — entries {i} and {} are both {:?}",
i + 1,
self.order[i]
));
}
if self.replicates.len() != self.order.len() {
return Err(format!(
"PP-32: {} replicates against {} order entries — every run in the sequence must \
carry its numbers",
self.replicates.len(),
self.order.len()
));
}
for (i, (want, got)) in self.order.iter().zip(self.replicates.iter()).enumerate() {
if *want != got.arm {
return Err(format!(
"PP-32: replicate {i} is arm {:?} but order says {want:?}",
got.arm
));
}
}
Ok(())
}
fn validate_config_diff(&self) -> Result<(), String> {
let declared = self.delta_kind.declared_keys();
let outside: Vec<&str> = self
.effective_config_diff
.iter()
.map(|d| d.key.as_str())
.filter(|k| !declared.contains(k))
.collect();
if outside.is_empty() {
return Ok(());
}
Err(format!(
"PP-32: the arms' effective configs differ on {outside:?}, outside the declared delta \
{declared:?} — the run measured more than one change and attributed it to one"
))
}
fn validate_interval(&self) -> Result<(), String> {
let derived = self.derived_interval();
if intervals_agree(self.interval.as_ref(), derived.as_ref()) {
return Ok(());
}
Err(format!(
"PP-32: the stated interval {:?} is not the one these replicates produce ({derived:?}) \
— a stated bound its own data does not reproduce is a fabricated measurement",
self.interval
))
}
}
fn intervals_agree(stated: Option<&Ratio>, derived: Option<&Ratio>) -> bool {
match (stated, derived) {
(None, None) => true,
(Some(a), Some(b)) => {
a.method == b.method
&& a.n == b.n
&& close(Some(a.point), Some(b.point))
&& close(a.lcb95, b.lcb95)
}
_ => false,
}
}
fn close(a: Option<f64>, b: Option<f64>) -> bool {
match (a, b) {
(None, None) => true,
(Some(x), Some(y)) => (x - y).abs() <= 1e-9 * x.abs().max(y.abs()).max(1.0),
_ => false,
}
}
#[cfg(test)]
mod tests {
#![allow(non_snake_case)]
use super::*;
use serde_json::json;
fn arm(id: ArmId, commit: &str, sha: char, config: Value) -> Arm {
Arm {
id,
commit: commit.to_string(),
sha256: std::iter::repeat_n(sha, 64).collect(),
effective_config: config,
}
}
fn record(delta_kind: DeltaKind, arms: [Arm; 2]) -> AbRecord {
let order = vec![ArmId::A, ArmId::B, ArmId::A, ArmId::B, ArmId::A, ArmId::B];
let replicates: Vec<AbReplicate> = order
.iter()
.enumerate()
.map(|(i, arm)| AbReplicate {
arm: *arm,
agg: if *arm == ArmId::A {
100.0 + i as f64
} else {
130.0 + i as f64
},
dec: Some(40.0),
prefill: None,
})
.collect();
let mut r = AbRecord {
run_id: RunId::derive("2026-09-02T10:11:12.345Z", "lambda", &"c".repeat(64), 7),
started_utc: "2026-09-02T10:11:12.345Z".to_string(),
host: "lambda".to_string(),
delta_kind,
prediction: "batched decode <= 3.5 ms/tok; agg(2) > 1.0x one client".to_string(),
arms,
interleaved: true,
order,
effective_config_diff: Vec::new(),
replicates,
interval: None,
};
r.interval = r.derived_interval();
r
}
fn code_record() -> AbRecord {
record(
DeltaKind::Code,
[
arm(ArmId::A, "119f61738", 'a', json!({"max_batch": 11})),
arm(ArmId::B, "2f0c9d114", 'b', json!({"max_batch": 11})),
],
)
}
#[test]
fn abrecord_ok__a_code_delta_with_two_shas_parses() {
let r = code_record();
let text = serde_json::to_string(&r).expect("serialises");
let back = AbRecord::parse(&text).expect("round-trips");
back.validate().expect("a conformant record validates");
assert_eq!(back.arms, r.arms);
assert_eq!(back.order, r.order);
assert_eq!(back.replicates, r.replicates);
assert_eq!(back.delta_kind, r.delta_kind);
assert_eq!(back.run_id, r.run_id);
assert!(
intervals_agree(back.interval.as_ref(), r.interval.as_ref()),
"{:?} vs {:?}",
back.interval,
r.interval
);
assert_eq!(back.arms[0].id, ArmId::A);
assert_ne!(back.arms[0].sha256, back.arms[1].sha256);
assert!(back.interval.expect("interval").point > 1.0);
}
#[test]
fn the_interval_tolerance_admits_an_ulp_and_nothing_more() {
let derived = code_record().interval.expect("interval");
let one_ulp = Ratio {
point: f64::from_bits(derived.point.to_bits() + 1),
..derived.clone()
};
assert!(intervals_agree(Some(&one_ulp), Some(&derived)));
let moved = Ratio {
point: derived.point * 1.000_01,
..derived.clone()
};
assert!(!intervals_agree(Some(&moved), Some(&derived)));
assert!(!intervals_agree(None, Some(&derived)));
assert!(!intervals_agree(Some(&derived), None));
}
#[test]
fn abrecord_comparator__a_comparator_field_does_not_parse() {
let mut value = serde_json::to_value(code_record()).expect("serialises");
value
.as_object_mut()
.expect("object")
.insert("comparator".to_string(), json!({"runtime": "llama.cpp"}));
let err = AbRecord::parse(&value.to_string()).expect_err("comparator must not parse");
assert!(err.contains("comparator"), "{err}");
for smuggled in ["runtime", "baseline", "parity", "agg_ratio", "llama_agg"] {
let mut v = serde_json::to_value(code_record()).expect("serialises");
v.as_object_mut()
.expect("object")
.insert(smuggled.to_string(), json!("llama.cpp"));
assert!(
AbRecord::parse(&v.to_string()).is_err(),
"{smuggled} must not parse"
);
}
}
#[test]
fn non_interleaved_ab_is_refused() {
let mut r = code_record();
r.interleaved = false;
let err = r.validate().expect_err("interleaved=false");
assert!(err.contains("alternate"), "{err}");
let mut blocked = code_record();
blocked.order = vec![ArmId::A, ArmId::A, ArmId::B, ArmId::B];
blocked.replicates = blocked
.order
.iter()
.map(|arm| AbReplicate {
arm: *arm,
agg: 100.0,
dec: None,
prefill: None,
})
.collect();
blocked.interval = blocked.derived_interval();
let err = blocked.validate().expect_err("order does not alternate");
assert!(err.contains("strictly alternating"), "{err}");
}
#[test]
fn a_config_diff_outside_the_declared_delta_is_refused() {
let mut r = record(
DeltaKind::Config {
flag: "FUSED_GATE_UP".to_string(),
},
[
arm(ArmId::A, "119f61738", 'a', json!({"fused_gate_up": false})),
arm(ArmId::A, "119f61738", 'a', json!({"fused_gate_up": true})),
],
);
r.arms[1].id = ArmId::B;
r.effective_config_diff = vec![ConfigDiff {
key: "FUSED_GATE_UP".to_string(),
a: json!(false),
b: json!(true),
}];
r.validate()
.expect("the declared flag is allowed to differ");
r.effective_config_diff.push(ConfigDiff {
key: "max_batch".to_string(),
a: json!(11),
b: json!(16),
});
let err = r.validate().expect_err("max_batch is outside the delta");
assert!(err.contains("max_batch"), "{err}");
assert!(err.contains("FUSED_GATE_UP"), "{err}");
let mut c = code_record();
c.effective_config_diff = vec![ConfigDiff {
key: "max_batch".to_string(),
a: json!(11),
b: json!(16),
}];
assert!(c.validate().is_err(), "a code delta permits no config diff");
}
#[test]
fn an_arm_digest_that_is_not_64_lowercase_hex_is_refused() {
for bad in ["short", &"A".repeat(64), &"z".repeat(64), &"a".repeat(63)] {
let mut r = code_record();
r.arms[1].sha256 = (*bad).to_string();
let err = r.validate().expect_err("{bad} must be refused");
assert!(err.contains("64 lowercase hex"), "{bad}: {err}");
}
let mut swapped = code_record();
swapped.arms.swap(0, 1);
let err = swapped.validate().expect_err("arms out of order");
assert!(err.contains("expected [A, B]"), "{err}");
}
#[test]
fn a_code_delta_with_one_binary_is_refused() {
let mut r = code_record();
r.arms[1].sha256 = r.arms[0].sha256.clone();
let err = r.validate().expect_err("one binary");
assert!(err.contains("two binaries"), "{err}");
}
#[test]
fn a_stated_interval_its_replicates_do_not_produce_is_refused() {
let mut r = code_record();
let mut fake = r.interval.clone().expect("interval");
fake.lcb95 = Some(9.99);
r.interval = Some(fake);
let err = r.validate().expect_err("fabricated interval");
assert!(err.contains("fabricated"), "{err}");
}
#[test]
fn an_empty_prediction_is_refused() {
let mut r = code_record();
r.prediction = " ".to_string();
let err = r.validate().expect_err("no prediction");
assert!(err.contains("predict, then verify"), "{err}");
}
#[test]
fn replicates_must_match_the_declared_order() {
let mut r = code_record();
r.replicates.pop();
let err = r.validate().expect_err("counts differ");
assert!(err.contains("order entries"), "{err}");
let mut swapped = code_record();
swapped.replicates[0].arm = ArmId::B;
let err = swapped.validate().expect_err("arm disagrees with order");
assert!(err.contains("order says"), "{err}");
}
#[test]
fn abrecord_blocked__a_blocked_order_produces_no_interval() {
let with_order = |order: Vec<ArmId>| -> AbRecord {
let replicates: Vec<AbReplicate> = order
.iter()
.enumerate()
.map(|(i, arm)| AbReplicate {
arm: *arm,
agg: if *arm == ArmId::A {
100.0 + i as f64
} else {
130.0 + i as f64
},
dec: Some(40.0),
prefill: None,
})
.collect();
AbRecord {
order,
replicates,
..code_record()
}
};
let interleaved = with_order(vec![
ArmId::A,
ArmId::B,
ArmId::A,
ArmId::B,
ArmId::A,
ArmId::B,
])
.derived_interval()
.expect("three adjacent pairs");
assert_eq!(interleaved.n, 3);
let blocked = with_order(vec![
ArmId::A,
ArmId::A,
ArmId::A,
ArmId::B,
ArmId::B,
ArmId::B,
]);
assert!(
blocked.derived_interval().is_none(),
"a blocked sweep measures the drift as well as the change, and pairing its k-th A \
with its k-th B pairs two runs minutes apart as though they had alternated"
);
let stated = AbRecord {
interval: Some(Ratio::reporting_only(
1.3,
crate::perf_gate::join::RatioMethod::ReplicateTLower,
3,
)),
..blocked
};
let err = stated
.validate()
.expect_err("a stated interval over a blocked sweep");
assert!(err.contains("PP-32"), "{err}");
}
#[test]
fn only_a_counterbalanced_sequence_earns_a_bound() {
let order = vec![
ArmId::A,
ArmId::B,
ArmId::B,
ArmId::A,
ArmId::A,
ArmId::B,
ArmId::B,
ArmId::A,
ArmId::A,
ArmId::B,
];
let replicates: Vec<AbReplicate> = order
.iter()
.enumerate()
.map(|(i, arm)| AbReplicate {
arm: *arm,
agg: if *arm == ArmId::A {
100.0 + (i % 3) as f64
} else {
130.0 + (i % 3) as f64
},
dec: None,
prefill: None,
})
.collect();
let counterbalanced = AbRecord {
order,
replicates,
..code_record()
};
let i = counterbalanced
.derived_interval()
.expect("five adjacent pairs");
assert_eq!(i.n, 5);
assert!(
i.lcb95.is_some(),
"five counterbalanced pairs support a bound: {i:?}"
);
let abab: Vec<ArmId> = (0..10)
.map(|i| if i % 2 == 0 { ArmId::A } else { ArmId::B })
.collect();
let replicates: Vec<AbReplicate> = abab
.iter()
.enumerate()
.map(|(i, arm)| AbReplicate {
arm: *arm,
agg: if *arm == ArmId::A {
100.0 + (i % 3) as f64
} else {
130.0 + (i % 3) as f64
},
dec: None,
prefill: None,
})
.collect();
let never_flips = AbRecord {
order: abab,
replicates,
..code_record()
};
let j = never_flips.derived_interval().expect("five adjacent pairs");
assert_eq!(j.n, 5);
assert!(
j.lcb95.is_none(),
"A always first is not counterbalanced, so §4.3 gives it no bound: {j:?}"
);
}
#[test]
fn the_interval_is_the_change_over_the_control() {
let r = code_record();
let i = r.derived_interval().expect("three pairs");
assert!(i.point > 1.2, "{i:?}");
assert!(
i.lcb95.is_none(),
"three replicate pairs bound no variance (§4.3)"
);
}
}