alloy-assurance 0.3.0

Shared assurance facade for the Alloy workspace
Documentation
use crate::api::{
    EvidenceLevel, FailureClassification, ScenarioOutcome, restart_requery_schema_id,
};

/// Stable workload identity shared across replay-ready evidence payloads.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct WorkloadIdentity<'a> {
    /// Stable workload identifier.
    pub workload_id: &'a str,
    /// Dataset family under evaluation.
    pub dataset_family: &'a str,
    /// Query or retrieval profile identifier.
    pub query_profile: &'a str,
    /// Embedding path or model profile used for the run.
    pub embedding_profile: &'a str,
}

impl<'a> WorkloadIdentity<'a> {
    /// Builds workload identity metadata.
    #[must_use]
    pub const fn new(
        workload_id: &'a str,
        dataset_family: &'a str,
        query_profile: &'a str,
        embedding_profile: &'a str,
    ) -> Self {
        Self {
            workload_id,
            dataset_family,
            query_profile,
            embedding_profile,
        }
    }
}

/// Stable replay bundle metadata.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ReplayBundle<'a> {
    /// Scenario identifier.
    pub scenario_id: &'a str,
    /// Dataset or workload family.
    pub dataset_family: &'a str,
    /// Commit or version provenance.
    pub commit_or_version: &'a str,
    /// Supported maturity tier.
    pub maturity_tier: &'a str,
}

impl<'a> ReplayBundle<'a> {
    /// Builds replay bundle metadata.
    #[must_use]
    pub const fn new(
        scenario_id: &'a str,
        dataset_family: &'a str,
        commit_or_version: &'a str,
        maturity_tier: &'a str,
    ) -> Self {
        Self {
            scenario_id,
            dataset_family,
            commit_or_version,
            maturity_tier,
        }
    }

    /// Returns the stable artifact stem for the bundle.
    #[must_use]
    pub fn artifact_name(&self) -> String {
        format!(
            "alloy-assurance-{}-{}-bundle-{}",
            self.commit_or_version, self.maturity_tier, self.scenario_id
        )
    }
}

/// Assertion record for replay-ready evidence payloads.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AssertionRecord<'a> {
    /// Stable assertion identifier.
    pub assertion_id: &'a str,
    /// Human-readable assertion description.
    pub description: &'a str,
    /// Assertion outcome.
    pub outcome: ScenarioOutcome,
    /// Expected value or invariant.
    pub expected: &'a str,
    /// Actual observed value or result.
    pub actual: &'a str,
}

impl<'a> AssertionRecord<'a> {
    /// Builds an assertion record.
    #[must_use]
    pub const fn new(
        assertion_id: &'a str,
        description: &'a str,
        outcome: ScenarioOutcome,
        expected: &'a str,
        actual: &'a str,
    ) -> Self {
        Self {
            assertion_id,
            description,
            outcome,
            expected,
            actual,
        }
    }
}

/// Artifact reference attached to replay-ready evidence.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AttachedArtifact<'a> {
    /// Artifact role inside the evidence package.
    pub artifact_role: &'a str,
    /// Stable artifact name or path.
    pub artifact_ref: &'a str,
    /// Media type or format hint.
    pub media_type: &'a str,
}

impl<'a> AttachedArtifact<'a> {
    /// Builds an attached artifact reference.
    #[must_use]
    pub const fn new(artifact_role: &'a str, artifact_ref: &'a str, media_type: &'a str) -> Self {
        Self {
            artifact_role,
            artifact_ref,
            media_type,
        }
    }
}

/// Replay-ready payload fields required by downstream scenario consumers.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ReplayPayload<'a> {
    /// Stable scenario identifier.
    pub scenario_id: &'a str,
    /// Replay bundle metadata.
    pub bundle: ReplayBundle<'a>,
    /// Command or script entry point used to reproduce the scenario.
    pub reproduction_entrypoint: &'a str,
    /// Runner or producer of the replay bundle.
    pub runner: &'a str,
}

impl<'a> ReplayPayload<'a> {
    /// Builds replay-ready payload metadata.
    #[must_use]
    pub const fn new(
        scenario_id: &'a str,
        bundle: ReplayBundle<'a>,
        reproduction_entrypoint: &'a str,
        runner: &'a str,
    ) -> Self {
        Self {
            scenario_id,
            bundle,
            reproduction_entrypoint,
            runner,
        }
    }
}

/// Scenario manifest metadata shared across tooling and evidence.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ScenarioManifest<'a> {
    /// Scenario identifier.
    pub scenario_id: &'a str,
    /// Scenario family or runtime band.
    pub scenario_family: &'a str,
    /// Tags used by tooling and reporting.
    pub tags: &'a [&'a str],
}

impl<'a> ScenarioManifest<'a> {
    /// Builds a scenario manifest.
    #[must_use]
    pub const fn new(scenario_id: &'a str, scenario_family: &'a str, tags: &'a [&'a str]) -> Self {
        Self {
            scenario_id,
            scenario_family,
            tags,
        }
    }

    /// Renders a short summary line for report output.
    #[must_use]
    pub fn summary_line(&self) -> String {
        format!(
            "{} [{}] tags={}",
            self.scenario_id,
            self.scenario_family,
            self.tags.join(",")
        )
    }
}

