use serde::Serialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum AttributionSource {
Echoed,
ConfirmedBySuccess,
}
impl AttributionSource {
pub fn as_str(self) -> &'static str {
match self {
Self::Echoed => "echoed",
Self::ConfirmedBySuccess => "confirmed_by_success",
}
}
pub fn parse_str(value: &str) -> Option<Self> {
match value {
"echoed" => Some(Self::Echoed),
"confirmed_by_success" => Some(Self::ConfirmedBySuccess),
_ => None,
}
}
pub fn is_conclusive(self) -> bool {
matches!(self, Self::Echoed)
}
}
pub fn is_router_alias(model: &str) -> bool {
matches!(
model.trim().to_ascii_lowercase().as_str(),
"auto" | "default" | "router"
)
}
pub fn grade_observation(
echoed: Option<&str>,
requested: Option<&str>,
succeeded: bool,
) -> (Option<String>, Option<AttributionSource>) {
if let Some(model) = echoed {
return (Some(model.to_string()), Some(AttributionSource::Echoed));
}
if !succeeded {
return (None, None);
}
match requested {
Some(model) if !is_router_alias(model) => (
Some(model.to_string()),
Some(AttributionSource::ConfirmedBySuccess),
),
_ => (None, None),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn only_an_echo_is_conclusive() {
assert!(AttributionSource::Echoed.is_conclusive());
assert!(!AttributionSource::ConfirmedBySuccess.is_conclusive());
}
#[test]
fn grades_round_trip_through_storage() {
for grade in [AttributionSource::Echoed, AttributionSource::ConfirmedBySuccess] {
assert_eq!(AttributionSource::parse_str(grade.as_str()), Some(grade));
}
assert_eq!(AttributionSource::parse_str("guessed"), None);
}
#[test]
fn router_names_are_not_models() {
for name in ["auto", "AUTO", " auto ", "default", "router"] {
assert!(is_router_alias(name), "{name} selects a model, it is not one");
}
for name in ["gpt-5.6", "claude-opus-5", "composer-2", "qwen3.8-max"] {
assert!(!is_router_alias(name));
}
}
}
#[cfg(test)]
mod grade_observation_tests {
use super::*;
#[test]
fn an_echo_outranks_the_request_and_is_conclusive() {
let (model, source) = grade_observation(Some("composer-2"), Some("auto"), true);
assert_eq!(model.as_deref(), Some("composer-2"));
assert_eq!(source, Some(AttributionSource::Echoed));
}
#[test]
fn a_silent_cli_that_succeeded_confirms_what_was_asked_for() {
let (model, source) = grade_observation(None, Some("gpt-5.6-luna"), true);
assert_eq!(model.as_deref(), Some("gpt-5.6-luna"));
assert_eq!(source, Some(AttributionSource::ConfirmedBySuccess));
}
#[test]
fn a_failed_run_confirms_nothing() {
assert_eq!(
grade_observation(None, Some("gemini-3.6-flash-low"), false),
(None, None)
);
}
#[test]
fn a_router_alias_is_never_confirmed() {
assert_eq!(grade_observation(None, Some("auto"), true), (None, None));
}
#[test]
fn nothing_asked_and_nothing_said_stays_unknown() {
assert_eq!(grade_observation(None, None, true), (None, None));
}
}