use serde::{Deserialize, Serialize};
pub const PREMIUM_DECLINE_FLOOR: u32 = 500;
pub const PREMIUM_HIGH_RISK_FLOOR: u32 = 500;
pub const PREMIUM_MEDIUM_RISK_FLOOR: u32 = 700;
pub const PREMIUM_LOW_RISK_FLOOR: u32 = 900;
pub const DEFAULT_BEHAVIORAL_PENALTY_PER_SIGMA: u32 = 50;
pub const DEFAULT_BEHAVIORAL_PENALTY_CAP: u32 = 250;
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct LookbackWindow {
pub since: u64,
pub until: u64,
}
impl LookbackWindow {
pub fn new(since: u64, until: u64) -> Result<Self, String> {
if since > until {
return Err(format!(
"premium lookback window requires since <= until, got since={since} until={until}"
));
}
Ok(Self { since, until })
}
#[must_use]
pub fn width_secs(&self) -> u64 {
self.until.saturating_sub(self.since)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PremiumInputs {
pub compliance_score: Option<u32>,
pub behavioral_z_score: Option<f64>,
pub behavioral_threshold: f64,
pub behavioral_penalty_per_sigma: u32,
pub behavioral_penalty_cap: u32,
pub base_rate_cents: u64,
pub currency: String,
}
impl PremiumInputs {
#[must_use]
pub fn new(
compliance_score: Option<u32>,
behavioral_z_score: Option<f64>,
base_rate_cents: u64,
currency: impl Into<String>,
) -> Self {
Self {
compliance_score,
behavioral_z_score,
behavioral_threshold: 3.0,
behavioral_penalty_per_sigma: DEFAULT_BEHAVIORAL_PENALTY_PER_SIGMA,
behavioral_penalty_cap: DEFAULT_BEHAVIORAL_PENALTY_CAP,
base_rate_cents,
currency: currency.into(),
}
}
pub fn validate(&self) -> Result<(), String> {
if self.base_rate_cents == 0 {
return Err("premium base_rate_cents must be greater than zero".to_string());
}
let currency = self.currency.trim();
if currency.len() != 3
|| !currency
.chars()
.all(|character| character.is_ascii_uppercase())
{
return Err(format!(
"premium currency must be a three-letter uppercase ISO-style code, got `{}`",
self.currency
));
}
if self.behavioral_threshold.is_nan() || self.behavioral_threshold < 0.0 {
return Err(
"premium behavioral_threshold must be a finite non-negative number".to_string(),
);
}
if let Some(score) = self.compliance_score {
if score > 1000 {
return Err(format!(
"premium compliance_score must be in 0..=1000, got {score}"
));
}
}
if let Some(z) = self.behavioral_z_score {
if z.is_nan() || z.is_infinite() {
return Err("premium behavioral_z_score must be finite".to_string());
}
}
Ok(())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "disposition", rename_all = "snake_case")]
pub enum PremiumQuote {
Quoted {
agent_id: String,
scope: String,
lookback_window: LookbackWindow,
combined_score: u32,
base_rate_cents: u64,
score_adjustment: f64,
quoted_cents: u64,
currency: String,
justification: String,
},
Declined {
agent_id: String,
scope: String,
lookback_window: LookbackWindow,
combined_score: Option<u32>,
reason: PremiumDeclineReason,
justification: String,
},
}
impl PremiumQuote {
#[must_use]
pub fn agent_id(&self) -> &str {
match self {
PremiumQuote::Quoted { agent_id, .. } | PremiumQuote::Declined { agent_id, .. } => {
agent_id
}
}
}
#[must_use]
pub fn scope(&self) -> &str {
match self {
PremiumQuote::Quoted { scope, .. } | PremiumQuote::Declined { scope, .. } => scope,
}
}
#[must_use]
pub fn lookback_window(&self) -> LookbackWindow {
match self {
PremiumQuote::Quoted {
lookback_window, ..
}
| PremiumQuote::Declined {
lookback_window, ..
} => *lookback_window,
}
}
#[must_use]
pub fn is_quoted(&self) -> bool {
matches!(self, PremiumQuote::Quoted { .. })
}
#[must_use]
pub fn is_declined(&self) -> bool {
matches!(self, PremiumQuote::Declined { .. })
}
#[must_use]
pub fn quoted_cents(&self) -> Option<u64> {
match self {
PremiumQuote::Quoted { quoted_cents, .. } => Some(*quoted_cents),
PremiumQuote::Declined { .. } => None,
}
}
#[must_use]
pub fn combined_score(&self) -> Option<u32> {
match self {
PremiumQuote::Quoted { combined_score, .. } => Some(*combined_score),
PremiumQuote::Declined { combined_score, .. } => *combined_score,
}
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum PremiumDeclineReason {
ScoreBelowFloor,
MissingComplianceScore,
InvalidInputs,
}
#[must_use]
pub fn price_premium(
agent_id: &str,
scope: &str,
lookback_window: LookbackWindow,
inputs: &PremiumInputs,
) -> PremiumQuote {
if let Err(error) = inputs.validate() {
return PremiumQuote::Declined {
agent_id: agent_id.to_string(),
scope: scope.to_string(),
lookback_window,
combined_score: None,
reason: PremiumDeclineReason::InvalidInputs,
justification: format!("premium inputs failed validation: {error}"),
};
}
let Some(compliance_score) = inputs.compliance_score else {
return PremiumQuote::Declined {
agent_id: agent_id.to_string(),
scope: scope.to_string(),
lookback_window,
combined_score: None,
reason: PremiumDeclineReason::MissingComplianceScore,
justification: "compliance score unavailable for agent; premium declined fail-closed"
.to_string(),
};
};
let (behavioral_penalty, behavioral_note) =
behavioral_penalty(inputs.behavioral_z_score, inputs);
let combined_score = compliance_score.saturating_sub(behavioral_penalty);
if combined_score < PREMIUM_DECLINE_FLOOR {
return PremiumQuote::Declined {
agent_id: agent_id.to_string(),
scope: scope.to_string(),
lookback_window,
combined_score: Some(combined_score),
reason: PremiumDeclineReason::ScoreBelowFloor,
justification: format!(
"combined score {combined_score} is below the decline floor {PREMIUM_DECLINE_FLOOR} \
(compliance_score={compliance_score}, behavioral_penalty={behavioral_penalty}{behavioral_note})",
),
};
}
let score_adjustment = risk_multiplier(combined_score);
let quoted_cents = compute_quoted_cents(inputs.base_rate_cents, score_adjustment);
PremiumQuote::Quoted {
agent_id: agent_id.to_string(),
scope: scope.to_string(),
lookback_window,
combined_score,
base_rate_cents: inputs.base_rate_cents,
score_adjustment,
quoted_cents,
currency: inputs.currency.trim().to_ascii_uppercase(),
justification: format!(
"compliance_score={compliance_score}, behavioral_penalty={behavioral_penalty}{behavioral_note}, \
combined_score={combined_score}, risk_multiplier={score_adjustment}, \
quoted_cents = base_rate_cents({}) * (1 + risk_multiplier({score_adjustment})) = {quoted_cents}",
inputs.base_rate_cents
),
}
}
#[must_use]
pub fn risk_multiplier(score: u32) -> f64 {
if score > PREMIUM_LOW_RISK_FLOOR {
1.0
} else if score >= PREMIUM_MEDIUM_RISK_FLOOR {
2.0
} else if score >= PREMIUM_HIGH_RISK_FLOOR {
5.0
} else {
f64::INFINITY
}
}
fn behavioral_penalty(z: Option<f64>, inputs: &PremiumInputs) -> (u32, String) {
match z {
None => (0, String::new()),
Some(z) => {
let magnitude = z.abs();
if magnitude <= inputs.behavioral_threshold {
(
0,
format!(
", behavioral_z={:.3} under threshold {:.3}",
magnitude, inputs.behavioral_threshold
),
)
} else {
let sigma_over = magnitude - inputs.behavioral_threshold;
let raw = sigma_over * f64::from(inputs.behavioral_penalty_per_sigma);
let raw_points = raw.round().clamp(0.0, f64::from(u32::MAX)) as u32;
let penalty = raw_points.min(inputs.behavioral_penalty_cap);
(
penalty,
format!(
", behavioral_z={:.3} over threshold {:.3} (capped at {})",
magnitude, inputs.behavioral_threshold, inputs.behavioral_penalty_cap
),
)
}
}
}
}
fn compute_quoted_cents(base: u64, multiplier: f64) -> u64 {
if !multiplier.is_finite() || multiplier < 0.0 {
return u64::MAX;
}
let factor = 1.0 + multiplier;
let product = (base as f64) * factor;
if !product.is_finite() || product < 0.0 {
return u64::MAX;
}
let rounded = product.round();
if rounded >= (u64::MAX as f64) {
return u64::MAX;
}
rounded as u64
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
fn window() -> LookbackWindow {
LookbackWindow::new(1_000_000, 1_000_600).unwrap()
}
fn inputs(score: Option<u32>, z: Option<f64>) -> PremiumInputs {
PremiumInputs::new(score, z, 1_000, "USD")
}
#[test]
fn clean_history_quotes_lowest_band() {
let quote = price_premium(
"agent-clean",
"tool:exec",
window(),
&inputs(Some(950), None),
);
match quote {
PremiumQuote::Quoted {
score_adjustment,
quoted_cents,
combined_score,
..
} => {
assert_eq!(combined_score, 950);
assert!((score_adjustment - 1.0).abs() < f64::EPSILON);
assert_eq!(quoted_cents, 2_000);
}
other => panic!("expected Quoted, got {other:?}"),
}
}
#[test]
fn medium_band_multiplies_base_rate_by_three() {
let quote = price_premium("agent-med", "tool:exec", window(), &inputs(Some(750), None));
match quote {
PremiumQuote::Quoted {
score_adjustment,
quoted_cents,
..
} => {
assert!((score_adjustment - 2.0).abs() < f64::EPSILON);
assert_eq!(quoted_cents, 3_000);
}
other => panic!("expected Quoted, got {other:?}"),
}
}
#[test]
fn high_risk_band_multiplies_base_rate_by_six() {
let quote = price_premium(
"agent-risk",
"tool:exec",
window(),
&inputs(Some(550), None),
);
match quote {
PremiumQuote::Quoted {
score_adjustment,
quoted_cents,
..
} => {
assert!((score_adjustment - 5.0).abs() < f64::EPSILON);
assert_eq!(quoted_cents, 6_000);
}
other => panic!("expected Quoted, got {other:?}"),
}
}
#[test]
fn score_below_floor_declines() {
let quote = price_premium("agent-bad", "tool:exec", window(), &inputs(Some(200), None));
match quote {
PremiumQuote::Declined {
reason,
combined_score,
..
} => {
assert_eq!(reason, PremiumDeclineReason::ScoreBelowFloor);
assert_eq!(combined_score, Some(200));
}
other => panic!("expected Declined, got {other:?}"),
}
}
#[test]
fn missing_compliance_score_declines_fail_closed() {
let quote = price_premium("agent-?", "tool:exec", window(), &inputs(None, None));
match quote {
PremiumQuote::Declined { reason, .. } => {
assert_eq!(reason, PremiumDeclineReason::MissingComplianceScore);
}
other => panic!("expected Declined, got {other:?}"),
}
}
#[test]
fn behavioral_anomaly_pushes_score_down() {
let bump = inputs(Some(920), Some(5.0));
let quote = price_premium("agent-anom", "tool:exec", window(), &bump);
match quote {
PremiumQuote::Quoted {
combined_score,
score_adjustment,
..
} => {
assert_eq!(combined_score, 820);
assert!((score_adjustment - 2.0).abs() < f64::EPSILON);
}
other => panic!("expected Quoted with penalty applied, got {other:?}"),
}
}
#[test]
fn behavioral_anomaly_can_force_decline() {
let mut bump = inputs(Some(720), Some(10.0));
bump.behavioral_penalty_per_sigma = 80;
bump.behavioral_penalty_cap = 500;
let quote = price_premium("agent-anom-decline", "tool:exec", window(), &bump);
assert!(matches!(
quote,
PremiumQuote::Declined {
reason: PremiumDeclineReason::ScoreBelowFloor,
..
}
));
}
#[test]
fn formula_is_deterministic_for_equal_inputs() {
let a = price_premium("agent-x", "scope", window(), &inputs(Some(800), Some(1.5)));
let b = price_premium("agent-x", "scope", window(), &inputs(Some(800), Some(1.5)));
assert_eq!(a, b);
}
#[test]
fn invalid_inputs_decline() {
let mut bad = inputs(Some(950), None);
bad.base_rate_cents = 0;
let quote = price_premium("agent-x", "scope", window(), &bad);
assert!(matches!(
quote,
PremiumQuote::Declined {
reason: PremiumDeclineReason::InvalidInputs,
..
}
));
}
#[test]
fn clean_quote_is_less_than_denial_heavy_quote() {
let clean = price_premium("clean", "scope", window(), &inputs(Some(980), None));
let denied = price_premium("denials", "scope", window(), &inputs(Some(560), None));
let clean_cents = clean.quoted_cents().unwrap();
let denied_cents = denied.quoted_cents().unwrap();
assert!(
clean_cents < denied_cents,
"expected clean ({clean_cents}) < denials ({denied_cents})"
);
}
#[test]
fn lookback_window_rejects_inverted_range() {
let err = LookbackWindow::new(100, 50).unwrap_err();
assert!(err.contains("since <= until"));
}
}