//! cyber-conformance โ€” stability harness for the soft3 stack.
//!
//! See `specs/README.md` for the full specification and `docs/README.md`
//! for the design rationale.
//!
//! Scaffold: trait surface drafted, hemera dependency stubbed until the
//! hemera crate reaches stable output. Snapshot file I/O and the
//! `cargo conformance` subcommand land in subsequent crates.

#![forbid(unsafe_code)]
#![warn(missing_docs)]

// ---------------------------------------------------------------------------
// Fingerprint
// ---------------------------------------------------------------------------

/// 32-byte hemera fingerprint of canonical bytes.
///
/// This is the only thing a snapshot ever stores. Equality of two
/// [`Fingerprint`] values implies equality of the underlying canonical
/// encoding to within hemera's 256-bit collision resistance.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Fingerprint(pub [u8; 32]);

impl Fingerprint {
    /// Hex-encoded form used inside `.snap` files: `h{64 hex chars}`.
    pub fn to_snap_string(self) -> String {
        let mut s = String::with_capacity(65);
        s.push('h');
        for b in self.0 {
            s.push_str(&format!("{:02x}", b));
        }
        s
    }
}

// ---------------------------------------------------------------------------
// Tier
// ---------------------------------------------------------------------------

/// Stability tier โ€” determines the ceremony required to move a snapshot.
///
/// Promotion is one-way. Demotion requires the same ceremony as breaking
/// a snapshot at the target tier.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Tier {
    /// freely mutable; snapshot regenerates silently
    Alpha,
    /// tracked; drift logs to CI but does not fail
    Beta,
    /// enforced; drift fails CI; bless requires explicit flag
    Gamma,
    /// locked; bless requires `[conformance:delta]` commit tag
    Delta,
    /// governed; bless requires detached signature appended to the .snap file
    Epsilon,
}

impl Tier {
    /// Whether drift at this tier should fail CI.
    pub const fn enforces(self) -> bool {
        matches!(self, Self::Gamma | Self::Delta | Self::Epsilon)
    }

    /// Whether mutation at this tier requires governance signature.
    pub const fn governed(self) -> bool {
        matches!(self, Self::Epsilon)
    }
}

// ---------------------------------------------------------------------------
// Conformant
// ---------------------------------------------------------------------------

/// A type whose canonical encoding has a stable fingerprint.
///
/// Implementing this trait is a commitment: the canonical encoding of any
/// representative instance hashes to the same fingerprint across versions
/// until a tier-appropriate bless ceremony occurs.
pub trait Conformant {
    /// Stability tier of this type's encoding.
    const TIER: Tier;

    /// Stable identifier โ€” `crate::path::Type@vN`.
    ///
    /// The `@vN` suffix permits parallel encodings during migration:
    /// `Share@v1` and `Share@v2` can coexist in the snapshot file
    /// while readers transition.
    const NAME: &'static str;

    /// Canonical encoding of `self`.
    ///
    /// Two values that are equal under domain equality must produce
    /// byte-identical encodings. The encoding must not depend on
    /// iteration order, system time, or any other source of nondeterminism.
    fn canonical_encoding(&self) -> Vec<u8>;

    /// Fingerprint = hemera over canonical_encoding.
    ///
    /// Default implementation is the one true definition; do not override.
    fn fingerprint(&self) -> Fingerprint {
        Fingerprint(hemera_hash(&self.canonical_encoding()))
    }

    /// One representative instance whose fingerprint anchors the snapshot.
    fn snapshot_instance() -> Self
    where
        Self: Sized;
}

// ---------------------------------------------------------------------------
// Snapshot records
// ---------------------------------------------------------------------------

/// One line in `conformance/encoding.snap`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EncodingSnapshot {
    /// stable identifier โ€” `crate::path::Type@vN`
    pub name: String,
    /// tier as of the last bless
    pub tier: Tier,
    /// hemera fingerprint of canonical_encoding(snapshot_instance())
    pub fingerprint: Fingerprint,
}

