khive-runtime 0.12.0

Composable Service API: entity/note CRUD, graph traversal, hybrid search, curation.
Documentation
//! Acceptance-matrix generator (ADR-115 Amendment 1; executable contract §2, §6).
//!
//! The matrix is generated by crossing every row of
//! [`declaration::FINALIZER_ENTRY_POINTS`] with the fixed set of
//! [`MatrixCaseKind`] the executable contract requires each declared entry
//! point to cover. No entry-point list is hand-maintained here or by any
//! consumer — the acceptance harness must iterate [`generated_acceptance_matrix`]
//! rather than enumerate entry points itself.

use super::declaration::{FinalizerEntryPoint, FINALIZER_ENTRY_POINTS};

/// The fixed, closed set of acceptance-case kinds every declared entry point
/// must cover (executable contract §2, §6).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(dead_code)] // consumed by the execution/outcome increment (step 15)
pub(crate) enum MatrixCaseKind {
    LegacyScannerBehavior,
    FixtureMatch,
    OneByteMiss,
    WrongScopeMiss,
    ReservedKeyMutation,
    SupportedEcho,
    RecordWriteFailure,
    StampFailure,
    SuccessAuditFailure,
    SecondOrderFailureAuditFailure,
    OneSnapshotRefreshRace,
}

impl MatrixCaseKind {
    /// Stable, exhaustive declaration order — the order the generator emits
    /// cases in for every entry point.
    pub(crate) const ALL: &'static [MatrixCaseKind] = &[
        MatrixCaseKind::LegacyScannerBehavior,
        MatrixCaseKind::FixtureMatch,
        MatrixCaseKind::OneByteMiss,
        MatrixCaseKind::WrongScopeMiss,
        MatrixCaseKind::ReservedKeyMutation,
        MatrixCaseKind::SupportedEcho,
        MatrixCaseKind::RecordWriteFailure,
        MatrixCaseKind::StampFailure,
        MatrixCaseKind::SuccessAuditFailure,
        MatrixCaseKind::SecondOrderFailureAuditFailure,
        MatrixCaseKind::OneSnapshotRefreshRace,
    ];
}

/// One generated acceptance-matrix row: a declared entry point crossed with
/// one required case kind.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)] // consumed by the execution/outcome increment (step 15)
pub(crate) struct MatrixRow {
    pub(crate) entry_point: &'static FinalizerEntryPoint,
    pub(crate) case: MatrixCaseKind,
}

/// Generate the full acceptance matrix from [`FINALIZER_ENTRY_POINTS`].
///
/// Deterministic: iterates the declaration in its declared order and
/// [`MatrixCaseKind::ALL`] in its declared order, so repeated calls produce
/// an identical sequence. This is the sole source of matrix rows — the
/// harness must not maintain a second, independent entry-point or case list.
#[allow(dead_code)] // consumed by the execution/outcome increment (step 15)
pub(crate) fn generated_acceptance_matrix() -> Vec<MatrixRow> {
    let mut rows = Vec::with_capacity(FINALIZER_ENTRY_POINTS.len() * MatrixCaseKind::ALL.len());
    for entry_point in FINALIZER_ENTRY_POINTS {
        for &case in MatrixCaseKind::ALL {
            rows.push(MatrixRow { entry_point, case });
        }
    }
    rows
}

/// Cases required of the currently wired storage routes. Caller echo
/// support remains deferred; its appearance still reaches reservation refusal.
pub(crate) fn generated_wired_acceptance_matrix() -> Vec<MatrixRow> {
    generated_acceptance_matrix()
        .into_iter()
        .filter(|row| row.entry_point.wired && row.case != MatrixCaseKind::SupportedEcho)
        .collect()
}

