1use std::sync::Arc;
18
19pub const BASIS_POINTS: u64 = 10_000;
21const SCALED_BASIS_POINTS: u64 = BASIS_POINTS * BASIS_POINTS;
22const COST_SCALE: u64 = 1_000_000;
23const COST_ROUNDING: u64 = COST_SCALE - 1;
24pub const ALL_PROVIDERS: u64 = u64::MAX;
26pub const ALL_REGIONS: u64 = u64::MAX;
28pub const MAX_PROVIDER_ID: u16 = 63;
30
31#[repr(C)]
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub struct KernelModel {
36 pub model_id: u32,
38 pub provider_id: u16,
40 pub quality_bps: u16,
42 pub risk_ceiling_bps: u16,
44 pub enabled: u8,
46 pub p95_latency_ms: u32,
48 pub capabilities: u64,
50 pub region_mask: u64,
52 pub input_cost_microunits_per_million_tokens: u64,
54 pub output_cost_microunits_per_million_tokens: u64,
56}
57
58#[repr(C)]
60#[derive(Clone, Copy, Debug, Eq, PartialEq)]
61#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
62#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
63pub struct KernelInput {
64 pub request_sequence: u64,
66 pub requested_model_id: u32,
68 pub input_tokens: u32,
70 pub output_tokens: u32,
72 pub business_value_microunits: i64,
74 pub budget_limit_microunits: u64,
76 pub risk_bps: u16,
78 pub confidence_bps: u16,
80 pub minimum_quality_bps: u16,
82 pub max_p95_latency_ms: u32,
84 pub required_capabilities: u64,
86 pub allowed_provider_mask: u64,
88 pub required_region_mask: u64,
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
94pub enum InputError {
95 #[error("{field} must be <= {max}, got {value}")]
96 OutOfRangeBps {
97 field: &'static str,
98 value: u16,
99 max: u16,
100 },
101}
102
103impl KernelInput {
104 pub fn validate(&self) -> Result<(), InputError> {
109 if self.risk_bps > MAX_BPS {
110 return Err(InputError::OutOfRangeBps {
111 field: "risk_bps",
112 value: self.risk_bps,
113 max: MAX_BPS,
114 });
115 }
116 if self.confidence_bps > MAX_BPS {
117 return Err(InputError::OutOfRangeBps {
118 field: "confidence_bps",
119 value: self.confidence_bps,
120 max: MAX_BPS,
121 });
122 }
123 if self.minimum_quality_bps > MAX_BPS {
124 return Err(InputError::OutOfRangeBps {
125 field: "minimum_quality_bps",
126 value: self.minimum_quality_bps,
127 max: MAX_BPS,
128 });
129 }
130 Ok(())
131 }
132}
133
134#[repr(u8)]
136#[derive(Clone, Copy, Debug, Eq, PartialEq)]
137#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
138pub enum KernelAction {
139 ExecuteRequested = 1,
141 Substitute = 2,
143 Reject = 3,
145}
146
147impl std::fmt::Display for KernelAction {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 match self {
150 Self::ExecuteRequested => write!(f, "execute_requested"),
151 Self::Substitute => write!(f, "substitute"),
152 Self::Reject => write!(f, "reject"),
153 }
154 }
155}
156
157#[repr(u16)]
159#[derive(Clone, Copy, Debug, Eq, PartialEq)]
160#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
161pub enum KernelReason {
162 RequestedModelMaximizesUtility = 1,
164 AlternativeMaximizesUtility = 2,
166 RiskHardLimit = 100,
168 ConfidenceHardLimit = 101,
170 NoEnabledModel = 102,
172 QualityConstraint = 103,
174 LatencyConstraint = 104,
176 CapabilityConstraint = 105,
178 ProviderConstraint = 106,
180 RegionConstraint = 107,
182 BudgetConstraint = 108,
184 NonPositiveUtility = 109,
186 RiskCeilingConstraint = 110,
188}
189
190impl std::fmt::Display for KernelReason {
191 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192 match self {
193 Self::RequestedModelMaximizesUtility => write!(f, "requested_model_maximizes_utility"),
194 Self::AlternativeMaximizesUtility => write!(f, "alternative_maximizes_utility"),
195 Self::RiskHardLimit => write!(f, "risk_hard_limit"),
196 Self::ConfidenceHardLimit => write!(f, "confidence_hard_limit"),
197 Self::NoEnabledModel => write!(f, "no_enabled_model"),
198 Self::QualityConstraint => write!(f, "quality_constraint"),
199 Self::LatencyConstraint => write!(f, "latency_constraint"),
200 Self::CapabilityConstraint => write!(f, "capability_constraint"),
201 Self::ProviderConstraint => write!(f, "provider_constraint"),
202 Self::RegionConstraint => write!(f, "region_constraint"),
203 Self::BudgetConstraint => write!(f, "budget_constraint"),
204 Self::NonPositiveUtility => write!(f, "non_positive_utility"),
205 Self::RiskCeilingConstraint => write!(f, "risk_ceiling_constraint"),
206 }
207 }
208}
209
210#[repr(C)]
212#[derive(Clone, Copy, Debug, Eq, PartialEq)]
213#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
214#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
215pub struct KernelDecision {
216 pub request_sequence: u64,
218 pub action: KernelAction,
220 pub reason: KernelReason,
222 pub selected_model_id: u32,
224 pub selected_model_index: u16,
226 pub estimated_cost_microunits: u64,
228 pub expected_utility_microunits: i64,
230 pub counterfactual_model_id: u32,
232 pub counterfactual_utility_microunits: i64,
234 pub evaluated_models: u16,
236 pub eligible_models: u16,
238 pub policy_epoch: u64,
240 pub catalog_epoch: u64,
242}
243
244impl KernelDecision {
245 #[must_use]
247 pub const fn is_executable(&self) -> bool {
248 matches!(
249 self.action,
250 KernelAction::ExecuteRequested | KernelAction::Substitute
251 )
252 }
253
254 #[must_use]
256 pub const fn is_requested_execution(&self) -> bool {
257 matches!(self.action, KernelAction::ExecuteRequested)
258 }
259
260 #[must_use]
262 pub const fn is_substitution(&self) -> bool {
263 matches!(self.action, KernelAction::Substitute)
264 }
265
266 #[must_use]
268 pub const fn is_rejected(&self) -> bool {
269 matches!(self.action, KernelAction::Reject)
270 }
271}
272
273#[derive(Clone, Debug)]
279pub struct PolicySnapshot {
280 pub policy_epoch: u64,
281 pub catalog_epoch: u64,
282 pub hard_risk_limit_bps: u16,
283 pub minimum_confidence_bps: u16,
284 pub risk_penalty_multiplier_bps: u16,
285 pub latency_penalty_microunits_per_ms: u64,
292 max_quality_bps: u16,
293 max_p95_latency_ms: u32,
294 max_input_cost: u64,
295 max_output_cost: u64,
296 models: Arc<[KernelModel]>,
297}
298
299#[derive(Clone, Copy)]
300struct Candidate {
301 model_id: u32,
302 model_index: u16,
303 quality_bps: u16,
304 cost: u64,
305 utility: i64,
306}
307
308#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
310#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
311pub struct RejectionHistogram {
312 pub disabled: u16,
314 pub quality: u16,
316 pub risk_ceiling: u16,
318 pub latency: u16,
320 pub capability: u16,
322 pub provider: u16,
324 pub region: u16,
326 pub budget: u16,
328 pub utility: u16,
330}
331
332#[derive(Clone, Copy, Debug, PartialEq, Eq)]
334#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
335pub struct DecisionTrace {
336 pub rejections: RejectionHistogram,
337 pub evaluated_models: u16,
338 pub eligible_models: u16,
339}
340
341pub const MAX_BPS: u16 = 10_000;
343
344pub const MAX_RISK_PENALTY_MULTIPLIER_BPS: u16 = 50_000;
346
347#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
349pub enum PolicyError {
350 #[error("model catalog is empty")]
351 EmptyCatalog,
352 #[error("duplicate model_id {model_id}")]
353 DuplicateModelId { model_id: u32 },
354 #[error("model_id {model_id} has provider_id {provider_id} > MAX_PROVIDER_ID")]
355 InvalidProviderId { model_id: u32, provider_id: u16 },
356 #[error("no enabled models in catalog")]
357 NoEnabledModels,
358 #[error("{field} must be <= {max}, got {value}")]
359 OutOfRangeBps {
360 field: &'static str,
361 value: u16,
362 max: u16,
363 },
364}
365
366type RejectionCounts = RejectionHistogram;
367
368impl PolicySnapshot {
369 pub fn new_unchecked(
379 policy_epoch: u64,
380 catalog_epoch: u64,
381 hard_risk_limit_bps: u16,
382 minimum_confidence_bps: u16,
383 risk_penalty_multiplier_bps: u16,
384 latency_penalty_microunits_per_ms: u64,
385 models: Vec<KernelModel>,
386 ) -> Self {
387 let max_quality_bps = models
388 .iter()
389 .map(|model| model.quality_bps)
390 .max()
391 .unwrap_or_default();
392 let max_p95_latency_ms = models
393 .iter()
394 .map(|model| model.p95_latency_ms)
395 .max()
396 .unwrap_or_default();
397 let max_input_cost = models
398 .iter()
399 .map(|model| model.input_cost_microunits_per_million_tokens)
400 .max()
401 .unwrap_or_default();
402 let max_output_cost = models
403 .iter()
404 .map(|model| model.output_cost_microunits_per_million_tokens)
405 .max()
406 .unwrap_or_default();
407 Self {
408 policy_epoch,
409 catalog_epoch,
410 hard_risk_limit_bps,
411 minimum_confidence_bps,
412 risk_penalty_multiplier_bps,
413 latency_penalty_microunits_per_ms,
414 max_quality_bps,
415 max_p95_latency_ms,
416 max_input_cost,
417 max_output_cost,
418 models: Arc::from(models),
419 }
420 }
421
422 #[deprecated(
424 since = "0.3.9",
425 note = "use PolicySnapshot::try_new for validated snapshots or new_unchecked for tests"
426 )]
427 pub fn new(
428 policy_epoch: u64,
429 catalog_epoch: u64,
430 hard_risk_limit_bps: u16,
431 minimum_confidence_bps: u16,
432 risk_penalty_multiplier_bps: u16,
433 latency_penalty_microunits_per_ms: u64,
434 models: Vec<KernelModel>,
435 ) -> Self {
436 Self::new_unchecked(
437 policy_epoch,
438 catalog_epoch,
439 hard_risk_limit_bps,
440 minimum_confidence_bps,
441 risk_penalty_multiplier_bps,
442 latency_penalty_microunits_per_ms,
443 models,
444 )
445 }
446
447 pub fn models(&self) -> &[KernelModel] {
449 &self.models
450 }
451
452 pub fn validate(&self) -> Result<(), PolicyError> {
454 if self.hard_risk_limit_bps > MAX_BPS {
455 return Err(PolicyError::OutOfRangeBps {
456 field: "hard_risk_limit_bps",
457 value: self.hard_risk_limit_bps,
458 max: MAX_BPS,
459 });
460 }
461 if self.minimum_confidence_bps > MAX_BPS {
462 return Err(PolicyError::OutOfRangeBps {
463 field: "minimum_confidence_bps",
464 value: self.minimum_confidence_bps,
465 max: MAX_BPS,
466 });
467 }
468 if self.risk_penalty_multiplier_bps > MAX_RISK_PENALTY_MULTIPLIER_BPS {
469 return Err(PolicyError::OutOfRangeBps {
470 field: "risk_penalty_multiplier_bps",
471 value: self.risk_penalty_multiplier_bps,
472 max: MAX_RISK_PENALTY_MULTIPLIER_BPS,
473 });
474 }
475 if self.models.is_empty() {
476 return Err(PolicyError::EmptyCatalog);
477 }
478 let mut seen = std::collections::HashSet::new();
479 let mut any_enabled = false;
480 for model in self.models.iter() {
481 if !seen.insert(model.model_id) {
482 return Err(PolicyError::DuplicateModelId {
483 model_id: model.model_id,
484 });
485 }
486 if model.provider_id > MAX_PROVIDER_ID {
487 return Err(PolicyError::InvalidProviderId {
488 model_id: model.model_id,
489 provider_id: model.provider_id,
490 });
491 }
492 if model.quality_bps > MAX_BPS {
493 return Err(PolicyError::OutOfRangeBps {
494 field: "model.quality_bps",
495 value: model.quality_bps,
496 max: MAX_BPS,
497 });
498 }
499 if model.risk_ceiling_bps > MAX_BPS {
500 return Err(PolicyError::OutOfRangeBps {
501 field: "model.risk_ceiling_bps",
502 value: model.risk_ceiling_bps,
503 max: MAX_BPS,
504 });
505 }
506 if model.enabled != 0 {
507 any_enabled = true;
508 }
509 }
510 if !any_enabled {
511 return Err(PolicyError::NoEnabledModels);
512 }
513 Ok(())
514 }
515
516 pub fn try_new(
518 policy_epoch: u64,
519 catalog_epoch: u64,
520 hard_risk_limit_bps: u16,
521 minimum_confidence_bps: u16,
522 risk_penalty_multiplier_bps: u16,
523 latency_penalty_microunits_per_ms: u64,
524 models: Vec<KernelModel>,
525 ) -> Result<Self, PolicyError> {
526 let snapshot = Self::new_unchecked(
527 policy_epoch,
528 catalog_epoch,
529 hard_risk_limit_bps,
530 minimum_confidence_bps,
531 risk_penalty_multiplier_bps,
532 latency_penalty_microunits_per_ms,
533 models,
534 );
535 snapshot.validate()?;
536 Ok(snapshot)
537 }
538
539 pub fn prescribe_batch(&self, inputs: &[KernelInput]) -> Vec<KernelDecision> {
541 inputs.iter().map(|&input| self.prescribe(input)).collect()
542 }
543
544 pub fn prescribe_batch_checked(
547 &self,
548 inputs: &[KernelInput],
549 ) -> Result<Vec<KernelDecision>, InputError> {
550 for input in inputs {
551 input.validate()?;
552 }
553 Ok(self.prescribe_batch(inputs))
554 }
555
556 pub fn prescribe_with_trace(&self, input: KernelInput) -> (KernelDecision, DecisionTrace) {
558 let (decision, rejections) = self.prescribe_inner(input);
559 let trace = DecisionTrace {
560 rejections,
561 evaluated_models: decision.evaluated_models,
562 eligible_models: decision.eligible_models,
563 };
564 (decision, trace)
565 }
566
567 pub fn prescribe_with_trace_checked(
569 &self,
570 input: KernelInput,
571 ) -> Result<(KernelDecision, DecisionTrace), InputError> {
572 input.validate()?;
573 Ok(self.prescribe_with_trace(input))
574 }
575
576 #[must_use]
587 pub fn prescribe(&self, input: KernelInput) -> KernelDecision {
588 self.prescribe_inner(input).0
589 }
590
591 pub fn prescribe_checked(&self, input: KernelInput) -> Result<KernelDecision, InputError> {
597 input.validate()?;
598 Ok(self.prescribe(input))
599 }
600
601 #[must_use]
606 pub fn utility_for_model(&self, input: KernelInput, model_id: u32) -> Option<i64> {
607 if input.risk_bps >= self.hard_risk_limit_bps {
608 return None;
609 }
610 if input.confidence_bps < self.minimum_confidence_bps {
611 return None;
612 }
613 let model = self.models.iter().find(|m| m.model_id == model_id)?;
614
615 if model.enabled == 0 {
616 return None;
617 }
618 if model.quality_bps < input.minimum_quality_bps {
619 return None;
620 }
621 if input.max_p95_latency_ms > 0 && model.p95_latency_ms > input.max_p95_latency_ms {
622 return None;
623 }
624 if model.capabilities & input.required_capabilities != input.required_capabilities {
625 return None;
626 }
627 if model.provider_id > MAX_PROVIDER_ID {
628 return None;
629 }
630 if input.allowed_provider_mask != ALL_PROVIDERS
631 && input.allowed_provider_mask & (1_u64 << model.provider_id) == 0
632 {
633 return None;
634 }
635 if input.required_region_mask != 0 && model.region_mask & input.required_region_mask == 0 {
636 return None;
637 }
638 if input.risk_bps > model.risk_ceiling_bps {
639 return None;
640 }
641
642 let all_costs_fit = self.all_costs_fit_u64(input.input_tokens, input.output_tokens);
643 let cost = if all_costs_fit {
644 model_cost_fast(model, input.input_tokens, input.output_tokens)
645 } else {
646 model_cost_reference(model, input.input_tokens, input.output_tokens)
647 };
648 if cost > input.budget_limit_microunits {
649 return None;
650 }
651
652 let value = input.business_value_microunits.max(0) as u64;
653 let confidence_bps = u64::from(input.confidence_bps);
654 let quality_prefix = value.checked_mul(confidence_bps).filter(|prefix| {
655 prefix
656 .checked_mul(u64::from(self.max_quality_bps))
657 .is_some()
658 });
659 let risk_penalty = scaled_term_exact(
660 value,
661 u64::from(input.risk_bps),
662 u64::from(self.risk_penalty_multiplier_bps),
663 );
664 let all_latencies_fit = u64::from(self.max_p95_latency_ms)
665 .checked_mul(self.latency_penalty_microunits_per_ms)
666 .is_some();
667 let quality_adjusted = quality_prefix.map_or_else(
668 || scaled_term_reference(value, confidence_bps, u64::from(model.quality_bps)),
669 |prefix| {
670 i128::from(prefix.wrapping_mul(u64::from(model.quality_bps)) / SCALED_BASIS_POINTS)
671 },
672 );
673 let latency_penalty = if all_latencies_fit {
674 i128::from(
675 u64::from(model.p95_latency_ms)
676 .wrapping_mul(self.latency_penalty_microunits_per_ms),
677 )
678 } else {
679 i128::from(model.p95_latency_ms) * i128::from(self.latency_penalty_microunits_per_ms)
680 };
681 let utility =
682 clamp_i128_to_i64(quality_adjusted - risk_penalty - i128::from(cost) - latency_penalty);
683 if utility <= 0 {
684 return None;
685 }
686 Some(utility)
687 }
688
689 fn prescribe_inner(&self, input: KernelInput) -> (KernelDecision, RejectionHistogram) {
690 if input.risk_bps >= self.hard_risk_limit_bps {
691 return self.reject(input, KernelReason::RiskHardLimit, 0, 0);
692 }
693 if input.confidence_bps < self.minimum_confidence_bps {
694 return self.reject(input, KernelReason::ConfidenceHardLimit, 0, 0);
695 }
696
697 let mut best: Option<Candidate> = None;
698 let mut second: Option<Candidate> = None;
699 let mut eligible_models = 0_u16;
700 let mut rejected = RejectionCounts::default();
701
702 let value = input.business_value_microunits.max(0) as u64;
703 let confidence_bps = u64::from(input.confidence_bps);
704 let quality_prefix = value.checked_mul(confidence_bps).filter(|prefix| {
705 prefix
706 .checked_mul(u64::from(self.max_quality_bps))
707 .is_some()
708 });
709 let risk_penalty = scaled_term_exact(
710 value,
711 u64::from(input.risk_bps),
712 u64::from(self.risk_penalty_multiplier_bps),
713 );
714 let all_costs_fit = self.all_costs_fit_u64(input.input_tokens, input.output_tokens);
715 let all_latencies_fit = u64::from(self.max_p95_latency_ms)
716 .checked_mul(self.latency_penalty_microunits_per_ms)
717 .is_some();
718
719 let check_provider = input.allowed_provider_mask != ALL_PROVIDERS;
720 let check_region = input.required_region_mask != 0;
721 let check_latency = input.max_p95_latency_ms > 0;
722 let latency_pen_per_ms = self.latency_penalty_microunits_per_ms;
723
724 for (index, model) in self.models.iter().enumerate() {
725 if model.enabled == 0 {
727 rejected.disabled += 1;
728 continue;
729 }
730 if model.quality_bps < input.minimum_quality_bps {
731 rejected.quality += 1;
732 continue;
733 }
734 if check_latency && model.p95_latency_ms > input.max_p95_latency_ms {
735 rejected.latency += 1;
736 continue;
737 }
738 if model.capabilities & input.required_capabilities != input.required_capabilities {
739 rejected.capability += 1;
740 continue;
741 }
742 if model.provider_id > MAX_PROVIDER_ID {
745 rejected.provider += 1;
746 continue;
747 }
748 if check_provider && input.allowed_provider_mask & (1_u64 << model.provider_id) == 0 {
749 rejected.provider += 1;
750 continue;
751 }
752 if check_region && model.region_mask & input.required_region_mask == 0 {
753 rejected.region += 1;
754 continue;
755 }
756 if input.risk_bps > model.risk_ceiling_bps {
757 rejected.risk_ceiling += 1;
758 continue;
759 }
760
761 let cost = if all_costs_fit {
762 model_cost_fast(model, input.input_tokens, input.output_tokens)
763 } else {
764 model_cost_reference(model, input.input_tokens, input.output_tokens)
765 };
766 if cost > input.budget_limit_microunits {
767 rejected.budget += 1;
768 continue;
769 }
770
771 let quality_adjusted = quality_prefix.map_or_else(
772 || scaled_term_reference(value, confidence_bps, u64::from(model.quality_bps)),
773 |prefix| {
774 i128::from(
776 prefix.wrapping_mul(u64::from(model.quality_bps)) / SCALED_BASIS_POINTS,
777 )
778 },
779 );
780 let latency_penalty = if all_latencies_fit {
781 i128::from(u64::from(model.p95_latency_ms).wrapping_mul(latency_pen_per_ms))
782 } else {
783 i128::from(model.p95_latency_ms) * i128::from(latency_pen_per_ms)
784 };
785 let utility = clamp_i128_to_i64(
786 quality_adjusted - risk_penalty - i128::from(cost) - latency_penalty,
787 );
788
789 if utility <= 0 {
790 rejected.utility += 1;
791 continue;
792 }
793 eligible_models = eligible_models.saturating_add(1);
794
795 let candidate = Candidate {
796 model_id: model.model_id,
797 model_index: u16::try_from(index).unwrap_or(u16::MAX),
798 quality_bps: model.quality_bps,
799 cost,
800 utility,
801 };
802 match best {
803 None => best = Some(candidate),
804 Some(current) if candidate_better(candidate, current) => {
805 second = best;
806 best = Some(candidate);
807 }
808 _ => {
809 if second.is_none_or(|s| candidate_better(candidate, s)) {
810 second = Some(candidate);
811 }
812 }
813 }
814 }
815
816 let evaluated_models = u16::try_from(self.models.len()).unwrap_or(u16::MAX);
817 let Some(best) = best else {
818 return self.reject(
819 input,
820 dominant_rejection_reason(&rejected),
821 evaluated_models,
822 eligible_models,
823 );
824 };
825 let action = if best.model_id == input.requested_model_id {
826 KernelAction::ExecuteRequested
827 } else {
828 KernelAction::Substitute
829 };
830 (
831 KernelDecision {
832 request_sequence: input.request_sequence,
833 action,
834 reason: if action == KernelAction::ExecuteRequested {
835 KernelReason::RequestedModelMaximizesUtility
836 } else {
837 KernelReason::AlternativeMaximizesUtility
838 },
839 selected_model_id: best.model_id,
840 selected_model_index: best.model_index,
841 estimated_cost_microunits: best.cost,
842 expected_utility_microunits: best.utility,
843 counterfactual_model_id: second.map_or(0, |candidate| candidate.model_id),
844 counterfactual_utility_microunits: second.map_or(0, |candidate| candidate.utility),
845 evaluated_models,
846 eligible_models,
847 policy_epoch: self.policy_epoch,
848 catalog_epoch: self.catalog_epoch,
849 },
850 rejected,
851 )
852 }
853
854 #[inline]
855 fn all_costs_fit_u64(&self, input_tokens: u32, output_tokens: u32) -> bool {
856 let input = u64::from(input_tokens)
857 .checked_mul(self.max_input_cost)
858 .and_then(|value| value.checked_add(COST_ROUNDING));
859 let output = u64::from(output_tokens)
860 .checked_mul(self.max_output_cost)
861 .and_then(|value| value.checked_add(COST_ROUNDING));
862 input
863 .zip(output)
864 .is_some_and(|(input, output)| input.checked_add(output).is_some())
865 }
866
867 fn reject(
871 &self,
872 input: KernelInput,
873 reason: KernelReason,
874 evaluated_models: u16,
875 eligible_models: u16,
876 ) -> (KernelDecision, RejectionHistogram) {
877 (
878 KernelDecision {
879 request_sequence: input.request_sequence,
880 action: KernelAction::Reject,
881 reason,
882 selected_model_id: 0,
883 selected_model_index: u16::MAX,
884 estimated_cost_microunits: 0,
885 expected_utility_microunits: 0,
886 counterfactual_model_id: 0,
887 counterfactual_utility_microunits: 0,
888 evaluated_models,
889 eligible_models,
890 policy_epoch: self.policy_epoch,
891 catalog_epoch: self.catalog_epoch,
892 },
893 RejectionHistogram::default(),
894 )
895 }
896}
897
898#[inline(always)]
899fn model_cost_fast(model: &KernelModel, input_tokens: u32, output_tokens: u32) -> u64 {
900 let input = u64::from(input_tokens)
901 .wrapping_mul(model.input_cost_microunits_per_million_tokens)
902 .wrapping_add(COST_ROUNDING)
903 / COST_SCALE;
904 let output = u64::from(output_tokens)
905 .wrapping_mul(model.output_cost_microunits_per_million_tokens)
906 .wrapping_add(COST_ROUNDING)
907 / COST_SCALE;
908 input.wrapping_add(output)
909}
910
911fn model_cost_reference(model: &KernelModel, input_tokens: u32, output_tokens: u32) -> u64 {
912 let input = u128::from(input_tokens)
913 .saturating_mul(u128::from(model.input_cost_microunits_per_million_tokens))
914 .saturating_add(u128::from(COST_ROUNDING))
915 / u128::from(COST_SCALE);
916 let output = u128::from(output_tokens)
917 .saturating_mul(u128::from(model.output_cost_microunits_per_million_tokens))
918 .saturating_add(u128::from(COST_ROUNDING))
919 / u128::from(COST_SCALE);
920 u64::try_from(input.saturating_add(output)).unwrap_or(u64::MAX)
921}
922
923#[inline]
924fn scaled_term_exact(value: u64, first_bps: u64, second_bps: u64) -> i128 {
925 value
926 .checked_mul(first_bps)
927 .and_then(|value| value.checked_mul(second_bps))
928 .map_or_else(
929 || scaled_term_reference(value, first_bps, second_bps),
930 |numerator| i128::from(numerator / SCALED_BASIS_POINTS),
931 )
932}
933
934#[inline]
935fn scaled_term_reference(value: u64, first_bps: u64, second_bps: u64) -> i128 {
936 i128::from(value) * i128::from(first_bps) * i128::from(second_bps)
937 / i128::from(SCALED_BASIS_POINTS)
938}
939
940#[inline(always)]
942fn candidate_better(left: Candidate, right: Candidate) -> bool {
943 left.utility > right.utility
944 || (left.utility == right.utility && left.cost < right.cost)
945 || (left.utility == right.utility
946 && left.cost == right.cost
947 && left.quality_bps > right.quality_bps)
948 || (left.utility == right.utility
949 && left.cost == right.cost
950 && left.quality_bps == right.quality_bps
951 && left.model_id < right.model_id)
952}
953
954fn dominant_rejection_reason(counts: &RejectionCounts) -> KernelReason {
955 let candidates = [
956 (counts.capability, KernelReason::CapabilityConstraint),
957 (counts.region, KernelReason::RegionConstraint),
958 (counts.provider, KernelReason::ProviderConstraint),
959 (counts.quality, KernelReason::QualityConstraint),
960 (counts.risk_ceiling, KernelReason::RiskCeilingConstraint),
961 (counts.latency, KernelReason::LatencyConstraint),
962 (counts.budget, KernelReason::BudgetConstraint),
963 (counts.utility, KernelReason::NonPositiveUtility),
964 (counts.disabled, KernelReason::NoEnabledModel),
965 ];
966 candidates
967 .into_iter()
968 .max_by_key(|(count, _)| *count)
969 .filter(|(count, _)| *count > 0)
970 .map_or(KernelReason::NoEnabledModel, |(_, reason)| reason)
971}
972
973fn clamp_i128_to_i64(value: i128) -> i64 {
974 value.clamp(i128::from(i64::MIN), i128::from(i64::MAX)) as i64
975}
976
977#[cfg(test)]
978mod tests {
979 use std::{hint::black_box, time::Instant};
980
981 use proptest::prelude::*;
982
983 use super::*;
984
985 const TOOLS: u64 = 1 << 0;
986 const REGION_EU: u64 = 1 << 0;
987
988 fn snapshot() -> PolicySnapshot {
989 PolicySnapshot::new_unchecked(
990 7,
991 11,
992 9_600,
993 5_500,
994 10_000,
995 2,
996 vec![
997 KernelModel {
998 model_id: 10,
999 provider_id: 0,
1000 quality_bps: 7_500,
1001 risk_ceiling_bps: 9_500,
1002 enabled: 1,
1003 p95_latency_ms: 180,
1004 capabilities: TOOLS,
1005 region_mask: REGION_EU,
1006 input_cost_microunits_per_million_tokens: 150_000,
1007 output_cost_microunits_per_million_tokens: 600_000,
1008 },
1009 KernelModel {
1010 model_id: 20,
1011 provider_id: 1,
1012 quality_bps: 9_500,
1013 risk_ceiling_bps: 9_500,
1014 enabled: 1,
1015 p95_latency_ms: 450,
1016 capabilities: TOOLS,
1017 region_mask: REGION_EU,
1018 input_cost_microunits_per_million_tokens: 2_500_000,
1019 output_cost_microunits_per_million_tokens: 10_000_000,
1020 },
1021 ],
1022 )
1023 }
1024
1025 fn input() -> KernelInput {
1026 KernelInput {
1027 request_sequence: 1,
1028 requested_model_id: 20,
1029 input_tokens: 2_000,
1030 output_tokens: 500,
1031 business_value_microunits: 100_000_000,
1032 budget_limit_microunits: 20_000_000,
1033 risk_bps: 1_000,
1034 confidence_bps: 9_000,
1035 minimum_quality_bps: 7_000,
1036 max_p95_latency_ms: 1_000,
1037 required_capabilities: TOOLS,
1038 allowed_provider_mask: ALL_PROVIDERS,
1039 required_region_mask: REGION_EU,
1040 }
1041 }
1042
1043 fn prescribe_reference(snapshot: &PolicySnapshot, input: KernelInput) -> KernelDecision {
1044 if input.risk_bps >= snapshot.hard_risk_limit_bps {
1045 return snapshot.reject(input, KernelReason::RiskHardLimit, 0, 0).0;
1046 }
1047 if input.confidence_bps < snapshot.minimum_confidence_bps {
1048 return snapshot
1049 .reject(input, KernelReason::ConfidenceHardLimit, 0, 0)
1050 .0;
1051 }
1052
1053 let mut best: Option<Candidate> = None;
1054 let mut second: Option<Candidate> = None;
1055 let mut eligible_models = 0_u16;
1056 let mut rejected = RejectionCounts::default();
1057 let value = input.business_value_microunits.max(0) as u64;
1058 let risk_penalty = scaled_term_reference(
1059 value,
1060 u64::from(input.risk_bps),
1061 u64::from(snapshot.risk_penalty_multiplier_bps),
1062 );
1063
1064 for (index, model) in snapshot.models.iter().enumerate() {
1065 if model.enabled == 0 {
1066 rejected.disabled += 1;
1067 continue;
1068 }
1069 if model.quality_bps < input.minimum_quality_bps {
1070 rejected.quality += 1;
1071 continue;
1072 }
1073 if input.max_p95_latency_ms > 0 && model.p95_latency_ms > input.max_p95_latency_ms {
1074 rejected.latency += 1;
1075 continue;
1076 }
1077 if model.capabilities & input.required_capabilities != input.required_capabilities {
1078 rejected.capability += 1;
1079 continue;
1080 }
1081 if model.provider_id > MAX_PROVIDER_ID {
1082 rejected.provider += 1;
1083 continue;
1084 }
1085 if input.allowed_provider_mask != ALL_PROVIDERS
1086 && input.allowed_provider_mask & (1_u64 << model.provider_id) == 0
1087 {
1088 rejected.provider += 1;
1089 continue;
1090 }
1091 if input.required_region_mask != 0
1092 && model.region_mask & input.required_region_mask == 0
1093 {
1094 rejected.region += 1;
1095 continue;
1096 }
1097 if input.risk_bps > model.risk_ceiling_bps {
1098 rejected.risk_ceiling += 1;
1099 continue;
1100 }
1101
1102 let cost = model_cost_reference(model, input.input_tokens, input.output_tokens);
1103 if cost > input.budget_limit_microunits {
1104 rejected.budget += 1;
1105 continue;
1106 }
1107 let quality_adjusted = scaled_term_reference(
1108 value,
1109 u64::from(input.confidence_bps),
1110 u64::from(model.quality_bps),
1111 );
1112 let latency_penalty = i128::from(model.p95_latency_ms)
1113 * i128::from(snapshot.latency_penalty_microunits_per_ms);
1114 let utility = clamp_i128_to_i64(
1115 quality_adjusted - risk_penalty - i128::from(cost) - latency_penalty,
1116 );
1117 if utility <= 0 {
1118 rejected.utility += 1;
1119 continue;
1120 }
1121 eligible_models = eligible_models.saturating_add(1);
1122 let candidate = Candidate {
1123 model_id: model.model_id,
1124 model_index: u16::try_from(index).unwrap_or(u16::MAX),
1125 quality_bps: model.quality_bps,
1126 cost,
1127 utility,
1128 };
1129 if best.is_none_or(|current| candidate_better(candidate, current)) {
1130 second = best;
1131 best = Some(candidate);
1132 } else if second.is_none_or(|current| candidate_better(candidate, current)) {
1133 second = Some(candidate);
1134 }
1135 }
1136
1137 let evaluated_models = u16::try_from(snapshot.models.len()).unwrap_or(u16::MAX);
1138 let Some(best) = best else {
1139 return snapshot
1140 .reject(
1141 input,
1142 dominant_rejection_reason(&rejected),
1143 evaluated_models,
1144 eligible_models,
1145 )
1146 .0;
1147 };
1148 let action = if best.model_id == input.requested_model_id {
1149 KernelAction::ExecuteRequested
1150 } else {
1151 KernelAction::Substitute
1152 };
1153 KernelDecision {
1154 request_sequence: input.request_sequence,
1155 action,
1156 reason: if action == KernelAction::ExecuteRequested {
1157 KernelReason::RequestedModelMaximizesUtility
1158 } else {
1159 KernelReason::AlternativeMaximizesUtility
1160 },
1161 selected_model_id: best.model_id,
1162 selected_model_index: best.model_index,
1163 estimated_cost_microunits: best.cost,
1164 expected_utility_microunits: best.utility,
1165 counterfactual_model_id: second.map_or(0, |candidate| candidate.model_id),
1166 counterfactual_utility_microunits: second.map_or(0, |candidate| candidate.utility),
1167 evaluated_models,
1168 eligible_models,
1169 policy_epoch: snapshot.policy_epoch,
1170 catalog_epoch: snapshot.catalog_epoch,
1171 }
1172 }
1173
1174 #[test]
1175 fn prescribes_maximum_utility_not_minimum_price() {
1176 let decision = snapshot().prescribe(input());
1177 assert_eq!(decision.action, KernelAction::ExecuteRequested);
1178 assert_eq!(decision.selected_model_id, 20);
1179 assert_eq!(decision.counterfactual_model_id, 10);
1180 assert!(decision.expected_utility_microunits > decision.counterfactual_utility_microunits);
1181 }
1182
1183 #[test]
1184 fn hard_budget_can_prescribe_substitution() {
1185 let mut request = input();
1186 request.budget_limit_microunits = 1_000;
1187 let decision = snapshot().prescribe(request);
1188 assert_eq!(decision.action, KernelAction::Substitute);
1189 assert_eq!(decision.selected_model_id, 10);
1190 }
1191
1192 #[test]
1193 fn decision_action_helpers_match_action() {
1194 let requested = snapshot().prescribe(input());
1195 assert!(requested.is_executable());
1196 assert!(requested.is_requested_execution());
1197 assert!(!requested.is_substitution());
1198 assert!(!requested.is_rejected());
1199
1200 let mut substitute_input = input();
1201 substitute_input.budget_limit_microunits = 1_000;
1202 let substitute = snapshot().prescribe(substitute_input);
1203 assert!(substitute.is_executable());
1204 assert!(!substitute.is_requested_execution());
1205 assert!(substitute.is_substitution());
1206 assert!(!substitute.is_rejected());
1207
1208 let mut rejected_input = input();
1209 rejected_input.risk_bps = 9_900;
1210 let rejected = snapshot().prescribe(rejected_input);
1211 assert!(!rejected.is_executable());
1212 assert!(!rejected.is_requested_execution());
1213 assert!(!rejected.is_substitution());
1214 assert!(rejected.is_rejected());
1215 }
1216
1217 fn base_model(model_id: u32, enabled: u8) -> KernelModel {
1218 KernelModel {
1219 model_id,
1220 provider_id: 0,
1221 quality_bps: 8_000,
1222 risk_ceiling_bps: 9_500,
1223 enabled,
1224 p95_latency_ms: 200,
1225 capabilities: 0,
1226 region_mask: ALL_REGIONS,
1227 input_cost_microunits_per_million_tokens: 100,
1228 output_cost_microunits_per_million_tokens: 400,
1229 }
1230 }
1231
1232 #[test]
1233 fn input_validate_rejects_out_of_range_bps() {
1234 let mut request = input();
1235 request.confidence_bps = 10_001;
1236 assert_eq!(
1237 request.validate(),
1238 Err(InputError::OutOfRangeBps {
1239 field: "confidence_bps",
1240 value: 10_001,
1241 max: MAX_BPS,
1242 })
1243 );
1244 }
1245
1246 #[test]
1247 fn input_validate_accepts_boundary_bps() {
1248 let mut request = input();
1249 request.risk_bps = MAX_BPS;
1250 request.confidence_bps = MAX_BPS;
1251 request.minimum_quality_bps = MAX_BPS;
1252 assert!(request.validate().is_ok());
1253 }
1254
1255 #[test]
1256 fn checked_prescribe_rejects_invalid_input_before_evaluation() {
1257 let snapshot = snapshot();
1258 let mut request = input();
1259 request.confidence_bps = MAX_BPS + 1;
1260 assert!(matches!(
1261 snapshot.prescribe_checked(request),
1262 Err(InputError::OutOfRangeBps {
1263 field: "confidence_bps",
1264 ..
1265 })
1266 ));
1267 assert!(snapshot.prescribe_with_trace_checked(request).is_err());
1268 assert!(snapshot
1269 .prescribe_batch_checked(&[input(), request])
1270 .is_err());
1271 }
1272
1273 #[test]
1274 fn policy_error_empty_catalog() {
1275 let snap = PolicySnapshot::new_unchecked(1, 1, 9_600, 5_500, 3_500, 0, vec![]);
1276 assert_eq!(snap.validate(), Err(PolicyError::EmptyCatalog));
1277 assert!(matches!(
1278 PolicySnapshot::try_new(1, 1, 9_600, 5_500, 3_500, 0, vec![]),
1279 Err(PolicyError::EmptyCatalog)
1280 ));
1281 }
1282
1283 #[test]
1284 fn policy_error_duplicate_model_id() {
1285 let snap = PolicySnapshot::new_unchecked(
1286 1,
1287 1,
1288 9_600,
1289 5_500,
1290 3_500,
1291 0,
1292 vec![base_model(1, 1), base_model(1, 1)],
1293 );
1294 assert_eq!(
1295 snap.validate(),
1296 Err(PolicyError::DuplicateModelId { model_id: 1 })
1297 );
1298 }
1299
1300 #[test]
1301 fn policy_error_invalid_provider_id() {
1302 let mut model = base_model(1, 1);
1303 model.provider_id = MAX_PROVIDER_ID + 1;
1304 let snap = PolicySnapshot::new_unchecked(1, 1, 9_600, 5_500, 3_500, 0, vec![model]);
1305 assert_eq!(
1306 snap.validate(),
1307 Err(PolicyError::InvalidProviderId {
1308 model_id: 1,
1309 provider_id: MAX_PROVIDER_ID + 1,
1310 })
1311 );
1312 }
1313
1314 #[test]
1315 fn policy_error_no_enabled_models() {
1316 let snap = PolicySnapshot::new_unchecked(
1317 1,
1318 1,
1319 9_600,
1320 5_500,
1321 3_500,
1322 0,
1323 vec![base_model(1, 0), base_model(2, 0)],
1324 );
1325 assert_eq!(snap.validate(), Err(PolicyError::NoEnabledModels));
1326 }
1327
1328 #[test]
1329 fn policy_error_out_of_range_bps() {
1330 let models = vec![base_model(1, 1)];
1331 assert!(matches!(
1332 PolicySnapshot::try_new(1, 1, 10_001, 5_500, 3_500, 0, models.clone()),
1333 Err(PolicyError::OutOfRangeBps { .. })
1334 ));
1335 assert!(matches!(
1336 PolicySnapshot::try_new(1, 1, 9_600, 10_001, 3_500, 0, models.clone()),
1337 Err(PolicyError::OutOfRangeBps { .. })
1338 ));
1339 assert!(matches!(
1340 PolicySnapshot::try_new(1, 1, 9_600, 5_500, 50_001, 0, models.clone()),
1341 Err(PolicyError::OutOfRangeBps { .. })
1342 ));
1343 let mut bad_quality = base_model(2, 1);
1344 bad_quality.quality_bps = 10_001;
1345 assert!(matches!(
1346 PolicySnapshot::try_new(1, 1, 9_600, 5_500, 3_500, 0, vec![bad_quality]),
1347 Err(PolicyError::OutOfRangeBps { .. })
1348 ));
1349 }
1350
1351 #[test]
1352 fn utility_for_model_matches_eligible_catalog_entry() {
1353 let snap = snapshot();
1354 let input = input();
1355 let utility = snap.utility_for_model(input, 20);
1356 assert!(utility.is_some());
1357 assert_eq!(
1358 utility,
1359 Some(snap.prescribe(input).expected_utility_microunits)
1360 );
1361 }
1362
1363 #[test]
1364 fn utility_for_model_none_for_missing_id() {
1365 let snap = snapshot();
1366 assert!(snap.utility_for_model(input(), 999).is_none());
1367 }
1368
1369 #[test]
1370 fn prescribe_batch_matches_individual() {
1371 let snap = snapshot();
1372 let inputs = [
1373 input(),
1374 KernelInput {
1375 request_sequence: 2,
1376 requested_model_id: 10,
1377 input_tokens: 500,
1378 output_tokens: 100,
1379 business_value_microunits: 50_000_000,
1380 budget_limit_microunits: 5_000_000,
1381 risk_bps: 500,
1382 confidence_bps: 9_500,
1383 minimum_quality_bps: 7_000,
1384 max_p95_latency_ms: 500,
1385 required_capabilities: TOOLS,
1386 allowed_provider_mask: ALL_PROVIDERS,
1387 required_region_mask: REGION_EU,
1388 },
1389 ];
1390 let batch = snap.prescribe_batch(&inputs);
1391 assert_eq!(batch.len(), inputs.len());
1392 for (i, &inp) in inputs.iter().enumerate() {
1393 assert_eq!(batch[i], snap.prescribe(inp));
1394 }
1395 }
1396
1397 #[test]
1398 fn hard_constraints_fail_closed() {
1399 let mut request = input();
1400 request.risk_bps = 9_900;
1401 let decision = snapshot().prescribe(request);
1402 assert_eq!(decision.action, KernelAction::Reject);
1403 assert_eq!(decision.reason, KernelReason::RiskHardLimit);
1404
1405 request.risk_bps = 1_000;
1406 request.required_capabilities = 1 << 9;
1407 let decision = snapshot().prescribe(request);
1408 assert_eq!(decision.action, KernelAction::Reject);
1409 assert_eq!(decision.reason, KernelReason::CapabilityConstraint);
1410 }
1411
1412 #[test]
1413 fn extreme_inputs_saturate_without_panicking() {
1414 let mut request = input();
1415 request.input_tokens = u32::MAX;
1416 request.output_tokens = u32::MAX;
1417 request.business_value_microunits = i64::MAX;
1418 request.budget_limit_microunits = u64::MAX;
1419 let decision = snapshot().prescribe(request);
1420 assert_eq!(decision.request_sequence, request.request_sequence);
1421 }
1422
1423 #[test]
1424 fn exact_fast_path_preserves_single_rounding_step() {
1425 assert_eq!(scaled_term_reference(2, 5_001, 9_999), 1);
1426 assert_eq!(scaled_term_exact(2, 5_001, 9_999), 1);
1427 }
1428
1429 proptest! {
1430 #[test]
1431 fn optimized_scaled_term_matches_i128_reference(
1432 value in any::<u64>(),
1433 first_bps in any::<u16>(),
1434 second_bps in any::<u16>(),
1435 ) {
1436 prop_assert_eq!(
1437 scaled_term_exact(value, u64::from(first_bps), u64::from(second_bps)),
1438 scaled_term_reference(value, u64::from(first_bps), u64::from(second_bps)),
1439 );
1440 }
1441
1442 #[test]
1443 fn optimized_cost_matches_u128_reference_when_guard_admits(
1444 input_tokens in any::<u32>(),
1445 output_tokens in any::<u32>(),
1446 input_price in any::<u64>(),
1447 output_price in any::<u64>(),
1448 ) {
1449 let model = KernelModel {
1450 model_id: 1,
1451 provider_id: 0,
1452 quality_bps: 10_000,
1453 risk_ceiling_bps: u16::MAX,
1454 enabled: 1,
1455 p95_latency_ms: 1,
1456 capabilities: 0,
1457 region_mask: ALL_REGIONS,
1458 input_cost_microunits_per_million_tokens: input_price,
1459 output_cost_microunits_per_million_tokens: output_price,
1460 };
1461 let snapshot = PolicySnapshot::new_unchecked(1, 1, u16::MAX, 0, 0, 0, vec![model]);
1462 if snapshot.all_costs_fit_u64(input_tokens, output_tokens) {
1463 prop_assert_eq!(
1464 model_cost_fast(&model, input_tokens, output_tokens),
1465 model_cost_reference(&model, input_tokens, output_tokens),
1466 );
1467 }
1468 }
1469
1470 #[test]
1471 fn optimized_kernel_matches_reference_decision(
1472 input_tokens in any::<u32>(),
1473 output_tokens in any::<u32>(),
1474 value in any::<i64>(),
1475 budget in any::<u64>(),
1476 risk in any::<u16>(),
1477 confidence in any::<u16>(),
1478 minimum_quality in any::<u16>(),
1479 maximum_latency in any::<u32>(),
1480 provider_mask in any::<u64>(),
1481 region_mask in any::<u64>(),
1482 ) {
1483 let mut request = input();
1484 request.input_tokens = input_tokens;
1485 request.output_tokens = output_tokens;
1486 request.business_value_microunits = value;
1487 request.budget_limit_microunits = budget;
1488 request.risk_bps = risk;
1489 request.confidence_bps = confidence;
1490 request.minimum_quality_bps = minimum_quality;
1491 request.max_p95_latency_ms = maximum_latency;
1492 request.allowed_provider_mask = provider_mask;
1493 request.required_region_mask = region_mask;
1494 let snapshot = snapshot();
1495 prop_assert_eq!(snapshot.prescribe(request), prescribe_reference(&snapshot, request));
1496 }
1497
1498 #[test]
1499 fn arbitrary_inputs_never_bypass_provider_fence(
1500 input_tokens in any::<u32>(),
1501 output_tokens in any::<u32>(),
1502 value in any::<i64>(),
1503 budget in any::<u64>(),
1504 risk in any::<u16>(),
1505 confidence in any::<u16>(),
1506 ) {
1507 let mut request = input();
1508 request.input_tokens = input_tokens;
1509 request.output_tokens = output_tokens;
1510 request.business_value_microunits = value;
1511 request.budget_limit_microunits = budget;
1512 request.risk_bps = risk;
1513 request.confidence_bps = confidence;
1514 request.allowed_provider_mask = 0;
1515 let decision = snapshot().prescribe(request);
1516 prop_assert_eq!(decision.action, KernelAction::Reject);
1517 }
1518 }
1519
1520 #[test]
1521 fn provider_id_above_64_rejected_even_with_all_providers() {
1522 let models = vec![KernelModel {
1523 model_id: 1,
1524 provider_id: 65,
1525 quality_bps: 9500,
1526 risk_ceiling_bps: 10000,
1527 enabled: 1,
1528 p95_latency_ms: 500,
1529 capabilities: 0,
1530 region_mask: ALL_REGIONS,
1531 input_cost_microunits_per_million_tokens: 100,
1532 output_cost_microunits_per_million_tokens: 400,
1533 }];
1534 let snapshot = PolicySnapshot::new_unchecked(1, 1, 9600, 5500, 3500, 0, models);
1535 let mut request = input();
1536 request.allowed_provider_mask = ALL_PROVIDERS;
1537 let decision = snapshot.prescribe(request);
1538 assert_eq!(
1539 decision.action,
1540 KernelAction::Reject,
1541 "provider_id >= 64 must be rejected even when mask is ALL_PROVIDERS"
1542 );
1543 }
1544
1545 #[test]
1546 fn provider_id_below_64_accepted_with_all_providers() {
1547 let mut request = input();
1548 request.allowed_provider_mask = ALL_PROVIDERS;
1549 let decision = snapshot().prescribe(request);
1550 assert_ne!(
1551 decision.action,
1552 KernelAction::Reject,
1553 "provider_id < 64 with ALL_PROVIDERS should not be rejected by provider fence"
1554 );
1555 }
1556
1557 #[test]
1558 #[ignore = "release-only kernel guard"]
1559 fn prescriptive_kernel_latency_guard() {
1560 let snapshot = snapshot();
1561 let base = input();
1562 let iterations = 1_000_000_u64;
1563 let started = Instant::now();
1564 for sequence in 0..iterations {
1565 let mut request = base;
1566 request.request_sequence = sequence;
1567 request.input_tokens = 1_000 + (sequence % 1_024) as u32;
1568 black_box(snapshot.prescribe(black_box(request)));
1569 }
1570 let average_ns = started.elapsed().as_nanos() / u128::from(iterations);
1571 assert!(
1572 average_ns < 2_000,
1573 "prescriptive kernel exceeded 2us average guard: {average_ns}ns"
1574 );
1575 }
1576}