/// One line in `conformance/mechanism.snap`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MechanismSnapshot {
    /// stable identifier โ€” `crate::path::mechanism@vN`
    pub mechanism: String,
    /// scenario lookup key โ€” names a fixed input for the mechanism
    pub scenario: String,
    /// tier as of the last bless
    pub tier: Tier,
    /// hemera fingerprint of the nox trace output for this scenario
    pub fingerprint: Fingerprint,
}

// ---------------------------------------------------------------------------
// Manifest
// ---------------------------------------------------------------------------

/// Union of every conformance snapshot across a workspace.
///
/// The manifest's own fingerprint is the protocol stability root for a
/// given git revision. A zheng proof can be produced over this root,
/// attesting that the protocol revision conforms to manifest M without a
/// verifier re-running the harness.
#[derive(Debug, Clone, Default)]
pub struct Manifest {
    /// every encoding snapshot in the workspace
    pub encodings: Vec<EncodingSnapshot>,
    /// every mechanism snapshot in the workspace
    pub mechanisms: Vec<MechanismSnapshot>,
}

impl Manifest {
    /// hemera fingerprint of the canonical ordering of all snapshots.
    ///
    /// Canonical ordering: sort encodings by `name`, mechanisms by
    /// `(mechanism, scenario)`, concatenate canonical encodings, hash.
    pub fn root(&self) -> Fingerprint {
        let mut buf: Vec<u8> = Vec::new();
        let mut encs = self.encodings.clone();
        encs.sort_by(|a, b| a.name.cmp(&b.name));
        for e in &encs {
            buf.extend_from_slice(e.name.as_bytes());
            buf.push(0);
            buf.push(e.tier as u8);
            buf.extend_from_slice(&e.fingerprint.0);
        }
        let mut mechs = self.mechanisms.clone();
        mechs.sort_by(|a, b| {
            a.mechanism
                .cmp(&b.mechanism)
                .then_with(|| a.scenario.cmp(&b.scenario))
        });
        for m in &mechs {
            buf.extend_from_slice(m.mechanism.as_bytes());
            buf.push(0);
            buf.extend_from_slice(m.scenario.as_bytes());
            buf.push(0);
            buf.push(m.tier as u8);
            buf.extend_from_slice(&m.fingerprint.0);
        }
        Fingerprint(hemera_hash(&buf))
    }
}

// ---------------------------------------------------------------------------
// hemera bridge
// ---------------------------------------------------------------------------

/// Placeholder for the cyber-hemera dependency.
///
/// Replace with `cyber_hemera::hash(bytes).into()` once hemera output
/// reaches the stable release. The signature stays identical.
fn hemera_hash(_bytes: &[u8]) -> [u8; 32] {
    [0u8; 32]
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

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

    struct Example {
        n: u64,
    }

    impl Conformant for Example {
        const TIER: Tier = Tier::Alpha;
        const NAME: &'static str = "cyber_conformance::tests::Example@v1";

        fn canonical_encoding(&self) -> Vec<u8> {
            self.n.to_le_bytes().to_vec()
        }

        fn snapshot_instance() -> Self {
            Example { n: 42 }
        }
    }

    #[test]
    fn fingerprint_is_deterministic() {
        let a = Example::snapshot_instance().fingerprint();
        let b = Example::snapshot_instance().fingerprint();
        assert_eq!(a, b);
    }

    #[test]
    fn tier_enforcement_policy() {
        assert!(!Tier::Alpha.enforces());
        assert!(!Tier::Beta.enforces());
        assert!(Tier::Gamma.enforces());
        assert!(Tier::Delta.enforces());
        assert!(Tier::Epsilon.enforces());
        assert!(Tier::Epsilon.governed());
        assert!(!Tier::Delta.governed());
    }

    #[test]
    fn manifest_root_is_deterministic() {
        let m = Manifest {
            encodings: vec![EncodingSnapshot {
                name: "x".into(),
                tier: Tier::Gamma,
                fingerprint: Fingerprint([1u8; 32]),
            }],
            mechanisms: vec![],
        };
        assert_eq!(m.root(), m.root());
    }
}