/// Source witnesses are separate from execution results: these tests are not
/// evidence of a passed native run. Missing route-specific witnesses remain
/// visible even where the shared finalizer state-machine harness has a case.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RouteWitness {
    SourceTest(&'static str),
    Missing(&'static str),
    Deferred(&'static str),
}

pub(crate) fn route_witness(row: MatrixRow) -> RouteWitness {
    use MatrixCaseKind as Case;
    use RouteWitness::{Deferred, Missing, SourceTest};
    if !row.entry_point.wired {
        return Deferred("note storage routes are not wired");
    }
    match (row.entry_point.id, row.case) {
        (_, Case::SupportedEcho) => Deferred("caller echo is not enabled; reserved keys refuse"),
        (_, Case::FixtureMatch) => {
            SourceTest("declared_entity_routes_persist_stamp_and_one_exact_audit")
        }
        ("entity.create", Case::LegacyScannerBehavior) => {
            SourceTest("empty_manifest_keeps_clean_writes_and_legacy_refusals")
        }
        ("entity.update", Case::LegacyScannerBehavior) => SourceTest(
            "empty_manifest_update_preserves_patch_scanning_and_nonempty_scans_final_state",
        ),
        ("entity.bulk", Case::LegacyScannerBehavior) => {
            SourceTest("empty_manifest_keeps_clean_writes_and_legacy_refusals")
        }
        (_, Case::OneByteMiss | Case::WrongScopeMiss | Case::ReservedKeyMutation) => {
            SourceTest("generated_negative_candidates_refuse_on_every_wired_route")
        }
        (
            _,
            Case::RecordWriteFailure
            | Case::StampFailure
            | Case::SuccessAuditFailure
            | Case::SecondOrderFailureAuditFailure,
        ) => SourceTest("generated_faults_preserve_each_route_and_classify_failure_audit_loss"),
        ("entity.create", Case::OneSnapshotRefreshRace) => {
            SourceTest("direct_preflight_snapshot_survives_refresh_and_next_context_sees_empty")
        }
        ("entity.update", Case::OneSnapshotRefreshRace) => {
            SourceTest("actual_update_keeps_its_snapshot_when_embedding_refreshes_the_manifest")
        }
        ("entity.bulk", Case::OneSnapshotRefreshRace) => {
            SourceTest("prepared_bulk_uses_one_snapshot_across_manifest_refresh")
        }
        _ => Missing("new route requires its own storage witness"),
    }
}

/// Real shared-handler hook normalization runs outside the runtime constructor.
/// The runtime suite does not substitute a manually mutated argument for that
/// handler integration witness.
pub(crate) const MISSING_HANDLER_WITNESS: &str =
    "shared create handler: hook-introduced matched value, second secret, and reserved stamp";

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

    #[test]
    fn wired_witnesses_report_missing_and_deferred_routes_explicitly() {
        let rows = generated_acceptance_matrix();
        assert!(generated_wired_acceptance_matrix()
            .iter()
            .all(|row| matches!(route_witness(*row), RouteWitness::SourceTest(_))));
        assert!(rows
            .iter()
            .filter(|row| !row.entry_point.wired)
            .all(|row| matches!(route_witness(*row), RouteWitness::Deferred(_))));
    }

    #[test]
    fn wired_matrix_contains_entity_families_without_activating_notes_or_echo() {
        let rows = generated_wired_acceptance_matrix();
        let families: BTreeSet<_> = rows.iter().map(|row| row.entry_point.id).collect();
        assert_eq!(
            families,
            BTreeSet::from(["entity.create", "entity.update", "entity.bulk"])
        );
        assert!(rows
            .iter()
            .all(|row| row.case != MatrixCaseKind::SupportedEcho));
        assert_eq!(rows.len(), families.len() * (MatrixCaseKind::ALL.len() - 1));
    }

    /// Generation: the matrix is actually produced, and its size is the
    /// exact cross product of declaration rows and case kinds — not a
    /// hand-picked or truncated subset.
    #[test]
    fn generation_produces_full_cross_product() {
        let rows = generated_acceptance_matrix();
        assert_eq!(
            rows.len(),
            FINALIZER_ENTRY_POINTS.len() * MatrixCaseKind::ALL.len()
        );
        assert_eq!(rows[0].entry_point.id, "entity.create");
        assert_eq!(rows[0].case, MatrixCaseKind::LegacyScannerBehavior);
    }

    /// Completeness: every declared entry point appears with every required
    /// case kind exactly once — no declaration row is skipped and no case
    /// kind is missing for any row.
    #[test]
    fn completeness_covers_every_entry_point_and_case_kind() {
        let rows = generated_acceptance_matrix();

        for entry_point in FINALIZER_ENTRY_POINTS {
            let cases_for_entry: BTreeSet<MatrixCaseKind> = rows
                .iter()
                .filter(|row| row.entry_point.id == entry_point.id)
                .map(|row| row.case)
                .collect();
            let expected: BTreeSet<MatrixCaseKind> = MatrixCaseKind::ALL.iter().copied().collect();
            assert_eq!(
                cases_for_entry, expected,
                "entry point {} is missing required case coverage",
                entry_point.id
            );
        }

        let pairs: BTreeSet<(&str, MatrixCaseKind)> = rows
            .iter()
            .map(|row| (row.entry_point.id, row.case))
            .collect();
        assert_eq!(
            pairs.len(),
            rows.len(),
            "generated matrix contains a duplicate (entry point, case) pair"
        );
    }

    /// Stability: the generator is deterministic — repeated calls and
    /// independent iteration produce byte-for-byte identical row sequences,
    /// so downstream generated test names/order never drift between runs.
    #[test]
    fn stability_is_deterministic_across_calls() {
        let first = generated_acceptance_matrix();
        let second = generated_acceptance_matrix();
        assert_eq!(first, second);

        let ids_first: Vec<&str> = first.iter().map(|row| row.entry_point.id).collect();
        let ids_second: Vec<&str> = second.iter().map(|row| row.entry_point.id).collect();
        assert_eq!(ids_first, ids_second);
    }

    /// Visibility: the declaration surface the matrix exposes to the
    /// harness is bounded to exactly the six contract-specified entry
    /// points and no others — nothing declared elsewhere leaks in, and
    /// nothing declared here is silently dropped from the generated matrix.
    #[test]
    fn visibility_exposes_exactly_the_declared_entry_points() {
        let rows = generated_acceptance_matrix();
        let visible_ids: BTreeSet<&str> = rows.iter().map(|row| row.entry_point.id).collect();
        let expected_ids: BTreeSet<&str> = [
            "entity.create",
            "entity.update",
            "entity.bulk",
            "note.create",
            "note.update",
            "note.atomic_message",
        ]
        .into_iter()
        .collect();
        assert_eq!(visible_ids, expected_ids);
    }
}