vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Compile-time registry of every [`ComponentSpec`] in vyre-conform.
//!
//! The meta-analogue of [`crate::spec::registry`]. Every load-bearing
//! internal of vyre-conform must register here. [`verify_meta_coverage`]
//! is called from the `build.rs` at build time (wired in Task #11) and
//! rejects any component with missing fields — a compile error, not a
//! runtime warning.
//!
//! [`ComponentSpec`]: crate::meta::component::ComponentSpec

use crate::meta::component::{ComponentKind, ComponentSpec, ContractKind};
use crate::meta::components;

/// Every [`ComponentSpec`] in vyre-conform lives in this slice. New
/// components append entries via their module's public constant, which
/// this slice references.
pub const COMPONENT_REGISTRY: &[&ComponentSpec] = &[
    &components::commutative_checker::COMMUTATIVE_CHECKER_SPEC,
    &components::reference_interpreter::REFERENCE_INTERPRETER_SPEC,
    &components::oracle_resolver::ORACLE_RESOLVER_SPEC,
    &components::mutation_gate::MUTATION_GATE_SPEC,
    &components::independence_certificate::INDEPENDENCE_CERTIFICATE_SPEC,
    &components::composition_proof::COMPOSITION_PROOF_SPEC,
];

/// A coverage error returned by [`verify_meta_coverage`].
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MetaCoverageError {
    /// The component whose spec is incomplete.
    pub component: String,
    /// Actionable diagnostic — always starts with `Fix: ...`.
    pub message: String,
}

/// Validate a single [`ComponentSpec`] for structural completeness.
///
/// This is the mechanical discipline that makes meta-conform trustworthy:
/// a component author cannot register a half-filled [`ComponentSpec`]
/// without a build error.
#[inline]
pub fn validate_component(component: &ComponentSpec) -> Vec<MetaCoverageError> {
    let mut errors = Vec::new();
    let name = component.name;

    if name.is_empty() {
        errors.push(MetaCoverageError {
            component: "<unnamed>".to_string(),
            message: "Fix: set ComponentSpec::name to the qualified module path.".to_string(),
        });
    }

    if component.contracts.is_empty() {
        errors.push(MetaCoverageError {
            component: name.to_string(),
            message: "Fix: declare at least one Contract (pre or post) so meta-tests have \
                 something to verify against."
                .to_string(),
        });
    }

    if component.adversaries.is_empty() {
        errors.push(MetaCoverageError {
            component: name.to_string(),
            message: "Fix: add at least one BrokenComponent adversary so the meta-gate has \
                 a concrete bug to catch."
                .to_string(),
        });
    }

    if component.meta_mutation_sensitivity.is_empty() {
        errors.push(MetaCoverageError {
            component: name.to_string(),
            message: "Fix: declare at least one MetaMutationClass sensitivity so the \
                 meta-mutation harness knows which corruptions to probe."
                .to_string(),
        });
    }

    if component.test_suite_filter.trim().is_empty() {
        errors.push(MetaCoverageError {
            component: name.to_string(),
            message: "Fix: set ComponentSpec::test_suite_filter to a committed test function."
                .to_string(),
        });
    } else if !test_filter_is_committed(component.test_suite_filter) {
        errors.push(MetaCoverageError {
            component: name.to_string(),
            message: format!(
                "Fix: ComponentSpec::test_suite_filter `{}` does not appear in conform/tests. \
                 Use a committed test function name that cargo test can match.",
                component.test_suite_filter
            ),
        });
    }

    if component.spec_table.is_empty() {
        errors.push(MetaCoverageError {
            component: name.to_string(),
            message: "Fix: add at least one ComponentSpecRow with rationale so there is a \
                 didactic input/expected-verdict row a reader can verify in seconds."
                .to_string(),
        });
    }

    // LawChecker must declare boundary witnesses.
    if matches!(component.kind, ComponentKind::LawChecker) {
        if component.boundary_witnesses.is_empty() {
            errors.push(MetaCoverageError {
                component: name.to_string(),
                message: "Fix: LawChecker components must declare at least one BoundaryWitness."
                    .to_string(),
            });
        } else {
            let mut seen = std::collections::HashSet::new();
            for bw in component.boundary_witnesses {
                if bw.id.is_empty() {
                    errors.push(MetaCoverageError {
                        component: name.to_string(),
                        message: "Fix: every BoundaryWitness id must be non-empty.".to_string(),
                    });
                }
                if !seen.insert(bw.id) {
                    errors.push(MetaCoverageError {
                        component: name.to_string(),
                        message: format!("Fix: duplicate BoundaryWitness id `{}`.", bw.id),
                    });
                }
            }
        }
    }

    for row in component.spec_table {
        if row.rationale.is_empty() {
            errors.push(MetaCoverageError {
                component: name.to_string(),
                message: format!(
                    "Fix: ComponentSpecRow `{}` has an empty rationale — explain why \
                     this row is load-bearing.",
                    row.input_id
                ),
            });
        }

        for &cid in row.contract_ids {
            if !component.contracts.iter().any(|c| c.id == cid) {
                errors.push(MetaCoverageError {
                    component: name.to_string(),
                    message: format!(
                        "Fix: ComponentSpecRow `{}` references unknown contract id `{}`.",
                        row.input_id, cid
                    ),
                });
            }
        }

        if matches!(
            row.expected,
            crate::meta::oracle::MetaVerdict::Counterexample { .. }
        ) && row.witness_id.is_empty()
        {
            errors.push(MetaCoverageError {
                component: name.to_string(),
                message: format!(
                    "Fix: ComponentSpecRow `{}` expects Counterexample but has an empty witness_id.",
                    row.input_id
                ),
            });
        }

        if matches!(component.kind, ComponentKind::LawChecker)
            && matches!(
                row.expected,
                crate::meta::oracle::MetaVerdict::Verified { .. }
            )
        {
            for bw in component.boundary_witnesses {
                if !row.expected_boundaries.contains(&bw.id) {
                    errors.push(MetaCoverageError {
                        component: name.to_string(),
                        message: format!(
                            "Fix: ComponentSpecRow `{}` expects Verified but does not \
                             require boundary `{}` in expected_boundaries.",
                            row.input_id, bw.id
                        ),
                    });
                }
            }
        }
    }

    for adversary in component.adversaries {
        if adversary.targets != name {
            errors.push(MetaCoverageError {
                component: name.to_string(),
                message: format!(
                    "Fix: adversary `{}` declares targets=`{}` but is registered under \
                     component `{}`. Route adversaries to their own component only.",
                    adversary.id, adversary.targets, name
                ),
            });
        }

        if adversary.expected_failure_signature.is_empty() {
            errors.push(MetaCoverageError {
                component: name.to_string(),
                message: format!(
                    "Fix: adversary `{}` has an empty expected_failure_signature.",
                    adversary.id
                ),
            });
        }

        for &cid in adversary.covers_contract_ids {
            if !component.contracts.iter().any(|c| c.id == cid) {
                errors.push(MetaCoverageError {
                    component: name.to_string(),
                    message: format!(
                        "Fix: adversary `{}` references unknown contract id `{}`.",
                        adversary.id, cid
                    ),
                });
            }
        }
    }

    for class in component.meta_mutation_sensitivity {
        let covered = component
            .adversaries
            .iter()
            .any(|adv| adv.covers_classes.contains(class));
        if !covered {
            errors.push(MetaCoverageError {
                component: name.to_string(),
                message: format!(
                    "Fix: no adversary covers the required MetaMutationClass `{:?}`. \
                     Add an adversary with `covers_classes` containing it.",
                    class
                ),
            });
        }
    }

    let mut covered_post = std::collections::HashSet::new();
    for row in component.spec_table {
        for &cid in row.contract_ids {
            if component
                .contracts
                .iter()
                .any(|c| c.id == cid && matches!(c.kind, ContractKind::Post))
            {
                covered_post.insert(cid);
            }
        }
    }
    for adv in component.adversaries {
        for &cid in adv.covers_contract_ids {
            if component
                .contracts
                .iter()
                .any(|c| c.id == cid && matches!(c.kind, ContractKind::Post))
            {
                covered_post.insert(cid);
            }
        }
    }
    for contract in component.contracts {
        if matches!(contract.kind, ContractKind::Post) && !covered_post.contains(contract.id) {
            errors.push(MetaCoverageError {
                component: name.to_string(),
                message: format!(
                    "Fix: Post-contract `{}` is prose-only — no spec row or adversary \
                     references it. Add a row or adversary that exercises it.",
                    contract.id
                ),
            });
        }
    }

    errors
}

