verification-calibration 0.1.0

Canonical verification calibration and abstention artifacts
Documentation
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use stack_ids::{CalibrationSnapshotId, NuisanceStateId, RegionId};

pub const CALIBRATION_SNAPSHOT_V1_SCHEMA: &str = "calibration_snapshot_v1";
pub const NUISANCE_STATE_ARTIFACT_V1_SCHEMA: &str = "nuisance_state_artifact_v1";

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CalibrationSnapshot {
    pub schema_version: String,
    pub snapshot_id: CalibrationSnapshotId,
    pub case_id: stack_ids::VerificationCaseId,
    pub recorded_at: String,
    pub comparability_available: bool,
    pub oracle_calibrated: bool,
    pub abstention_threshold_micros: u64,
    pub observed_risk_micros: u64,
    #[serde(default)]
    pub drift_markers: Vec<String>,
    pub forces_advisory_only: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct NuisanceStateArtifact {
    pub schema_version: String,
    pub nuisance_state_id: NuisanceStateId,
    pub recorded_at: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub region_id: Option<RegionId>,
    pub family: String,
    pub markers: Vec<String>,
    pub semantic_change_confounded: bool,
    pub operator_families: Vec<String>,
}

impl CalibrationSnapshot {
    pub fn evaluate(
        case_id: stack_ids::VerificationCaseId,
        recorded_at: impl Into<String>,
        comparability_available: bool,
        oracle_calibrated: bool,
        abstention_threshold_micros: u64,
        observed_risk_micros: u64,
        drift_markers: Vec<String>,
    ) -> Self {
        let forces_advisory_only = !comparability_available
            || !oracle_calibrated
            || observed_risk_micros >= abstention_threshold_micros
            || !drift_markers.is_empty();
        Self {
            schema_version: CALIBRATION_SNAPSHOT_V1_SCHEMA.into(),
            snapshot_id: CalibrationSnapshotId::generate(),
            case_id,
            recorded_at: recorded_at.into(),
            comparability_available,
            oracle_calibrated,
            abstention_threshold_micros,
            observed_risk_micros,
            drift_markers,
            forces_advisory_only,
        }
    }
}

impl NuisanceStateArtifact {
    pub fn new(
        recorded_at: impl Into<String>,
        region_id: Option<RegionId>,
        family: impl Into<String>,
        markers: Vec<String>,
        semantic_change_confounded: bool,
        operator_families: Vec<String>,
    ) -> Self {
        Self {
            schema_version: NUISANCE_STATE_ARTIFACT_V1_SCHEMA.into(),
            nuisance_state_id: NuisanceStateId::generate(),
            recorded_at: recorded_at.into(),
            region_id,
            family: family.into(),
            markers,
            semantic_change_confounded,
            operator_families,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn missing_comparability_forces_advisory_only() {
        let snapshot = CalibrationSnapshot::evaluate(
            stack_ids::VerificationCaseId::new("case-1"),
            "2026-03-12T00:00:00Z",
            false,
            true,
            500_000,
            100_000,
            vec![],
        );
        assert!(snapshot.forces_advisory_only);
    }

    #[test]
    fn nuisance_state_artifact_is_serializable_and_region_bound() {
        let artifact = NuisanceStateArtifact::new(
            "2026-03-13T00:00:00Z",
            Some(RegionId::new("region:demo")),
            "retrieval_widening_shift",
            vec!["widened_scope".into(), "provider_retry_storm".into()],
            true,
            vec!["kernel_execution".into(), "kernel_oracles".into()],
        );

        assert_eq!(artifact.schema_version, NUISANCE_STATE_ARTIFACT_V1_SCHEMA);
        assert_eq!(artifact.region_id, Some(RegionId::new("region:demo")));
        assert!(artifact.semantic_change_confounded);
    }
}