Homonyms

soft3/mir/src/lib.rs
soft3/strata/src/lib.rs
soft3/lens/src/lib.rs
soft3/crate/src/lib.rs
cyb/prysm/rs/lib.rs
cyb/honeycrisp/src/lib.rs
soft3/mudra/src/lib.rs
soft3/cybergraph/src/lib.rs
warriors/trisha/wgpu/lib.rs
soft3/glia/run/lib.rs
soft3/nox/rs/lib.rs
warriors/trisha/rs/lib.rs
soft3/tru/rs/lib.rs
cyb/optica/src/lib.rs
warriors/trisha/honeycrisp/lib.rs
soft3/foculus/src/lib.rs
cyb/core/src/lib.rs
soft3/glia/import/lib.rs
cyb/shell/src/lib.rs
neural/trident/src/lib.rs
neural/rune/rs/ast/lib.rs
cyb/crates/cyb/src/lib.rs
neural/rs/dialect/src/lib.rs
neural/rune/rs/compile/lib.rs
neural/rs/link/src/lib.rs
neural/rune/rs/lex/lib.rs
soft3/hemera/rs/src/lib.rs
soft3/radio/iroh/src/lib.rs
soft3/lens/core/src/lib.rs
cyb/honeycrisp/unimem/src/lib.rs
soft3/radio/iroh-ffi/src/lib.rs
soft3/lens/brakedown/src/lib.rs
soft3/lens/binius/src/lib.rs
neural/rune/rs/interp/lib.rs
soft3/radio/iroh-blobs/src/lib.rs
neural/rune/rs/parse/lib.rs
neural/rune/rs/mold/lib.rs
neural/rune/rs/subject/lib.rs
soft3/strata/proof/src/lib.rs
soft3/lens/ikat/src/lib.rs
soft3/radio/iroh-docs/src/lib.rs
soft3/radio/cyber-bao/src/lib.rs
cyb/honeycrisp/acpu/src/lib.rs
neural/eidos/rs/src/lib.rs
soft3/hemera/wgsl/src/lib.rs
soft3/lens/porphyry/src/lib.rs
neural/rs/macros/src/lib.rs
soft3/bbg/rs/src/lib.rs
cyb/honeycrisp/rane/src/lib.rs
soft3/radio/iroh-base/src/lib.rs
neural/rune/rs/parse-pure/lib.rs
neural/rs/mir-format/src/lib.rs
soft3/zheng/rs/src/lib.rs
soft3/lens/assayer/src/lib.rs
neural/rune/rs/prysm/lib.rs
soft3/strata/compute/src/lib.rs
soft3/tok/rs/src/lib.rs
soft3/strata/nebu/rs/lib.rs
soft3/radio/iroh-dns-server/src/lib.rs
cyb/honeycrisp/aruminium/src/lib.rs
soft3/strata/kuro/rs/lib.rs
soft3/radio/iroh-car/src/lib.rs
soft3/radio/iroh-gossip/src/lib.rs
soft3/radio/iroh-willow/src/lib.rs
soft3/strata/ext/src/lib.rs
neural/rs/sigil/src/lib.rs
neural/rs/core/src/lib.rs
cyb/crates/cyb-reserve/src/lib.rs
soft3/radio/iroh-relay/src/lib.rs
neural/rs/darwin-sys/src/lib.rs
soft3/strata/core/src/lib.rs
neural/rs/codegen/src/lib.rs
neural/rune/rs/lower/lib.rs
cyb/wysm/crates/wasmi/src/lib.rs
soft3/radio/quinn/quinn/src/lib.rs
soft3/radio/quinn/quinn-proto/src/lib.rs
cyb/evy/forks/bevy_mesh/src/lib.rs
cyb/evy/crates/evy_diagnostic/src/lib.rs
cyb/evy/forks/bevy_anti_alias/src/lib.rs
neural/inf/rs/parse/src/lib.rs
neural/inf/rs/ast/src/lib.rs
cyb/evy/forks/bevy_post_process/src/lib.rs
soft3/radio/nettools/netwatch/src/lib.rs
neural/inf/rs/plan/src/lib.rs
cyb/evy/crates/evy_ecs_storage/src/lib.rs
soft3/strata/jali/rs/src/lib.rs
cyb/evy/crates/evy_engine_core/src/lib.rs
cyb/wysm/crates/collections/src/lib.rs
neural/inf/rs/oracle/src/lib.rs
cyb/evy/forks/bevy_sprite_render/src/lib.rs
cyb/wysm/crates/wast/src/lib.rs
cyb/evy/crates/evy_prysm_core/src/lib.rs
soft3/radio/quinn/quinn-udp/src/lib.rs
soft3/strata/kuro/wgsl/src/lib.rs
cyb/evy/forks/bevy_sprite/src/lib.rs
soft3/lytics/rs/core/src/lib.rs
cyb/wysm/crates/c_api/macro/lib.rs
cyb/evy/forks/bevy_gizmos/src/lib.rs
soft3/strata/nebu/wgsl/src/lib.rs
soft3/radio/nettools/portmapper/src/lib.rs
cyb/evy/forks/bevy_gizmos_render/src/lib.rs
cyb/evy/forks/bevy_transform/src/lib.rs
cyb/wysm/crates/wasi/src/lib.rs
soft3/radio/tests/integration/src/lib.rs
neural/trident/editor/zed/src/lib.rs
cyb/evy/forks/bevy_core_pipeline/src/lib.rs
cyb/evy/forks/bevy_pbr/src/lib.rs
cyb/evy/crates/evy_engine_dispatch/src/lib.rs
soft3/lytics/rs/event/src/lib.rs
cyb/evy/forks/bevy_ecs/src/lib.rs
cyb/evy/forks/bevy_diagnostic/src/lib.rs
neural/inf/rs/lex/src/lib.rs
neural/inf/rs/eval/src/lib.rs
cyb/evy/forks/naga/src/lib.rs
cyb/evy/crates/evy_platform_caps/src/lib.rs
soft3/strata/trop/wgsl/src/lib.rs
cyb/wysm/crates/core/src/lib.rs
cyb/wysm/crates/c_api/artifact/lib.rs
cyb/wysm/crates/fuzz/src/lib.rs
cyb/evy/forks/bevy_animation/src/lib.rs
soft3/strata/genies/wgsl/src/lib.rs
soft3/radio/quinn/bench/src/lib.rs
cyb/evy/crates/evy_dialect/src/lib.rs
soft3/tape/impl/rust/src/lib.rs
soft3/strata/trop/rs/src/lib.rs
cyb/evy/crates/evy_engine_tasks/src/lib.rs
neural/rs/tests/macro-integration/src/lib.rs
soft3/radio/quinn/perf/src/lib.rs
soft3/strata/genies/rs/src/lib.rs
cyb/evy/crates/evy_radio/src/lib.rs
soft3/radio/iroh/bench/src/lib.rs
cyb/wysm/crates/c_api/src/lib.rs
cyb/evy/forks/bevy_tasks/src/lib.rs
cyb/evy/forks/bevy_render/src/lib.rs
cyb/wysm/crates/ir/src/lib.rs
neural/inf/rs/source/src/lib.rs
soft3/radio/iroh-ffi/iroh-js/src/lib.rs
soft3/strata/jali/wgsl/src/lib.rs
neural/inf/rs/value/src/lib.rs
cyb/evy/forks/bevy_image/src/lib.rs
neural/inf/rs/lower/src/lib.rs
bootloader/go-cyber/cw/contracts/graph-filter/src/lib.rs
bootloader/go-cyber/cw/packages/cyber-std-test/src/lib.rs
bootloader/go-cyber/cw/contracts/std-test/src/lib.rs
bootloader/go-cyber/cw/packages/cyber-std/src/lib.rs

Graph