/// Evidence record shared across scenario and benchmark outputs.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct EvidenceEnvelope<'a> {
    /// Artifact identifier.
    pub artifact_id: &'a str,
    /// Dataset family or workload family.
    pub dataset_family: &'a str,
    /// Commit or version provenance.
    pub commit_or_version: &'a str,
    /// Maturity tier under evaluation.
    pub maturity_tier: &'a str,
    /// Gating level.
    pub level: EvidenceLevel,
    /// Last recorded outcome.
    pub outcome: ScenarioOutcome,
    /// Last recorded failure classification.
    pub failure: FailureClassification,
}

impl<'a> EvidenceEnvelope<'a> {
    /// Builds an evidence envelope with a conservative initial state.
    #[must_use]
    pub const fn new(
        artifact_id: &'a str,
        dataset_family: &'a str,
        commit_or_version: &'a str,
        maturity_tier: &'a str,
        level: EvidenceLevel,
    ) -> Self {
        Self {
            artifact_id,
            dataset_family,
            commit_or_version,
            maturity_tier,
            level,
            outcome: ScenarioOutcome::Pass,
            failure: FailureClassification::None,
        }
    }

    /// Records a new outcome onto the envelope.
    pub fn record_outcome(
        &mut self,
        outcome: ScenarioOutcome,
        failure: FailureClassification,
    ) -> &mut Self {
        self.outcome = outcome;
        self.failure = failure;
        self
    }

    /// Returns whether the evidence still permits a release claim.
    #[must_use]
    pub const fn permits_release(&self) -> bool {
        match self.level {
            EvidenceLevel::ReleaseBlocking => matches!(self.outcome, ScenarioOutcome::Pass),
            EvidenceLevel::Informational | EvidenceLevel::RegressionProtecting => true,
        }
    }

    /// Converts the envelope into a stable report-oriented bundle identifier.
    #[must_use]
    pub fn artifact_name(&self) -> String {
        format!(
            "alloy-assurance-{}-{}-report-{}",
            self.commit_or_version, self.maturity_tier, self.artifact_id
        )
    }

    /// Renders a compact report line.
    #[must_use]
    pub fn report_line(&self) -> String {
        format!(
            "{} outcome={:?} failure={}",
            self.artifact_id,
            self.outcome,
            self.failure.as_str()
        )
    }
}

/// Typed restart/re-query evidence payload shared by Iridium and Strontium.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RestartRequeryEvidence<'a> {
    /// Stable schema identifier for the payload.
    pub schema_id: &'static str,
    /// Workload identity for the scenario.
    pub workload: WorkloadIdentity<'a>,
    /// Release-gating envelope for the evidence.
    pub envelope: EvidenceEnvelope<'a>,
    /// Structured assertion outcomes for the scenario.
    pub assertions: Vec<AssertionRecord<'a>>,
    /// Attached evidence artifacts.
    pub artifacts: Vec<AttachedArtifact<'a>>,
    /// Replay-ready payload fields.
    pub replay: ReplayPayload<'a>,
}

impl<'a> RestartRequeryEvidence<'a> {
    /// Builds typed restart/re-query evidence and derives the envelope outcome.
    #[must_use]
    pub fn new(
        workload: WorkloadIdentity<'a>,
        mut envelope: EvidenceEnvelope<'a>,
        assertions: Vec<AssertionRecord<'a>>,
        artifacts: Vec<AttachedArtifact<'a>>,
        replay: ReplayPayload<'a>,
    ) -> Self {
        envelope.record_outcome(
            aggregate_outcome(&assertions),
            aggregate_failure(&assertions),
        );

        Self {
            schema_id: restart_requery_schema_id(),
            workload,
            envelope,
            assertions,
            artifacts,
            replay,
        }
    }

    /// Returns whether the payload contains the required replay-ready fields.
    #[must_use]
    pub fn is_replay_ready(&self) -> bool {
        !self.assertions.is_empty()
            && self
                .artifacts
                .iter()
                .any(|artifact| artifact.artifact_role == "replay-bundle")
            && !self.replay.reproduction_entrypoint.is_empty()
            && !self.replay.runner.is_empty()
    }
}

fn aggregate_outcome(assertions: &[AssertionRecord<'_>]) -> ScenarioOutcome {
    if assertions
        .iter()
        .all(|assertion| assertion.outcome == ScenarioOutcome::Pass)
    {
        ScenarioOutcome::Pass
    } else if assertions
        .iter()
        .all(|assertion| assertion.outcome == ScenarioOutcome::Fail)
    {
        ScenarioOutcome::Fail
    } else {
        ScenarioOutcome::Mixed
    }
}

fn aggregate_failure(assertions: &[AssertionRecord<'_>]) -> FailureClassification {
    if assertions
        .iter()
        .any(|assertion| assertion.outcome != ScenarioOutcome::Pass)
    {
        FailureClassification::RestartConsistency
    } else {
        FailureClassification::None
    }
}