fn test_filter_is_committed(filter: &str) -> bool {
    let tests_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests");
    let Ok(entries) = std::fs::read_dir(tests_dir) else {
        return false;
    };
    for entry in entries.flatten() {
        let path = entry.path();
        if path.extension().and_then(|ext| ext.to_str()) != Some("rs") {
            continue;
        }
        let Ok(text) = std::fs::read_to_string(&path) else {
            continue;
        };
        if text.contains(filter) {
            return true;
        }
    }
    false
}

/// Walk the [`COMPONENT_REGISTRY`] and verify every required field on
/// every component is populated.
///
/// This is the mechanical discipline that makes meta-conform trustworthy:
/// a component author cannot register a half-filled [`ComponentSpec`]
/// without a build error. Missing adversaries → error. Empty meta-mutation
/// sensitivity → error. Empty spec table → error.
///
/// # Errors
///
/// Returns one [`MetaCoverageError`] per coverage gap. Returns
/// `Err(vec![])` rather than `Ok(())` is deliberately impossible — either
/// all components are complete (`Ok`) or the caller gets a list of exact
/// fixes.
#[inline]
pub fn verify_meta_coverage() -> Result<(), Vec<MetaCoverageError>> {
    let mut errors = Vec::new();

    for component in COMPONENT_REGISTRY {
        errors.extend(validate_component(component));
    }

    if errors.is_empty() {
        Ok(())
    } else {
        Err(errors)
    }
}

#[cfg(test)]
mod tests {

    use super::{verify_meta_coverage, COMPONENT_REGISTRY};

    #[test]
    fn registry_coverage_is_clean() {
        assert_eq!(
            COMPONENT_REGISTRY.len(),
            6,
            "meta component registry should cover the six canonical internals"
        );

        match verify_meta_coverage() {
            Ok(()) => {}
            Err(errors) => {
                let rendered: Vec<String> = errors
                    .iter()
                    .map(|e| format!("{}: {}", e.component, e.message))
                    .collect();
                panic!(
                    "meta component registry has coverage gaps:\n{}",
                    rendered.join("\n")
                );
            }
        }
    }
}