1use serde::{Deserialize, Serialize};
74
75use super::bootstrap::{median_decode_tok_s, paired_ratio_lcb};
76use super::join::{BandRatios, JoinKey, Ratio, RatioMethod};
77use super::metrics::RequestSample;
78use super::protocol::{stream_live_ttft_over_e2e_max, INTERLEAVED, REPLICATES};
79use super::receipt::RunId;
80use super::replicate::MIN_REPLICATES;
81use super::samples::SamplesFile;
82use super::witness::BatchInvarianceWitness;
83
84pub const REQUEST_TIMEOUT_MS: f64 = 120_000.0;
86
87pub const DRAIN_SUSPECT_FRACTION: f64 = 0.5;
89
90pub const SCHEMA_VERSION: u32 = 3;
93
94pub const VERDICT_CONFIDENCE: f64 = 0.95;
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
101#[serde(rename_all = "snake_case")]
102pub enum Outcome {
103 Completed,
105 Timeout,
107 AbandonedAtDrain,
110 Failed,
113}
114
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
117#[serde(rename_all = "snake_case")]
118pub enum StreamMode {
119 Live,
121 Replayed,
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
129#[serde(rename_all = "snake_case")]
130pub enum StreamVerdict {
131 Live,
135 Replayed,
137 Undeclared,
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
154#[serde(rename_all = "snake_case")]
155pub enum StreamWitnessSource {
156 Server,
158 Client,
161}
162
163#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
170#[serde(deny_unknown_fields)]
171pub struct StreamWitness {
172 pub client_ttft_over_e2e_median: f64,
174 pub verdict: StreamVerdict,
176 pub source: StreamWitnessSource,
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
186#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
187pub enum BandStatus {
188 Measured,
190 Unmeasured,
192 Na,
194 InvalidCorrectness,
196 NonconformantValid,
198 ComparatorStale,
200}
201
202impl BandStatus {
203 #[must_use]
208 pub fn wire_token(self) -> &'static str {
209 match self {
210 Self::Measured => "MEASURED",
211 Self::Unmeasured => "UNMEASURED",
212 Self::Na => "NA",
213 Self::InvalidCorrectness => "INVALID-CORRECTNESS",
214 Self::NonconformantValid => "NONCONFORMANT-VALID",
215 Self::ComparatorStale => "COMPARATOR_STALE",
216 }
217 }
218
219 #[must_use]
222 pub fn vocabulary() -> [Self; 6] {
223 [
224 Self::Measured,
225 Self::Unmeasured,
226 Self::Na,
227 Self::InvalidCorrectness,
228 Self::NonconformantValid,
229 Self::ComparatorStale,
230 ]
231 }
232
233 #[must_use]
235 pub fn baseline_eligible(self) -> bool {
236 self == Self::Measured
237 }
238
239 #[must_use]
259 pub fn rank(self) -> u8 {
260 match self {
261 Self::InvalidCorrectness => 0,
262 Self::ComparatorStale => 1,
263 Self::Na => 2,
264 Self::NonconformantValid => 3,
265 Self::Unmeasured => 4,
266 Self::Measured => 5,
267 }
268 }
269
270 #[must_use]
275 pub fn stronger_of(self, other: Self) -> Self {
276 if other.rank() < self.rank() {
277 other
278 } else {
279 self
280 }
281 }
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
286#[serde(rename_all = "snake_case")]
287pub enum Lane {
288 Apr,
290 Llama,
292}
293
294impl Lane {
295 #[must_use]
297 pub fn wire_token(self) -> &'static str {
298 match self {
299 Self::Apr => "apr",
300 Self::Llama => "llama",
301 }
302 }
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
309#[serde(deny_unknown_fields)]
310pub struct AdmissionCap {
311 pub lane: Lane,
313 pub cap: u32,
315}
316
317#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
325#[serde(deny_unknown_fields)]
326pub enum ComparatorStatus {
327 NotApplicable {
329 decided_by: String,
331 reason: String,
333 budget: Option<String>,
336 },
337 Unmeasured {
339 owner: String,
341 reason: String,
343 admission_capped: Option<AdmissionCap>,
346 },
347 Measured(MeasuredJoin),
354}
355
356#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
378#[serde(deny_unknown_fields)]
379pub struct MeasuredJoin {
380 baseline: Box<DerivedBand>,
382 ratios: BandRatios,
384}
385
386impl MeasuredJoin {
387 pub(crate) fn sealed(baseline: DerivedBand, ratios: BandRatios) -> Self {
391 Self {
392 baseline: Box::new(baseline),
393 ratios,
394 }
395 }
396
397 #[must_use]
399 pub fn baseline(&self) -> &DerivedBand {
400 &self.baseline
401 }
402
403 #[must_use]
405 pub fn ratios(&self) -> &BandRatios {
406 &self.ratios
407 }
408}
409
410impl ComparatorStatus {
411 #[must_use]
413 pub fn unmeasured(owner: impl Into<String>, reason: impl Into<String>) -> Self {
414 Self::Unmeasured {
415 owner: owner.into(),
416 reason: reason.into(),
417 admission_capped: None,
418 }
419 }
420
421 #[must_use]
423 pub fn not_applicable(decided_by: impl Into<String>, reason: impl Into<String>) -> Self {
424 Self::NotApplicable {
425 decided_by: decided_by.into(),
426 reason: reason.into(),
427 budget: None,
428 }
429 }
430
431 #[must_use]
437 pub fn wire_token(&self) -> &'static str {
438 match self {
439 Self::NotApplicable { .. } => "NOT_APPLICABLE",
440 Self::Unmeasured { .. } => "UNMEASURED",
441 Self::Measured(_) => "MEASURED",
442 }
443 }
444}
445
446#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
453#[serde(deny_unknown_fields)]
454pub struct LaneConfig {
455 pub n_ctx_slot: Option<u32>,
457 pub kv_type: Option<String>,
459 pub fa: Option<bool>,
461 pub n_batch: Option<u32>,
463}
464
465#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
468#[serde(deny_unknown_fields)]
469pub struct RequestOutcome {
470 pub issued_ms: f64,
472 pub settled_ms: f64,
474 pub outcome: Outcome,
476 pub generated_tokens: u32,
479 pub prompt_tokens: u32,
482 pub expected_tokens: Option<u32>,
485 pub ttft_ms: Option<f64>,
488 pub prefill_ms: Option<f64>,
493 pub in_flight_at_start: u32,
497 pub token_times_ms: Vec<f64>,
500}
501
502impl RequestOutcome {
503 #[must_use]
509 pub fn new(issued_ms: f64, settled_ms: f64, outcome: Outcome, generated_tokens: u32) -> Self {
510 Self {
511 issued_ms,
512 settled_ms,
513 outcome,
514 generated_tokens,
515 prompt_tokens: 0,
516 expected_tokens: None,
517 ttft_ms: None,
518 prefill_ms: None,
519 in_flight_at_start: 0,
520 token_times_ms: Vec::new(),
521 }
522 }
523
524 #[must_use]
526 pub fn completed(issued_ms: f64, settled_ms: f64, generated_tokens: u32) -> Self {
527 Self::new(issued_ms, settled_ms, Outcome::Completed, generated_tokens)
528 }
529
530 #[must_use]
532 pub fn streamed(mut self, ttft_ms: f64, token_times_ms: Vec<f64>) -> Self {
533 self.ttft_ms = Some(ttft_ms);
534 self.token_times_ms = token_times_ms;
535 self
536 }
537
538 #[must_use]
540 pub fn server_prefill(mut self, prompt_tokens: u32, prefill_ms: f64) -> Self {
541 self.prompt_tokens = prompt_tokens;
542 self.prefill_ms = Some(prefill_ms);
543 self
544 }
545
546 #[must_use]
548 pub fn with_prompt_tokens(mut self, prompt_tokens: u32) -> Self {
549 self.prompt_tokens = prompt_tokens;
550 self
551 }
552
553 #[must_use]
555 pub fn expecting(mut self, expected_tokens: u32) -> Self {
556 self.expected_tokens = Some(expected_tokens);
557 self
558 }
559
560 #[must_use]
562 pub fn in_flight(mut self, in_flight_at_start: u32) -> Self {
563 self.in_flight_at_start = in_flight_at_start;
564 self
565 }
566
567 #[must_use]
569 pub fn duration_ms(&self) -> f64 {
570 self.settled_ms - self.issued_ms
571 }
572
573 #[must_use]
576 pub fn decode_tok_per_sec(&self) -> Option<f64> {
577 let (first, last) = (self.token_times_ms.first()?, self.token_times_ms.last()?);
578 let span_s = (last - first) / 1000.0;
579 let n = self.token_times_ms.len();
580 if n < 2 || span_s <= 0.0 {
581 return None;
582 }
583 Some((n as f64 - 1.0) / span_s)
584 }
585
586 #[must_use]
588 pub fn itl_gaps_ms(&self) -> Vec<f64> {
589 self.token_times_ms
590 .windows(2)
591 .map(|w| w[1] - w[0])
592 .collect()
593 }
594
595 #[must_use]
598 pub fn ttft_over_e2e(&self) -> Option<f64> {
599 let ttft = self.ttft_ms?;
600 let e2e = self.duration_ms();
601 if e2e <= 0.0 {
602 return None;
603 }
604 Some(ttft / e2e)
605 }
606
607 #[must_use]
609 pub fn to_sample(&self, index: usize, in_flight_fallback: u32) -> RequestSample {
610 RequestSample {
611 index,
612 worker: 0,
613 start_s: self.issued_ms / 1000.0,
614 end_s: self.settled_ms / 1000.0,
615 token_times_s: self.token_times_ms.iter().map(|t| t / 1000.0).collect(),
616 generated_tokens: self.generated_tokens,
617 prompt_tokens: self.prompt_tokens,
618 outcome: self.outcome,
619 in_flight_at_start: if self.in_flight_at_start == 0 {
620 in_flight_fallback as usize
621 } else {
622 self.in_flight_at_start as usize
623 },
624 drained: false,
625 }
626 }
627
628 #[must_use]
632 pub fn to_row(&self, index: usize) -> SampleRow {
633 SampleRow {
634 index,
635 issued_ms: self.issued_ms,
636 settled_ms: self.settled_ms,
637 outcome: self.outcome,
638 generated_tokens: self.generated_tokens,
639 prompt_tokens: self.prompt_tokens,
640 ttft_ms: self.ttft_ms,
641 in_flight_at_start: self.in_flight_at_start,
642 }
643 }
644}
645
646#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
648#[serde(deny_unknown_fields)]
649pub struct SampleRow {
650 pub index: usize,
652 pub issued_ms: f64,
654 pub settled_ms: f64,
656 pub outcome: Outcome,
658 pub generated_tokens: u32,
660 pub prompt_tokens: u32,
662 pub ttft_ms: Option<f64>,
664 pub in_flight_at_start: u32,
666}
667
668#[derive(Debug, Clone, Copy, PartialEq)]
674pub struct BandContext {
675 pub schema_version: u32,
679 pub replicates: u32,
681 pub interleaved: bool,
683 pub comparator_stale: bool,
685 pub stream_live_ttft_over_e2e_max: f64,
687}
688
689impl Default for BandContext {
690 fn default() -> Self {
691 Self {
692 schema_version: SCHEMA_VERSION,
693 replicates: REPLICATES as u32,
694 interleaved: INTERLEAVED,
695 comparator_stale: false,
696 stream_live_ttft_over_e2e_max: stream_live_ttft_over_e2e_max(),
697 }
698 }
699}
700
701impl BandContext {
702 #[must_use]
705 pub fn at_schema_version(schema_version: u32) -> Self {
706 Self {
707 schema_version,
708 ..Self::default()
709 }
710 }
711}
712
713#[derive(Debug, Clone, PartialEq)]
715pub struct BandInput {
716 pub concurrency: u32,
718 pub window_ms: f64,
720 pub replicate: u32,
722 pub requests: Vec<RequestOutcome>,
724 pub comparator: ComparatorStatus,
726 pub n_predict: Option<u32>,
729 pub stream_mode: Option<StreamMode>,
731 pub witness: Option<BatchInvarianceWitness>,
733 pub samples_file: Option<SamplesFile>,
735 pub lane: LaneConfig,
737 pub role: Lane,
746 pub conformance_violations: Vec<String>,
755}
756
757impl BandInput {
758 #[must_use]
767 pub fn new(
768 concurrency: u32,
769 window_ms: f64,
770 requests: Vec<RequestOutcome>,
771 comparator: ComparatorStatus,
772 ) -> Self {
773 Self {
774 concurrency,
775 window_ms,
776 replicate: 1,
777 requests,
778 comparator,
779 n_predict: None,
780 stream_mode: None,
781 witness: None,
782 samples_file: None,
783 lane: LaneConfig::default(),
784 role: Lane::Apr,
785 conformance_violations: Vec::new(),
786 }
787 }
788
789 #[must_use]
793 pub fn role(mut self, role: Lane) -> Self {
794 self.role = role;
795 self
796 }
797
798 #[must_use]
800 pub fn conformance_violations(mut self, violations: Vec<String>) -> Self {
801 self.conformance_violations = violations;
802 self
803 }
804
805 #[must_use]
807 pub fn replicate(mut self, replicate: u32) -> Self {
808 self.replicate = replicate;
809 self
810 }
811
812 #[must_use]
814 pub fn n_predict(mut self, n_predict: u32) -> Self {
815 self.n_predict = Some(n_predict);
816 self
817 }
818
819 #[must_use]
821 pub fn stream_mode(mut self, stream_mode: StreamMode) -> Self {
822 self.stream_mode = Some(stream_mode);
823 self
824 }
825
826 #[must_use]
828 pub fn witness(mut self, witness: BatchInvarianceWitness) -> Self {
829 self.witness = Some(witness);
830 self
831 }
832
833 #[must_use]
835 pub fn samples_file(mut self, samples_file: SamplesFile) -> Self {
836 self.samples_file = Some(samples_file);
837 self
838 }
839
840 #[must_use]
842 pub fn lane(mut self, lane: LaneConfig) -> Self {
843 self.lane = lane;
844 self
845 }
846
847 pub fn derive(&self) -> Result<DerivedBand, String> {
856 self.derive_in(&BandContext::default())
857 }
858
859 pub fn derive_at(&self, schema_version: u32) -> Result<DerivedBand, String> {
864 self.derive_in(&BandContext::at_schema_version(schema_version))
865 }
866
867 pub fn derive_in(&self, ctx: &BandContext) -> Result<DerivedBand, String> {
872 self.validate()?;
873 let drain_ms = self.drain_ms();
874 let span_ms = self.span_ms();
875 let tokens_total = self.tokens_total();
876 let short_of_n_predict = self.short_of_n_predict();
877 let stream_witness = self.stream_witness(ctx.stream_live_ttft_over_e2e_max);
878 let stream_live = stream_witness.is_some_and(|w| w.verdict == StreamVerdict::Live);
882 let invalid_correctness = self.invalid_correctness(ctx);
883
884 let mut unproduced = Vec::new();
885 let latency = if stream_live {
886 Latency::from(self)
887 } else {
888 unproduced.push(self.stream_reason(stream_witness.as_ref()));
889 Latency::none()
890 };
891 let mut prefill = self.prefill_tok_per_sec();
892 if prefill.is_none() {
893 unproduced.push(format!(
894 "PP-4 c={}: prefill_tok_per_sec — no request carried a server-reported \
895 `timings.prompt_ms`, and a client-side prefill estimate is exactly the \
896 harness-inferred field PP-13 refuses",
897 self.concurrency
898 ));
899 }
900 let mut aggregate = Some(rate_per_sec(tokens_total as f64, span_ms));
901 let mut latency = latency;
902 if invalid_correctness {
903 aggregate = None;
904 prefill = None;
905 latency.decode_tok_per_sec = None;
906 unproduced.push(format!(
907 "P-4 c={}: aggregate_tok_per_sec, decode_tok_per_sec and prefill_tok_per_sec — \
908 the band's batch-invariance witness (PP-26) is {} , so its throughput is not \
909 reported, not gated and never a baseline",
910 self.concurrency,
911 self.witness.as_ref().map_or_else(
912 || "absent".to_string(),
913 |w| format!("{:?}", w.batch_invariance)
914 )
915 ));
916 }
917 if short_of_n_predict > 0 {
918 unproduced.push(format!(
919 "PP-28 c={}: {short_of_n_predict} of {} completed requests did not reach \
920 n_predict — the sampler pin was not honoured, so this band is a record and not \
921 a baseline",
922 self.concurrency,
923 self.count(Outcome::Completed)
924 ));
925 }
926 for violation in &self.conformance_violations {
927 unproduced.push(format!(
928 "§4.4.2 c={}: protocol violation observed by the driver — {violation}. The band \
929 is NONCONFORMANT-VALID: a record, cited, never a baseline.",
930 self.concurrency
931 ));
932 }
933 let metrics_complete =
935 aggregate.is_some() && latency.decode_tok_per_sec.is_some() && prefill.is_some();
936 let status = self.status(
937 ctx,
938 invalid_correctness,
939 stream_live,
940 short_of_n_predict,
941 metrics_complete,
942 );
943 if status == BandStatus::NonconformantValid {
944 unproduced.push(format!(
945 "§7.4 c={}: this band is NONCONFORMANT-VALID — a historical record, cited, never \
946 a baseline",
947 self.concurrency
948 ));
949 }
950
951 Ok(DerivedBand {
952 concurrency: self.concurrency,
953 replicate: self.replicate,
954 window_ms: self.window_ms,
955 drain_ms,
956 suspect: self.suspect(drain_ms),
957 requested: self.requests.len(),
958 completed: self.count(Outcome::Completed),
959 timeouts: self.count(Outcome::Timeout),
960 truncated: self.count(Outcome::AbandonedAtDrain),
961 errors: self.count(Outcome::Failed),
962 short_of_n_predict,
963 tokens_total,
964 span_ms,
965 aggregate_tok_per_sec: aggregate,
966 decode_tok_per_sec: latency.decode_tok_per_sec,
967 prefill_tok_per_sec: prefill,
968 ttft_p50_ms: latency.ttft_p50_ms,
969 ttft_p95_ms: latency.ttft_p95_ms,
970 itl_p50_ms: latency.itl_p50_ms,
971 itl_p95_ms: latency.itl_p95_ms,
972 latencies_ms: self.latencies_ms(),
973 samples: self.sample_rows(),
974 samples_file: self.samples_file.clone(),
975 stream_mode: self.stream_mode,
976 stream_witness,
977 witness: self.witness.clone(),
978 status,
979 join_key: None,
980 run_id: None,
981 unproduced,
982 comparator: self.comparator.clone(),
983 })
984 }
985
986 pub fn join_status(
997 subject: &Self,
998 comparator: &Self,
999 subject_key: &JoinKey,
1000 comparator_key: &JoinKey,
1001 run_ids: (&RunId, &RunId),
1002 ) -> Result<ComparatorStatus, String> {
1003 Self::join_status_in(
1004 subject,
1005 comparator,
1006 subject_key,
1007 comparator_key,
1008 run_ids,
1009 &BandContext::default(),
1010 )
1011 }
1012
1013 pub fn join_status_in(
1018 subject: &Self,
1019 comparator: &Self,
1020 subject_key: &JoinKey,
1021 comparator_key: &JoinKey,
1022 run_ids: (&RunId, &RunId),
1023 ctx: &BandContext,
1024 ) -> Result<ComparatorStatus, String> {
1025 let (subject_run, comparator_run) = run_ids;
1026 if subject_run != comparator_run {
1027 return Err(format!(
1028 "PP-3: the comparator lane is run_id {} and the subject is run_id {} — a ratio is \
1029 representable only against a baseline from the SAME run; two runs saw two \
1030 thermal states, two free-VRAM figures and two schedulers",
1031 comparator_run.as_str(),
1032 subject_run.as_str()
1033 ));
1034 }
1035 subject_key.refuse_mismatch(comparator_key)?;
1036 let subject_band = subject.derive_in(ctx)?;
1037 let comparator_band = comparator.derive_in(ctx)?;
1038 for (lane, band) in [("subject", &subject_band), ("comparator", &comparator_band)] {
1039 if band.timeouts > 0 {
1040 return Err(format!(
1041 "PP-5: the {lane} lane at c={} recorded {} timeouts — a timed-out band cannot \
1042 carry a ratio, because the requests that did not return are exactly the ones \
1043 the ratio would have to account for",
1044 band.concurrency, band.timeouts
1045 ));
1046 }
1047 }
1048 let ratios = ratios_of(subject, comparator, &subject_band, &comparator_band)?;
1049 Ok(ComparatorStatus::Measured(MeasuredJoin::sealed(
1050 comparator_band
1051 .with_run_id(comparator_run.clone())
1052 .with_join_key(comparator_key.clone()),
1053 ratios,
1054 )))
1055 }
1056
1057 pub fn join(
1063 subject: &Self,
1064 comparator: &Self,
1065 subject_key: &JoinKey,
1066 comparator_key: &JoinKey,
1067 run_ids: (&RunId, &RunId),
1068 ) -> Result<DerivedBand, String> {
1069 let status = Self::join_status(subject, comparator, subject_key, comparator_key, run_ids)?;
1070 let joined = Self {
1071 comparator: status,
1072 ..subject.clone()
1073 };
1074 Ok(joined
1075 .derive()?
1076 .with_run_id(run_ids.0.clone())
1077 .with_join_key(subject_key.clone()))
1078 }
1079
1080 fn completed_iter(&self) -> impl Iterator<Item = &RequestOutcome> {
1081 self.requests
1082 .iter()
1083 .filter(|r| r.outcome == Outcome::Completed)
1084 }
1085
1086 fn count(&self, outcome: Outcome) -> usize {
1087 self.requests
1088 .iter()
1089 .filter(|r| r.outcome == outcome)
1090 .count()
1091 }
1092
1093 fn tokens_total(&self) -> u64 {
1094 self.completed_iter()
1095 .map(|r| u64::from(r.generated_tokens))
1096 .sum()
1097 }
1098
1099 fn short_of_n_predict(&self) -> usize {
1106 self.completed_iter()
1107 .filter(|r| {
1108 r.expected_tokens
1109 .or(self.n_predict)
1110 .is_some_and(|want| r.generated_tokens != want)
1111 })
1112 .count()
1113 }
1114
1115 fn stream_witness(&self, live_max: f64) -> Option<StreamWitness> {
1134 let ratios: Vec<f64> = self
1135 .completed_iter()
1136 .filter_map(RequestOutcome::ttft_over_e2e)
1137 .collect();
1138 let median = percentile(&sorted(ratios), 0.50)?;
1139 let client_live = median <= live_max;
1140 let (verdict, source) = match (self.stream_mode, client_live) {
1141 (Some(StreamMode::Replayed), _) => {
1142 (StreamVerdict::Replayed, StreamWitnessSource::Server)
1143 }
1144 (Some(StreamMode::Live), true) => (StreamVerdict::Live, StreamWitnessSource::Server),
1145 (Some(StreamMode::Live), false) => {
1146 (StreamVerdict::Replayed, StreamWitnessSource::Client)
1147 }
1148 (None, true) => (StreamVerdict::Live, StreamWitnessSource::Client),
1149 (None, false) => (StreamVerdict::Undeclared, StreamWitnessSource::Client),
1150 };
1151 Some(StreamWitness {
1152 client_ttft_over_e2e_median: median,
1153 verdict,
1154 source,
1155 })
1156 }
1157
1158 fn stream_reason(&self, witness: Option<&StreamWitness>) -> String {
1159 let verdict = witness.map_or(StreamVerdict::Undeclared, |w| w.verdict);
1160 let observed = witness.map_or_else(
1161 || "no completed request reported a first-token instant".to_string(),
1162 |w| format!("median(ttft/e2e)={:.3}", w.client_ttft_over_e2e_median),
1163 );
1164 format!(
1165 "PP-27 c={}: decode_tok_per_sec, ttft_ms p50/p95 and itl_ms p50/p95 — stream verdict \
1166 {verdict:?} ({observed}); a latency computed off a replayed or undeclared stream is a \
1167 property of the replay, not of the server",
1168 self.concurrency
1169 )
1170 }
1171
1172 fn invalid_correctness(&self, ctx: &BandContext) -> bool {
1183 self.role == Lane::Apr
1184 && ctx.schema_version >= SCHEMA_VERSION
1185 && self.concurrency > 1
1186 && !self
1187 .witness
1188 .as_ref()
1189 .is_some_and(BatchInvarianceWitness::passed)
1190 }
1191
1192 fn status(
1200 &self,
1201 ctx: &BandContext,
1202 invalid_correctness: bool,
1203 stream_live: bool,
1204 short_of_n_predict: usize,
1205 metrics_complete: bool,
1206 ) -> BandStatus {
1207 let v3 = ctx.schema_version >= SCHEMA_VERSION;
1212 let nonconformant = self.count(Outcome::Timeout) > 0
1213 || !self.conformance_violations.is_empty()
1214 || (v3
1215 && (!ctx.interleaved
1216 || (ctx.replicates as usize) < MIN_REPLICATES
1217 || !stream_live
1218 || short_of_n_predict > 0
1219 || !metrics_complete));
1220 let mut status = match self.comparator {
1221 ComparatorStatus::Measured(_) => BandStatus::Measured,
1222 ComparatorStatus::NotApplicable { .. } => BandStatus::Na,
1223 ComparatorStatus::Unmeasured { .. } => BandStatus::Unmeasured,
1224 };
1225 if nonconformant {
1226 status = status.stronger_of(BandStatus::NonconformantValid);
1227 }
1228 if ctx.comparator_stale {
1229 status = status.stronger_of(BandStatus::ComparatorStale);
1230 }
1231 if invalid_correctness {
1232 status = status.stronger_of(BandStatus::InvalidCorrectness);
1233 }
1234 status
1235 }
1236
1237 fn drain_ms(&self) -> f64 {
1239 let last = self
1240 .requests
1241 .iter()
1242 .map(|r| r.settled_ms)
1243 .fold(f64::NEG_INFINITY, f64::max);
1244 (last - self.window_ms).max(0.0)
1245 }
1246
1247 fn span_ms(&self) -> f64 {
1249 let first = self
1250 .requests
1251 .iter()
1252 .map(|r| r.issued_ms)
1253 .fold(f64::INFINITY, f64::min);
1254 let last = self
1255 .completed_iter()
1256 .map(|r| r.settled_ms)
1257 .fold(f64::NEG_INFINITY, f64::max);
1258 (last - first).max(0.0)
1259 }
1260
1261 fn suspect(&self, drain_ms: f64) -> Vec<String> {
1262 if self.window_ms > 0.0 && drain_ms > DRAIN_SUSPECT_FRACTION * self.window_ms {
1263 return vec![format!(
1264 "SUSPECT PP-10 c={}: drain_ms={drain_ms:.1} > 0.5 x window_ms={:.1} — one \
1265 request dominated the window; re-run this band with a longer window",
1266 self.concurrency, self.window_ms
1267 )];
1268 }
1269 Vec::new()
1270 }
1271
1272 fn latencies_ms(&self) -> Vec<f64> {
1273 self.completed_iter()
1274 .map(RequestOutcome::duration_ms)
1275 .collect()
1276 }
1277
1278 fn sample_rows(&self) -> Vec<SampleRow> {
1279 self.requests
1280 .iter()
1281 .enumerate()
1282 .map(|(i, r)| r.to_row(i))
1283 .collect()
1284 }
1285
1286 fn request_samples(&self) -> Vec<RequestSample> {
1288 self.requests
1289 .iter()
1290 .enumerate()
1291 .map(|(i, r)| r.to_sample(i, self.concurrency))
1292 .collect()
1293 }
1294
1295 fn decode_median(&self) -> Option<f64> {
1296 let rates: Vec<f64> = self
1297 .completed_iter()
1298 .filter_map(RequestOutcome::decode_tok_per_sec)
1299 .collect();
1300 percentile(&sorted(rates), 0.50)
1301 }
1302
1303 fn ttft_percentile(&self, p: f64) -> Option<f64> {
1304 let v: Vec<f64> = self.completed_iter().filter_map(|r| r.ttft_ms).collect();
1305 percentile(&sorted(v), p)
1306 }
1307
1308 fn itl_percentile(&self, p: f64) -> Option<f64> {
1309 let v: Vec<f64> = self
1310 .completed_iter()
1311 .flat_map(RequestOutcome::itl_gaps_ms)
1312 .collect();
1313 percentile(&sorted(v), p)
1314 }
1315
1316 fn prefill_tok_per_sec(&self) -> Option<f64> {
1324 let mut tokens = 0_u64;
1325 let mut ms = 0.0_f64;
1326 for r in self.completed_iter() {
1327 if let Some(p) = r.prefill_ms {
1328 if p > 0.0 {
1329 tokens += u64::from(r.prompt_tokens);
1330 ms += p;
1331 }
1332 }
1333 }
1334 if ms <= 0.0 || tokens == 0 {
1335 return None;
1336 }
1337 Some(tokens as f64 / (ms / 1000.0))
1338 }
1339
1340 fn validate(&self) -> Result<(), String> {
1341 if self.requests.is_empty() {
1342 return Err(format!(
1343 "band c={}: no sampled requests — a band over zero requests is a vacuous pass, \
1344 not a measurement",
1345 self.concurrency
1346 ));
1347 }
1348 if self.window_ms.is_nan() || self.window_ms <= 0.0 {
1350 return Err(format!(
1351 "band c={}: window_ms={} — the window must have positive length or `drain_ms` \
1352 and the SUSPECT fraction are both undefined",
1353 self.concurrency, self.window_ms
1354 ));
1355 }
1356 for (i, r) in self.requests.iter().enumerate() {
1357 validate_request(self.concurrency, i, r, self.window_ms)?;
1358 }
1359 Ok(())
1360 }
1361}
1362
1363struct Latency {
1365 decode_tok_per_sec: Option<f64>,
1366 ttft_p50_ms: Option<f64>,
1367 ttft_p95_ms: Option<f64>,
1368 itl_p50_ms: Option<f64>,
1369 itl_p95_ms: Option<f64>,
1370}
1371
1372impl Latency {
1373 fn from(band: &BandInput) -> Self {
1374 Self {
1375 decode_tok_per_sec: band.decode_median(),
1376 ttft_p50_ms: band.ttft_percentile(0.50),
1377 ttft_p95_ms: band.ttft_percentile(0.95),
1378 itl_p50_ms: band.itl_percentile(0.50),
1379 itl_p95_ms: band.itl_percentile(0.95),
1380 }
1381 }
1382
1383 fn none() -> Self {
1384 Self {
1385 decode_tok_per_sec: None,
1386 ttft_p50_ms: None,
1387 ttft_p95_ms: None,
1388 itl_p50_ms: None,
1389 itl_p95_ms: None,
1390 }
1391 }
1392}
1393
1394fn ratios_of(
1396 subject: &BandInput,
1397 comparator: &BandInput,
1398 subject_band: &DerivedBand,
1399 comparator_band: &DerivedBand,
1400) -> Result<BandRatios, String> {
1401 let agg = window_ratio(
1402 subject_band.aggregate_tok_per_sec,
1403 comparator_band.aggregate_tok_per_sec,
1404 )
1405 .ok_or_else(|| {
1406 format!(
1407 "P-5: neither lane at c={} produced an aggregate throughput, so there is no agg ratio \
1408 to form",
1409 subject_band.concurrency
1410 )
1411 })?;
1412 let dec = if subject_band.decode_tok_per_sec.is_some()
1420 && comparator_band.decode_tok_per_sec.is_some()
1421 {
1422 paired_ratio_lcb(
1423 &subject.request_samples(),
1424 &comparator.request_samples(),
1425 median_decode_tok_s,
1426 VERDICT_CONFIDENCE,
1427 )
1428 } else {
1429 None
1430 };
1431 let prefill = window_ratio(
1432 subject_band.prefill_tok_per_sec,
1433 comparator_band.prefill_tok_per_sec,
1434 );
1435 Ok(BandRatios { agg, dec, prefill })
1436}
1437
1438fn window_ratio(subject: Option<f64>, comparator: Option<f64>) -> Option<Ratio> {
1441 let (s, c) = (subject?, comparator?);
1442 if c <= 0.0 {
1443 return None;
1444 }
1445 Some(Ratio::reporting_only(
1446 s / c,
1447 RatioMethod::ReplicateTLower,
1448 1,
1449 ))
1450}
1451
1452#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1454#[serde(deny_unknown_fields)]
1455pub struct DerivedBand {
1456 pub concurrency: u32,
1458 pub replicate: u32,
1460 pub window_ms: f64,
1462 pub drain_ms: f64,
1464 pub suspect: Vec<String>,
1466 pub requested: usize,
1468 pub completed: usize,
1470 pub timeouts: usize,
1472 pub truncated: usize,
1474 pub errors: usize,
1476 pub short_of_n_predict: usize,
1478 pub tokens_total: u64,
1480 pub span_ms: f64,
1482 pub aggregate_tok_per_sec: Option<f64>,
1485 pub decode_tok_per_sec: Option<f64>,
1487 pub prefill_tok_per_sec: Option<f64>,
1489 pub ttft_p50_ms: Option<f64>,
1491 pub ttft_p95_ms: Option<f64>,
1493 pub itl_p50_ms: Option<f64>,
1495 pub itl_p95_ms: Option<f64>,
1497 pub latencies_ms: Vec<f64>,
1499 pub samples: Vec<SampleRow>,
1501 pub samples_file: Option<SamplesFile>,
1503 pub stream_mode: Option<StreamMode>,
1505 pub stream_witness: Option<StreamWitness>,
1507 pub witness: Option<BatchInvarianceWitness>,
1509 pub status: BandStatus,
1511 pub join_key: Option<JoinKey>,
1513 pub run_id: Option<RunId>,
1515 pub unproduced: Vec<String>,
1518 pub comparator: ComparatorStatus,
1520}
1521
1522impl DerivedBand {
1523 #[must_use]
1526 pub fn with_join_key(mut self, key: JoinKey) -> Self {
1527 self.join_key = Some(key);
1528 self
1529 }
1530
1531 #[must_use]
1533 pub fn with_run_id(mut self, run_id: RunId) -> Self {
1534 self.run_id = Some(run_id);
1535 self
1536 }
1537
1538 #[must_use]
1548 pub fn marked_comparator_stale(mut self, pin_expiry: &str, started_utc: &str) -> Self {
1549 self.status = self.status.stronger_of(BandStatus::ComparatorStale);
1550 self.unproduced.push(format!(
1551 "PP-20 c={}: the comparator pin expired {pin_expiry}, before this run started \
1552 {started_utc} — every ratio on this band is COMPARATOR_STALE and blocks MEASURED \
1553 until the pin is refreshed",
1554 self.concurrency
1555 ));
1556 self
1557 }
1558
1559 #[must_use]
1561 pub fn baseline_eligible(&self) -> bool {
1562 self.status.baseline_eligible()
1563 }
1564}
1565
1566fn validate_request(c: u32, i: usize, r: &RequestOutcome, window_ms: f64) -> Result<(), String> {
1568 let at = format!("band c={c} request[{i}]");
1569 if r.issued_ms >= window_ms {
1570 return Err(format!(
1571 "{at}: issued_ms={} >= T={window_ms} — PP-10: no request is issued at or after the \
1572 window close, and its tokens are never counted",
1573 r.issued_ms
1574 ));
1575 }
1576 if r.settled_ms < r.issued_ms {
1577 return Err(format!(
1578 "{at}: settled_ms={} precedes issued_ms={}",
1579 r.settled_ms, r.issued_ms
1580 ));
1581 }
1582 validate_outcome(&at, r, window_ms)
1583}
1584
1585fn validate_outcome(at: &str, r: &RequestOutcome, window_ms: f64) -> Result<(), String> {
1587 let d = r.duration_ms();
1588 match r.outcome {
1589 Outcome::Completed if r.generated_tokens == 0 => Err(format!(
1590 "{at}: completed with zero generated tokens — a zero-token response is a failure, not \
1591 a fast request"
1592 )),
1593 Outcome::Timeout if d < REQUEST_TIMEOUT_MS => Err(format!(
1594 "{at}: labelled Timeout but ran {d:.1} ms < the {REQUEST_TIMEOUT_MS} ms hard timeout \
1595 (§3) — that is a Failed, and the two are separate counters"
1596 )),
1597 Outcome::Failed if d >= REQUEST_TIMEOUT_MS => Err(format!(
1598 "{at}: labelled Failed but ran {d:.1} ms >= the {REQUEST_TIMEOUT_MS} ms hard timeout \
1599 — that is a Timeout, which PP-5 makes fatal to this band's ratio"
1600 )),
1601 Outcome::AbandonedAtDrain if r.settled_ms < window_ms => Err(format!(
1602 "{at}: labelled AbandonedAtDrain but settled at {}, before T={window_ms} — a request \
1603 can only be abandoned during the drain",
1604 r.settled_ms
1605 )),
1606 _ => Ok(()),
1607 }
1608}
1609
1610fn rate_per_sec(count: f64, span_ms: f64) -> f64 {
1611 if span_ms <= 0.0 {
1612 return 0.0;
1613 }
1614 count / (span_ms / 1000.0)
1615}
1616
1617fn sorted(mut v: Vec<f64>) -> Vec<f64> {
1618 v.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
1619 v
1620}
1621
1622#[must_use]
1627pub fn percentile(sorted_ascending: &[f64], p: f64) -> Option<f64> {
1628 match sorted_ascending.len() {
1629 0 => None,
1630 1 => Some(sorted_ascending[0]),
1631 n => {
1632 let idx = (n as f64 - 1.0) * p;
1633 let lo = idx.floor() as usize;
1634 let hi = (lo + 1).min(n - 1);
1635 let frac = idx - lo as f64;
1636 Some(sorted_ascending[lo].mul_add(1.0 - frac, sorted_ascending[hi] * frac))
1637 }
1638 }
1639}
1640
1641#[cfg(test)]
1642mod tests {
1643 #![allow(non_snake_case)]
1647 use super::*;
1648 use crate::perf_gate::receipt::{TokenCountingMethod, Workload};
1649 use crate::perf_gate::witness::BatchInvariance;
1650
1651 fn done(issued_ms: f64, dur_ms: f64, tokens: u32) -> RequestOutcome {
1654 RequestOutcome::completed(issued_ms, issued_ms + dur_ms, tokens)
1655 }
1656
1657 fn streamed(issued_ms: f64, dur_ms: f64, tokens: u32) -> RequestOutcome {
1660 let ttft = dur_ms * 0.08;
1661 let times: Vec<f64> = (0..tokens)
1662 .map(|k| issued_ms + ttft + f64::from(k) * (dur_ms - ttft) / f64::from(tokens))
1663 .collect();
1664 done(issued_ms, dur_ms, tokens)
1665 .streamed(ttft, times)
1666 .server_prefill(512, dur_ms * 0.05)
1667 }
1668
1669 fn unmeasured() -> ComparatorStatus {
1670 ComparatorStatus::unmeasured("perf-gate", "no comparator lane on this cell yet (PP-25)")
1671 }
1672
1673 fn band(window_ms: f64, requests: Vec<RequestOutcome>) -> BandInput {
1677 BandInput::new(1, window_ms, requests, unmeasured())
1678 }
1679
1680 fn passing_witness() -> BatchInvarianceWitness {
1681 let tokens: Vec<u32> = (0..128).collect();
1682 BatchInvarianceWitness::compare(&tokens, &tokens, 64).formed_at(4, "perf041")
1683 }
1684
1685 fn conformant_band(concurrency: u32) -> BandInput {
1688 let requests: Vec<RequestOutcome> = (0..8)
1689 .map(|i| streamed(f64::from(i) * 100.0, 90.0 + f64::from(i), 128))
1690 .collect();
1691 BandInput::new(concurrency, 1000.0, requests, unmeasured())
1692 .n_predict(128)
1693 .stream_mode(StreamMode::Live)
1694 .witness(passing_witness())
1695 }
1696
1697 #[test]
1700 fn drain_ms_is_zero_when_nothing_straddles_the_window_close() {
1701 let d = band(1000.0, vec![done(0.0, 100.0, 128), done(200.0, 100.0, 128)])
1702 .derive()
1703 .expect("valid band");
1704 assert_eq!(d.drain_ms, 0.0);
1705 assert!(d.suspect.is_empty(), "{:?}", d.suspect);
1706 }
1707
1708 #[test]
1712 fn drain_ms_varies_with_actual_drain_behaviour() {
1713 let quiet = band(1000.0, vec![done(0.0, 100.0, 128), done(900.0, 50.0, 128)])
1714 .derive()
1715 .expect("valid band");
1716 let straggler = band(1000.0, vec![done(0.0, 100.0, 128), done(900.0, 350.0, 128)])
1717 .derive()
1718 .expect("valid band");
1719 assert_eq!(quiet.drain_ms, 0.0);
1720 assert!((straggler.drain_ms - 250.0).abs() < 1e-9, "{straggler:?}");
1721 assert_ne!(quiet.drain_ms, straggler.drain_ms);
1722 }
1723
1724 #[test]
1726 fn a_dominating_request_is_annotated_suspect() {
1727 let d = band(1000.0, vec![done(0.0, 50.0, 128), done(900.0, 700.0, 128)])
1728 .derive()
1729 .expect("valid band");
1730 assert!((d.drain_ms - 600.0).abs() < 1e-9, "{d:?}");
1731 assert_eq!(d.suspect.len(), 1, "{:?}", d.suspect);
1732 assert!(d.suspect[0].contains("drain_ms"), "{:?}", d.suspect);
1733 }
1734
1735 #[test]
1737 fn a_drain_just_under_half_the_window_is_not_suspect() {
1738 let d = band(1000.0, vec![done(0.0, 50.0, 128), done(900.0, 599.0, 128)])
1739 .derive()
1740 .expect("valid band");
1741 assert!((d.drain_ms - 499.0).abs() < 1e-9, "{d:?}");
1742 assert!(d.suspect.is_empty(), "{:?}", d.suspect);
1743 }
1744
1745 #[test]
1748 fn a_request_issued_at_or_after_t_is_refused() {
1749 let at_t = band(1000.0, vec![done(0.0, 10.0, 8), done(1000.0, 10.0, 8)]).derive();
1750 let after_t = band(1000.0, vec![done(0.0, 10.0, 8), done(1500.0, 10.0, 8)]).derive();
1751 for (label, got) in [("at T", at_t), ("after T", after_t)] {
1752 let err = got.expect_err(label);
1753 assert!(err.contains("PP-10"), "{label}: {err}");
1754 }
1755 }
1756
1757 #[test]
1763 fn max_tokens_truncation_is_not_drain_truncation() {
1764 let reqs: Vec<RequestOutcome> = (0..8)
1765 .map(|i| done(f64::from(i) * 100.0, 90.0, 128))
1766 .collect();
1767 let d = band(1000.0, reqs).derive().expect("valid band");
1768 assert_eq!(
1769 d.truncated, 0,
1770 "no request was abandoned at the drain deadline"
1771 );
1772 assert_eq!(d.completed, 8);
1773 assert_eq!(d.tokens_total, 1024, "the numerator must not be emptied");
1774 assert!(
1775 d.aggregate_tok_per_sec.expect("agg") > 0.0,
1776 "{:?}",
1777 d.aggregate_tok_per_sec
1778 );
1779 }
1780
1781 #[test]
1783 fn an_abandoned_request_increments_truncated_not_completed() {
1784 let abandoned = RequestOutcome::new(900.0, 1400.0, Outcome::AbandonedAtDrain, 12);
1785 let d = band(1000.0, vec![done(0.0, 100.0, 128), abandoned])
1786 .derive()
1787 .expect("valid band");
1788 assert_eq!(d.truncated, 1);
1789 assert_eq!(d.completed, 1);
1790 assert_eq!(
1791 d.tokens_total, 128,
1792 "an abandoned request contributes no tokens"
1793 );
1794 assert!((d.drain_ms - 400.0).abs() < 1e-9, "{d:?}");
1795 }
1796
1797 #[test]
1799 fn an_abandonment_before_the_window_close_is_refused() {
1800 let bogus = RequestOutcome::new(100.0, 200.0, Outcome::AbandonedAtDrain, 1);
1801 let err = band(1000.0, vec![done(0.0, 10.0, 8), bogus])
1802 .derive()
1803 .expect_err("settled before T");
1804 assert!(err.contains("only be abandoned during the drain"), "{err}");
1805 }
1806
1807 #[test]
1810 fn timeouts_and_failures_are_separate_and_both_are_verified() {
1811 let timeout = RequestOutcome::new(10.0, 10.0 + REQUEST_TIMEOUT_MS, Outcome::Timeout, 0);
1812 let failure = RequestOutcome::new(20.0, 45.0, Outcome::Failed, 0);
1813 let with_both = band(
1814 1000.0,
1815 vec![done(0.0, 10.0, 8), timeout.clone(), failure.clone()],
1816 );
1817 let d = with_both.derive().expect("valid band");
1818 assert_eq!(d.timeouts, 1);
1819 assert_eq!(d.errors, 1);
1820 assert_eq!(
1821 d.requested,
1822 d.completed + d.timeouts + d.truncated + d.errors,
1823 "the four counters must partition the requests"
1824 );
1825 assert_eq!(
1826 d.status,
1827 BandStatus::NonconformantValid,
1828 "PP-5: a band that timed out is a record, at every schema version"
1829 );
1830 assert_eq!(
1831 with_both.derive_at(2).expect("renders").status,
1832 BandStatus::NonconformantValid,
1833 "…including a v2-dated one"
1834 );
1835 }
1836
1837 #[test]
1840 fn a_short_request_cannot_be_labelled_a_timeout() {
1841 let liar = RequestOutcome::new(0.0, 50.0, Outcome::Timeout, 0);
1842 let err = band(1000.0, vec![done(500.0, 10.0, 8), liar])
1843 .derive()
1844 .expect_err("50 ms is not a timeout");
1845 assert!(err.contains("hard timeout"), "{err}");
1846 }
1847
1848 #[test]
1851 fn an_over_long_request_cannot_be_labelled_a_plain_failure() {
1852 let liar = RequestOutcome::new(0.0, REQUEST_TIMEOUT_MS + 1.0, Outcome::Failed, 0);
1853 let err = band(1000.0, vec![done(500.0, 10.0, 8), liar])
1854 .derive()
1855 .expect_err("past the hard timeout");
1856 assert!(err.contains("PP-5"), "{err}");
1857 }
1858
1859 #[test]
1861 fn a_zero_token_completion_is_refused() {
1862 let err = band(1000.0, vec![done(0.0, 10.0, 0)])
1863 .derive()
1864 .expect_err("zero tokens");
1865 assert!(err.contains("zero-token"), "{err}");
1866 }
1867
1868 #[test]
1869 fn an_empty_band_is_refused() {
1870 let err = band(1000.0, Vec::new()).derive().expect_err("no requests");
1871 assert!(err.contains("vacuous"), "{err}");
1872 }
1873
1874 #[test]
1875 fn a_non_positive_window_is_refused() {
1876 let err = band(0.0, vec![done(-10.0, 5.0, 8)])
1877 .derive()
1878 .expect_err("zero window");
1879 assert!(err.contains("window_ms"), "{err}");
1880 }
1881
1882 #[test]
1885 fn aggregate_is_wall_clock_over_the_whole_span() {
1886 let d = band(
1888 2500.0,
1889 vec![done(0.0, 500.0, 100), done(1000.0, 1000.0, 100)],
1890 )
1891 .derive()
1892 .expect("valid band");
1893 assert!((d.span_ms - 2000.0).abs() < 1e-9, "{d:?}");
1894 assert!(
1895 (d.aggregate_tok_per_sec.expect("agg") - 100.0).abs() < 1e-9,
1896 "200 tokens over 2 s = 100 tok/s, got {:?}",
1897 d.aggregate_tok_per_sec
1898 );
1899 }
1900
1901 #[test]
1905 fn a_non_streaming_band_names_what_it_could_not_produce() {
1906 let d = band(1000.0, vec![done(0.0, 100.0, 128)])
1907 .derive()
1908 .expect("valid band");
1909 assert_eq!(d.ttft_p50_ms, None);
1910 assert_eq!(d.itl_p95_ms, None);
1911 assert_eq!(d.decode_tok_per_sec, None);
1912 assert_eq!(d.prefill_tok_per_sec, None);
1913 assert_eq!(d.status, BandStatus::NonconformantValid);
1914 let notes = d.unproduced.join("\n");
1915 assert!(notes.contains("PP-27"), "{notes}");
1916 assert!(notes.contains("PP-4"), "{notes}");
1917 }
1918
1919 #[test]
1922 fn a_streaming_band_produces_ttft_itl_and_decode() {
1923 let one = RequestOutcome::completed(0.0, 500.0, 5)
1924 .streamed(100.0, vec![100.0, 200.0, 300.0, 400.0, 500.0])
1925 .server_prefill(512, 90.0);
1926 let d = BandInput::new(1, 1000.0, vec![one], unmeasured())
1927 .stream_mode(StreamMode::Live)
1928 .n_predict(5)
1929 .derive()
1930 .expect("valid band");
1931 assert_eq!(d.ttft_p50_ms, Some(100.0));
1932 assert_eq!(d.itl_p50_ms, Some(100.0));
1933 assert_eq!(d.decode_tok_per_sec, Some(10.0));
1935 assert!(
1937 (d.prefill_tok_per_sec.expect("prefill") - 512.0 / 0.09).abs() < 1e-6,
1938 "{:?}",
1939 d.prefill_tok_per_sec
1940 );
1941 assert!(d.unproduced.is_empty(), "{:?}", d.unproduced);
1942 assert_eq!(d.status, BandStatus::Unmeasured, "no comparator lane");
1943 }
1944
1945 #[test]
1946 fn percentile_of_nothing_is_undefined_not_zero() {
1947 assert_eq!(percentile(&[], 0.5), None);
1948 assert_eq!(percentile(&[7.0], 0.95), Some(7.0));
1949 assert_eq!(percentile(&[0.0, 10.0], 0.5), Some(5.0));
1950 }
1951
1952 #[test]
1953 fn comparator_status_renders_the_token_the_gate_reads() {
1954 assert_eq!(unmeasured().wire_token(), "UNMEASURED");
1955 let na = ComparatorStatus::not_applicable("perf-matrix.yaml", "vLLM has no aarch64 build");
1956 assert_eq!(na.wire_token(), "NOT_APPLICABLE");
1957 }
1958
1959 #[test]
1962 fn status_tokens_are_exactly_the_section_7_4_vocabulary() {
1963 let table = [
1964 (BandStatus::Measured, "MEASURED"),
1965 (BandStatus::Unmeasured, "UNMEASURED"),
1966 (BandStatus::Na, "NA"),
1967 (BandStatus::InvalidCorrectness, "INVALID-CORRECTNESS"),
1968 (BandStatus::NonconformantValid, "NONCONFORMANT-VALID"),
1969 (BandStatus::ComparatorStale, "COMPARATOR_STALE"),
1970 ];
1971 assert_eq!(table.len(), BandStatus::vocabulary().len());
1972 for (status, token) in table {
1973 assert_eq!(status.wire_token(), token);
1974 assert!(
1975 BandStatus::vocabulary().contains(&status),
1976 "{token} missing from the vocabulary"
1977 );
1978 }
1979 assert_ne!(
1980 BandStatus::Na.wire_token(),
1981 "NOT_APPLICABLE",
1982 "§7.4 spells it NA; NOT_APPLICABLE is the legacy comparator_status token"
1983 );
1984 assert!(BandStatus::Measured.baseline_eligible());
1985 for s in BandStatus::vocabulary() {
1986 if s != BandStatus::Measured {
1987 assert!(!s.baseline_eligible(), "{s:?} may not be a baseline");
1988 }
1989 }
1990 }
1991
1992 #[test]
1994 fn a_completed_sample_short_of_n_predict_is_counted() {
1995 let mut b = conformant_band(1);
1996 b.requests[3].generated_tokens = 67;
1997 let d = b.derive().expect("the band still renders");
1998 assert_eq!(d.short_of_n_predict, 1);
1999 assert_eq!(d.status, BandStatus::NonconformantValid);
2000 assert!(
2001 d.aggregate_tok_per_sec.is_some(),
2002 "the evidence still renders; PP-28 is not fatal to the receipt"
2003 );
2004 let notes = d.unproduced.join("\n");
2005 assert!(notes.contains("PP-28"), "{notes}");
2006 }
2007
2008 #[test]
2010 fn thirty_of_thirty_at_n_predict_pass() {
2011 let requests: Vec<RequestOutcome> = (0..30)
2012 .map(|i| streamed(f64::from(i) * 30.0, 90.0 + f64::from(i), 128))
2013 .collect();
2014 let d = BandInput::new(1, 1000.0, requests, unmeasured())
2015 .n_predict(128)
2016 .stream_mode(StreamMode::Live)
2017 .derive()
2018 .expect("valid band");
2019 assert_eq!(d.short_of_n_predict, 0);
2020 assert_eq!(d.completed, 30);
2021 assert_eq!(d.status, BandStatus::Unmeasured);
2022 }
2023
2024 #[test]
2026 fn a_band_with_short_samples_is_nonconformant() {
2027 let mut b = conformant_band(4);
2028 for r in &mut b.requests {
2029 r.generated_tokens = 112;
2030 }
2031 let d = b.derive().expect("renders");
2032 assert_eq!(d.short_of_n_predict, 8);
2033 assert_eq!(d.status, BandStatus::NonconformantValid);
2034 assert!(!d.baseline_eligible());
2035 }
2036
2037 #[test]
2040 fn a_per_request_expectation_overrides_the_band_pin() {
2041 let mut b = conformant_band(1);
2042 b.requests[0].generated_tokens = 64;
2043 assert_eq!(b.derive().expect("renders").short_of_n_predict, 1);
2044 b.requests[0] = b.requests[0].clone().expecting(64);
2045 assert_eq!(b.derive().expect("renders").short_of_n_predict, 0);
2046 }
2047
2048 #[test]
2050 fn a_replayed_stream_sends_latency_to_unproduced() {
2051 let d = conformant_band(1)
2052 .stream_mode(StreamMode::Replayed)
2053 .derive()
2054 .expect("renders");
2055 assert_eq!(d.decode_tok_per_sec, None);
2056 assert_eq!(d.ttft_p95_ms, None);
2057 assert_eq!(d.itl_p95_ms, None);
2058 assert_eq!(
2059 d.stream_witness.expect("witness").verdict,
2060 StreamVerdict::Replayed
2061 );
2062 assert_eq!(d.status, BandStatus::NonconformantValid);
2063 }
2064
2065 #[test]
2069 fn a_server_claiming_live_is_overruled_by_the_client_witness() {
2070 let late = RequestOutcome::completed(0.0, 500.0, 4)
2071 .streamed(499.0, vec![499.0, 499.5, 499.8, 500.0])
2072 .server_prefill(512, 40.0);
2073 let d = BandInput::new(1, 1000.0, vec![late], unmeasured())
2074 .stream_mode(StreamMode::Live)
2075 .n_predict(4)
2076 .derive()
2077 .expect("renders");
2078 let w = d.stream_witness.expect("witness");
2079 assert!(w.client_ttft_over_e2e_median > 0.95, "{w:?}");
2080 assert_eq!(w.verdict, StreamVerdict::Replayed);
2081 assert_eq!(d.decode_tok_per_sec, None);
2082 }
2083
2084 #[test]
2088 fn the_stream_threshold_is_exclusive_at_the_declared_maximum() {
2089 let ctx = BandContext {
2090 stream_live_ttft_over_e2e_max: 0.95,
2091 ..BandContext::default()
2092 };
2093 let at_threshold = |ratio: f64| {
2094 let e2e = 1000.0;
2095 let ttft = ratio * e2e;
2096 let one = RequestOutcome::completed(0.0, e2e, 4)
2097 .streamed(ttft, vec![ttft, ttft + 10.0, ttft + 20.0, ttft + 30.0])
2098 .server_prefill(512, 40.0);
2099 BandInput::new(1, 2_000.0, vec![one], unmeasured())
2100 .stream_mode(StreamMode::Live)
2101 .n_predict(4)
2102 .derive_in(&ctx)
2103 .expect("renders")
2104 };
2105 assert_eq!(
2106 at_threshold(0.95).stream_witness.expect("witness").verdict,
2107 StreamVerdict::Live,
2108 "exactly at the maximum is still live"
2109 );
2110 assert_eq!(
2111 at_threshold(0.951).stream_witness.expect("witness").verdict,
2112 StreamVerdict::Replayed
2113 );
2114 }
2115
2116 #[test]
2127 fn an_undeclared_stream_the_client_measured_as_live_is_live() {
2128 let d = BandInput::new(1, 1000.0, conformant_band(1).requests, unmeasured())
2129 .n_predict(128)
2130 .derive()
2131 .expect("renders");
2132 let w = d.stream_witness.expect("witness");
2133 assert_eq!(w.verdict, StreamVerdict::Live);
2134 assert_eq!(
2135 w.source,
2136 StreamWitnessSource::Client,
2137 "the server said nothing"
2138 );
2139 assert_eq!(d.stream_mode, None, "and the receipt still says so");
2140 assert!(d.decode_tok_per_sec.is_some(), "a live stream has a dec");
2141 assert_eq!(
2142 d.status,
2143 BandStatus::Unmeasured,
2144 "no comparator lane, but conformant"
2145 );
2146 }
2147
2148 #[test]
2153 fn an_undeclared_stream_the_client_cannot_call_live_is_undeclared() {
2154 let requests: Vec<RequestOutcome> = (0..6)
2156 .map(|i| {
2157 let issued = f64::from(i) * 10.0;
2158 RequestOutcome::completed(issued, issued + 100.0 + f64::from(i), 128)
2159 .streamed(99.0, vec![issued + 99.0, issued + 99.5, issued + 100.0])
2160 })
2161 .collect();
2162 let d = BandInput::new(1, 1000.0, requests, unmeasured())
2163 .n_predict(128)
2164 .derive()
2165 .expect("renders");
2166 let w = d.stream_witness.expect("witness");
2167 assert_eq!(w.verdict, StreamVerdict::Undeclared);
2168 assert_eq!(w.source, StreamWitnessSource::Client);
2169 assert_eq!(d.decode_tok_per_sec, None);
2170 assert_eq!(d.ttft_p50_ms, None);
2171 assert_eq!(d.itl_p95_ms, None);
2172 assert_eq!(d.status, BandStatus::NonconformantValid);
2173 }
2174
2175 #[test]
2178 fn a_constant_token_batch_is_invalid_correctness() {
2179 let m1: Vec<u32> = (0..128).map(|i| 1000 + i).collect();
2180 let failing = BatchInvarianceWitness::compare(&m1, &vec![474_u32; 128], 64)
2181 .formed_at(3, "scripts/perf041_batched_parity_probe.py");
2182 let d = conformant_band(4)
2183 .witness(failing)
2184 .derive()
2185 .expect("the band still renders");
2186 assert_eq!(d.status, BandStatus::InvalidCorrectness);
2187 assert_eq!(d.aggregate_tok_per_sec, None);
2188 assert_eq!(d.decode_tok_per_sec, None);
2189 assert_eq!(d.prefill_tok_per_sec, None);
2190 }
2191
2192 #[test]
2194 fn identical_128_token_prefixes_pass() {
2195 let d = conformant_band(4).derive().expect("renders");
2196 assert_eq!(
2197 d.witness.expect("witness").batch_invariance,
2198 BatchInvariance::Pass
2199 );
2200 assert_eq!(d.status, BandStatus::Unmeasured, "no comparator lane");
2201 assert!(d.aggregate_tok_per_sec.is_some());
2202 }
2203
2204 #[test]
2207 fn an_invalid_correctness_band_reports_no_throughput() {
2208 let d = conformant_band(8)
2209 .witness(BatchInvarianceWitness::compare(&[1, 2, 3], &[9, 9, 9], 64))
2210 .derive()
2211 .expect("renders");
2212 assert_eq!(d.status, BandStatus::InvalidCorrectness);
2213 assert!(!d.baseline_eligible());
2214 let notes = d.unproduced.join("\n");
2215 assert!(notes.contains("aggregate_tok_per_sec"), "{notes}");
2216 assert!(notes.contains("decode_tok_per_sec"), "{notes}");
2217 assert!(notes.contains("prefill_tok_per_sec"), "{notes}");
2218 }
2219
2220 #[test]
2223 fn c1_needs_no_witness() {
2224 let mut b = conformant_band(1);
2225 b.witness = None;
2226 let d = b.derive().expect("renders");
2227 assert_ne!(d.status, BandStatus::InvalidCorrectness);
2228 assert!(d.aggregate_tok_per_sec.is_some());
2229
2230 let mut wider = conformant_band(4);
2232 wider.witness = None;
2233 assert_eq!(
2234 wider.derive().expect("renders").status,
2235 BandStatus::InvalidCorrectness
2236 );
2237 }
2238
2239 #[test]
2242 fn a_v2_receipt_is_historical_not_a_baseline() {
2243 let mut b = conformant_band(4);
2244 b.witness = None;
2245 b.stream_mode = None;
2246 let v2 = b.derive_at(2).expect("renders");
2247 assert_ne!(v2.status, BandStatus::InvalidCorrectness);
2248 assert!(
2249 v2.aggregate_tok_per_sec.is_some(),
2250 "a v2 band keeps its throughput"
2251 );
2252 assert!(!v2.baseline_eligible(), "but is never a baseline");
2253 assert_eq!(
2254 b.derive_at(3).expect("renders").status,
2255 BandStatus::InvalidCorrectness,
2256 "the same band at v3"
2257 );
2258 }
2259
2260 #[test]
2263 fn a_measured_band_without_prefill_is_nonconformant() {
2264 let mut b = conformant_band(1);
2265 for r in &mut b.requests {
2266 r.prefill_ms = None;
2267 }
2268 let d = b.derive().expect("renders");
2269 assert_eq!(d.prefill_tok_per_sec, None);
2270 assert_eq!(d.status, BandStatus::NonconformantValid);
2271 assert!(d.unproduced.join("\n").contains("PP-13"));
2272 }
2273
2274 #[test]
2277 fn prefill_is_prompt_tokens_over_server_prefill_ms() {
2278 let a = RequestOutcome::completed(0.0, 500.0, 8)
2279 .streamed(
2280 40.0,
2281 vec![40.0, 100.0, 200.0, 300.0, 350.0, 400.0, 450.0, 500.0],
2282 )
2283 .server_prefill(500, 100.0);
2284 let b = RequestOutcome::completed(10.0, 520.0, 8)
2285 .streamed(
2286 40.0,
2287 vec![50.0, 110.0, 210.0, 310.0, 360.0, 410.0, 460.0, 520.0],
2288 )
2289 .server_prefill(300, 100.0);
2290 let c = RequestOutcome::completed(20.0, 530.0, 8)
2292 .streamed(
2293 40.0,
2294 vec![60.0, 120.0, 220.0, 320.0, 370.0, 420.0, 470.0, 530.0],
2295 )
2296 .with_prompt_tokens(9_999);
2297 let zero = RequestOutcome::completed(30.0, 540.0, 8)
2301 .streamed(
2302 40.0,
2303 vec![70.0, 130.0, 230.0, 330.0, 380.0, 430.0, 480.0, 540.0],
2304 )
2305 .server_prefill(7_777, 0.0);
2306 let d = BandInput::new(1, 1000.0, vec![a, b, c, zero], unmeasured())
2307 .stream_mode(StreamMode::Live)
2308 .n_predict(8)
2309 .derive()
2310 .expect("renders");
2311 assert!(
2313 (d.prefill_tok_per_sec.expect("prefill") - 4_000.0).abs() < 1e-9,
2314 "{:?}",
2315 d.prefill_tok_per_sec
2316 );
2317 }
2318
2319 #[test]
2322 fn fewer_than_five_replicates_makes_the_band_nonconformant() {
2323 let b = conformant_band(1);
2324 let five = BandContext {
2325 replicates: 5,
2326 ..BandContext::default()
2327 };
2328 let three = BandContext {
2329 replicates: 3,
2330 ..BandContext::default()
2331 };
2332 assert_eq!(
2333 b.derive_in(&five).expect("renders").status,
2334 BandStatus::Unmeasured
2335 );
2336 assert_eq!(
2337 b.derive_in(&three).expect("renders").status,
2338 BandStatus::NonconformantValid
2339 );
2340 }
2341
2342 #[test]
2344 fn a_non_interleaved_receipt_makes_the_band_nonconformant() {
2345 let ctx = BandContext {
2346 interleaved: false,
2347 ..BandContext::default()
2348 };
2349 assert_eq!(
2350 conformant_band(1).derive_in(&ctx).expect("renders").status,
2351 BandStatus::NonconformantValid
2352 );
2353 }
2354
2355 #[test]
2357 fn a_stale_pin_renders_comparator_stale() {
2358 let ctx = BandContext {
2359 comparator_stale: true,
2360 ..BandContext::default()
2361 };
2362 let d = conformant_band(1).derive_in(&ctx).expect("renders");
2363 assert_eq!(d.status, BandStatus::ComparatorStale);
2364 assert!(!d.baseline_eligible());
2365 }
2366
2367 fn jkey(c: u32) -> JoinKey {
2370 JoinKey {
2371 host: "lambda".to_string(),
2372 workload: Workload::W1,
2373 band: c,
2374 model: "qwen2.5-coder-7b-apache-q4k-v1".to_string(),
2375 quant: "Q4_K_M".to_string(),
2376 tokenization: TokenCountingMethod::ClientTokenizer,
2377 window_ms: 1_000,
2378 replicates: 5,
2379 interleaved: true,
2380 n_ctx_slot: Some(1024),
2381 kv_type: Some("f16".to_string()),
2382 fa: Some(true),
2383 n_batch: Some(2048),
2384 n_predict: 128,
2385 }
2386 }
2387
2388 fn same_run() -> RunId {
2389 RunId::derive("2026-09-02T10:11:12.345Z", "lambda", &"a".repeat(64), 4242)
2390 }
2391
2392 fn another_run() -> RunId {
2393 RunId::derive("2026-09-02T11:00:00.000Z", "lambda", &"a".repeat(64), 4243)
2394 }
2395
2396 #[test]
2399 fn ratio_paired__a_same_run_baseline_joins() {
2400 let subject = conformant_band(1);
2401 let comparator = conformant_band(1);
2402 let id = same_run();
2403 let status = BandInput::join_status(&subject, &comparator, &jkey(1), &jkey(1), (&id, &id))
2404 .expect("a same-run, same-key, timeout-free join");
2405
2406 let ComparatorStatus::Measured(join) = &status else {
2407 panic!("expected Measured, got {status:?}");
2408 };
2409 let (baseline, ratios) = (join.baseline(), join.ratios());
2410 assert_eq!(
2411 baseline.run_id.as_ref(),
2412 Some(&id),
2413 "PP-3: the baseline says which run it came from"
2414 );
2415 assert_eq!(baseline.join_key.as_ref(), Some(&jkey(1)));
2416 assert_eq!(status.wire_token(), "MEASURED");
2417
2418 assert!((ratios.agg.point - 1.0).abs() < 1e-9, "{:?}", ratios.agg);
2420 assert_eq!(ratios.agg.method, RatioMethod::ReplicateTLower);
2421 assert!(
2422 ratios.agg.lcb95.is_none(),
2423 "one replicate bounds no variance (§4.3)"
2424 );
2425 let dec = ratios.dec.as_ref().expect("a live stream has a dec ratio");
2426 assert_eq!(dec.method, RatioMethod::PairedPercentileBootstrap);
2427 assert!((dec.point - 1.0).abs() < 1e-9, "{dec:?}");
2428 assert!(dec.lcb95.is_some(), "the request unit does bound");
2429 assert!(ratios.prefill.is_some(), "both lanes reported prefill");
2430
2431 let joined =
2433 BandInput::join(&subject, &comparator, &jkey(1), &jkey(1), (&id, &id)).expect("joins");
2434 assert_eq!(joined.status, BandStatus::Measured);
2435 assert!(joined.baseline_eligible());
2436 }
2437
2438 #[test]
2441 fn a_baseline_from_another_run_is_refused() {
2442 let subject = conformant_band(1);
2443 let comparator = conformant_band(1);
2444 let (mine, theirs) = (same_run(), another_run());
2445 assert_ne!(mine, theirs);
2446 let err =
2447 BandInput::join_status(&subject, &comparator, &jkey(1), &jkey(1), (&mine, &theirs))
2448 .expect_err("cross-run baseline");
2449 assert!(err.contains("PP-3"), "{err}");
2450 assert!(err.contains("SAME run"), "{err}");
2451 }
2452
2453 #[test]
2456 fn a_key_mismatch_stops_the_join_before_any_ratio_is_computed() {
2457 let id = same_run();
2458 let err = BandInput::join_status(
2459 &conformant_band(4),
2460 &conformant_band(16),
2461 &jkey(4),
2462 &jkey(16),
2463 (&id, &id),
2464 )
2465 .expect_err("c=4 against c=16");
2466 assert!(err.contains("band: 4 != 16"), "{err}");
2467 }
2468
2469 #[test]
2472 fn a_timed_out_band_cannot_carry_a_ratio() {
2473 let id = same_run();
2474 let mut timed_out = conformant_band(1);
2475 timed_out.requests.push(RequestOutcome::new(
2476 10.0,
2477 10.0 + REQUEST_TIMEOUT_MS,
2478 Outcome::Timeout,
2479 0,
2480 ));
2481 assert_eq!(
2482 timed_out.derive().expect("renders").timeouts,
2483 1,
2484 "control: the band itself still renders its evidence"
2485 );
2486
2487 let subject_side = BandInput::join_status(
2488 &timed_out,
2489 &conformant_band(1),
2490 &jkey(1),
2491 &jkey(1),
2492 (&id, &id),
2493 )
2494 .expect_err("the subject timed out");
2495 assert!(subject_side.contains("PP-5"), "{subject_side}");
2496 assert!(subject_side.contains("subject"), "{subject_side}");
2497
2498 let comparator_side = BandInput::join_status(
2499 &conformant_band(1),
2500 &timed_out,
2501 &jkey(1),
2502 &jkey(1),
2503 (&id, &id),
2504 )
2505 .expect_err("the comparator timed out");
2506 assert!(comparator_side.contains("comparator"), "{comparator_side}");
2507
2508 BandInput::join_status(
2510 &conformant_band(1),
2511 &conformant_band(1),
2512 &jkey(1),
2513 &jkey(1),
2514 (&id, &id),
2515 )
2516 .expect("a clean pair joins");
2517 }
2518
2519 #[test]
2522 fn the_joined_ratio_is_subject_over_comparator() {
2523 let id = same_run();
2524 let subject = conformant_band(1);
2525 let mut fast_comparator = conformant_band(1);
2527 for r in &mut fast_comparator.requests {
2528 let dur = r.settled_ms - r.issued_ms;
2529 r.settled_ms = r.issued_ms + dur / 2.0;
2530 let first = r.token_times_ms[0];
2531 for t in &mut r.token_times_ms {
2532 *t = first + (*t - first) / 2.0;
2533 }
2534 }
2535 let status =
2536 BandInput::join_status(&subject, &fast_comparator, &jkey(1), &jkey(1), (&id, &id))
2537 .expect("joins");
2538 let ComparatorStatus::Measured(join) = &status else {
2539 panic!("expected Measured");
2540 };
2541 let ratios = join.ratios();
2542 assert!(
2543 ratios.agg.point < 1.0,
2544 "a slower subject is below parity: {:?}",
2545 ratios.agg
2546 );
2547 let dec = ratios.dec.as_ref().expect("dec ratio");
2548 assert!((dec.point - 0.5).abs() < 0.02, "{dec:?}");
2549 }
2550
2551 #[test]
2557 fn the_status_precedence_is_a_total_order_correctness_first() {
2558 use BandStatus::{
2559 ComparatorStale, InvalidCorrectness, Measured, Na, NonconformantValid, Unmeasured,
2560 };
2561 let strongest_first = [
2562 InvalidCorrectness,
2563 ComparatorStale,
2564 Na,
2565 NonconformantValid,
2566 Unmeasured,
2567 Measured,
2568 ];
2569 for (i, strong) in strongest_first.iter().enumerate() {
2570 for weak in &strongest_first[i + 1..] {
2571 assert_eq!(
2572 strong.stronger_of(*weak),
2573 *strong,
2574 "{strong:?} must win over {weak:?}"
2575 );
2576 assert_eq!(
2577 weak.stronger_of(*strong),
2578 *strong,
2579 "…in either argument order"
2580 );
2581 }
2582 assert_eq!(strong.stronger_of(*strong), *strong, "idempotent");
2583 }
2584 assert_eq!(strongest_first.len(), BandStatus::vocabulary().len());
2587 }
2588
2589 #[test]
2597 fn an_unwitnessed_batch_under_a_stale_pin_stays_invalid_correctness() {
2598 let ctx = BandContext {
2599 comparator_stale: true,
2600 ..BandContext::default()
2601 };
2602 let unwitnessed = BandInput::new(4, 1000.0, conformant_band(4).requests, unmeasured())
2603 .n_predict(128)
2604 .stream_mode(StreamMode::Live);
2605 let d = unwitnessed
2606 .derive_in(&ctx)
2607 .expect("renders")
2608 .marked_comparator_stale("2026-01-01T00:00:00.000Z", "2026-09-02T10:11:12.345Z");
2609 assert_eq!(d.status, BandStatus::InvalidCorrectness);
2610 assert_eq!(
2611 d.aggregate_tok_per_sec, None,
2612 "and it reports no throughput"
2613 );
2614 assert!(!d.baseline_eligible());
2615 let witnessed = conformant_band(4)
2618 .derive_in(&ctx)
2619 .expect("renders")
2620 .marked_comparator_stale("2026-01-01T00:00:00.000Z", "2026-09-02T10:11:12.345Z");
2621 assert_eq!(witnessed.status, BandStatus::ComparatorStale);
2622 }
2623
2624 #[test]
2627 fn a_not_applicable_band_is_na_even_when_it_is_also_nonconformant() {
2628 let ctx = BandContext {
2629 interleaved: false,
2630 ..BandContext::default()
2631 };
2632 let na = ComparatorStatus::not_applicable("perf-matrix.yaml", "no Metal path (#2841)");
2633 let d = BandInput::new(1, 1000.0, conformant_band(1).requests, na)
2634 .n_predict(128)
2635 .stream_mode(StreamMode::Live)
2636 .derive_in(&ctx)
2637 .expect("renders");
2638 assert_eq!(d.status, BandStatus::Na);
2639 let d2 = conformant_band(1).derive_in(&ctx).expect("renders");
2642 assert_eq!(d2.status, BandStatus::NonconformantValid);
2643 }
2644
2645 #[test]
2663 fn ratio_paired__the_measured_payload_is_read_only_outside_the_join() {
2664 let id = same_run();
2665 let status = BandInput::join_status(
2666 &conformant_band(1),
2667 &conformant_band(1),
2668 &jkey(1),
2669 &jkey(1),
2670 (&id, &id),
2671 )
2672 .expect("joins");
2673 let ComparatorStatus::Measured(join) = &status else {
2674 panic!("expected Measured");
2675 };
2676 assert_eq!(join.baseline().concurrency, 1);
2677 assert_eq!(join.baseline().run_id.as_ref(), Some(&id));
2678 assert!((join.ratios().agg.point - 1.0).abs() < 1e-9);
2679 }
2680
2681 #[test]
2692 fn a_comparator_lane_band_needs_no_batch_invariance_witness() {
2693 let subject = BandInput::new(4, 1000.0, conformant_band(4).requests, unmeasured())
2694 .n_predict(128)
2695 .stream_mode(StreamMode::Live);
2696 let subject_band = subject.clone().derive().expect("renders");
2697 assert_eq!(
2698 subject_band.status,
2699 BandStatus::InvalidCorrectness,
2700 "the SUBJECT still needs one"
2701 );
2702
2703 let comparator_band = subject.role(Lane::Llama).derive().expect("renders");
2704 assert_ne!(comparator_band.status, BandStatus::InvalidCorrectness);
2705 assert!(
2706 comparator_band.aggregate_tok_per_sec.is_some(),
2707 "the oracle's throughput is not withheld for a witness it is not the subject of"
2708 );
2709 assert!(
2710 comparator_band.witness.is_none(),
2711 "and it carries no witness of its own"
2712 );
2713 }
2714
2715 #[test]
2718 fn the_comparator_exemption_is_about_the_lane_not_the_band_width() {
2719 let one = BandInput::new(1, 1000.0, conformant_band(1).requests, unmeasured())
2720 .n_predict(128)
2721 .stream_mode(StreamMode::Live);
2722 assert_ne!(
2723 one.clone().derive().expect("renders").status,
2724 BandStatus::InvalidCorrectness
2725 );
2726 assert_ne!(
2727 one.role(Lane::Llama).derive().expect("renders").status,
2728 BandStatus::InvalidCorrectness
2729 );
2730 }
2731
2732 #[test]
2742 fn a_lane_with_suppressed_decode_forms_no_dec_ratio() {
2743 let id = same_run();
2744 let replayed = BandInput::new(1, 1000.0, conformant_band(1).requests, unmeasured())
2745 .n_predict(128)
2746 .stream_mode(StreamMode::Replayed)
2747 .witness(passing_witness());
2748 assert_eq!(
2749 replayed.derive().expect("renders").decode_tok_per_sec,
2750 None,
2751 "the fixture's decode must actually be withheld"
2752 );
2753
2754 let status = BandInput::join_status(
2755 &conformant_band(1),
2756 &replayed,
2757 &jkey(1),
2758 &jkey(1),
2759 (&id, &id),
2760 )
2761 .expect("joins");
2762 let ComparatorStatus::Measured(join) = &status else {
2763 panic!("expected Measured");
2764 };
2765 assert!(
2766 join.ratios().dec.is_none(),
2767 "a ratio whose denominator the band refused to report is not a ratio: {:?}",
2768 join.ratios().dec
2769 );
2770 let live = BandInput::join_status(
2772 &conformant_band(1),
2773 &conformant_band(1),
2774 &jkey(1),
2775 &jkey(1),
2776 (&id, &id),
2777 )
2778 .expect("joins");
2779 let ComparatorStatus::Measured(join) = &live else {
2780 panic!("expected Measured");
2781 };
2782 assert!(join.ratios().dec.is_some());
2783 }
2784
2785 #[test]
2788 fn a_lane_without_server_prefill_forms_no_prefill_ratio() {
2789 let id = same_run();
2790 let no_timings: Vec<RequestOutcome> = (0..8)
2791 .map(|i| {
2792 let (issued, dur) = (f64::from(i) * 100.0, 90.0 + f64::from(i));
2793 let ttft = dur * 0.08;
2794 let times: Vec<f64> = (0..128)
2795 .map(|k| issued + ttft + f64::from(k) * (dur - ttft) / 128.0)
2796 .collect();
2797 RequestOutcome::completed(issued, issued + dur, 128)
2798 .with_prompt_tokens(512)
2799 .streamed(ttft, times)
2800 })
2801 .collect();
2802 let bare = BandInput::new(1, 1000.0, no_timings, unmeasured())
2803 .n_predict(128)
2804 .stream_mode(StreamMode::Live)
2805 .witness(passing_witness());
2806 assert_eq!(bare.derive().expect("renders").prefill_tok_per_sec, None);
2807
2808 let status =
2809 BandInput::join_status(&conformant_band(1), &bare, &jkey(1), &jkey(1), (&id, &id))
2810 .expect("joins");
2811 let ComparatorStatus::Measured(join) = &status else {
2812 panic!("expected Measured");
2813 };
2814 assert!(join.ratios().prefill.is_none());
2815 }
2816
2817 #[test]
2826 fn a_driver_protocol_violation_reaches_the_band_and_its_status() {
2827 let clean = conformant_band(1).derive().expect("renders");
2828 assert_eq!(clean.status, BandStatus::Unmeasured);
2829
2830 let violated = conformant_band(1)
2831 .conformance_violations(vec![
2832 "window closed after 30 samples, below the max(30, 8c) floor".to_string(),
2833 ])
2834 .derive()
2835 .expect("renders");
2836 assert_eq!(violated.status, BandStatus::NonconformantValid);
2837 assert!(
2838 violated
2839 .unproduced
2840 .iter()
2841 .any(|u| u.contains("below the max(30, 8c) floor") && u.contains("§4.4.2")),
2842 "the violation text itself must be on the receipt: {:?}",
2843 violated.unproduced
2844 );
2845 }
2846
2847 #[test]
2850 fn a_band_carries_one_sample_row_per_request() {
2851 let d = conformant_band(1).derive().expect("renders");
2852 assert_eq!(d.samples.len(), d.requested);
2853 assert_eq!(d.samples[0].index, 0);
2854 assert_eq!(d.samples[0].generated_tokens, 128);
2855 assert_eq!(d.samples[0].prompt_tokens, 512);
2856 assert!(d.samples[0].ttft_ms.is_some());
2857 let json = serde_json::to_string(&d.samples[0]).expect("serialises");
2858 assert!(
2859 !json.contains("token_times"),
2860 "token times stay in the side file: {json}"
2861 );
2862 }
2863}