vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Pipeline proof-token validation before composition dispatch.

use super::chain_version;
use crate::spec::types::{ChainSpec, ParityFailure, ProofToken};

#[inline]
pub(crate) fn validate_chain(chain: &ChainSpec) -> Result<(), Box<ParityFailure>> {
    let expected = match ProofToken::from_specs(&chain.specs, chain.proof_token.computed_at) {
        Ok(t) => t,
        Err(err) => {
            return Err(Box::new(ParityFailure {
                op_id: chain.id.clone(),
                generator: "composition-proof".to_string(),
                input_label: "construction-token".to_string(),
                input: Vec::new(),
                gpu_output: Vec::new(),
                cpu_output: Vec::new(),
                message: format!(
                    "composition proof token recomputation failed for {}: {err}. \
                     Fix: verify that all component ops satisfy their declared laws.",
                    chain.id
                ),
                spec_version: chain_version(chain),
                workgroup_size: 0,
            }));
        }
    };
    if chain.proof_token.theorem_claims_match(&expected) {
        return Ok(());
    }

    Err(Box::new(ParityFailure {
        op_id: chain.id.clone(),
        generator: "composition-proof".to_string(),
        input_label: "construction-token".to_string(),
        input: Vec::new(),
        gpu_output: Vec::new(),
        cpu_output: Vec::new(),
        message: format!(
            "composition proof token mismatch for {}: claimed preserved=[{}], broken=[{}], \
             theorems=[{}]; expected preserved=[{}], broken=[{}], theorems=[{}]. \
             Fix: build ChainSpec through a composer or recompute ProofToken::from_specs \
             before dispatch.",
            chain.id,
            law_names(&chain.proof_token.preserved_laws),
            law_names(&chain.proof_token.broken_laws),
            chain.proof_token.theorem_chain.join(","),
            law_names(&expected.preserved_laws),
            law_names(&expected.broken_laws),
            expected.theorem_chain.join(","),
        ),
        spec_version: chain_version(chain),
        workgroup_size: 0,
    }))
}

fn law_names(laws: &[crate::spec::law::AlgebraicLaw]) -> String {
    laws.iter()
        .map(crate::spec::law::AlgebraicLaw::name)
        .collect::<Vec<_>>()
        .join(",")
}