dreamwell-engine 1.0.0

Dreamwell pure-logic engine library — transforms, hierarchy, canon pipeline, spatial math, hashing, tile rules, validation, waymark schema, material/lighting descriptors. No SpacetimeDB dependency.
Documentation
//! Event envelope types for the canon pipeline.
//!
//! `CanonEnvelope` wraps an event payload with metadata required
//! for deterministic event ordering and hash chain verification.

use crate::ids::{ActorId, EventId, ScopeKey};
use serde::{Deserialize, Serialize};

/// Canon event envelope — wraps a payload with deterministic metadata.
/// The hash chain links each event to its predecessor for tamper detection.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CanonEnvelope<E> {
    /// Unique event identifier.
    pub event_id: EventId,
    /// Actor who caused the event.
    pub actor_id: ActorId,
    /// Partition scope.
    pub scope_key: ScopeKey,
    /// Deterministic tick when event occurred.
    pub tick: u64,
    /// The event payload.
    pub payload: E,
    /// Hash of the previous event in the chain.
    pub hash_prev: u64,
    /// Hash of this event (computed from all fields above).
    pub hash_self: u64,
}

/// Trait for types that can be deterministically hashed for the canon pipeline.
pub trait CanonHashable {
    /// Write deterministic bytes for hashing. Must be stable across versions.
    fn canon_bytes(&self, out: &mut Vec<u8>);
}

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

    #[test]
    fn envelope_construction() {
        let env = CanonEnvelope {
            event_id: EventId(1),
            actor_id: ActorId(42),
            scope_key: ScopeKey(100),
            tick: 500,
            payload: "test_event".to_string(),
            hash_prev: 0,
            hash_self: 12345,
        };
        assert_eq!(env.event_id, EventId(1));
        assert_eq!(env.tick, 500);
    }

    #[test]
    fn serde_roundtrip() {
        let env = CanonEnvelope {
            event_id: EventId(1),
            actor_id: ActorId(2),
            scope_key: ScopeKey(3),
            tick: 4,
            payload: 42u64,
            hash_prev: 5,
            hash_self: 6,
        };
        let json = serde_json::to_string(&env).unwrap();
        let back: CanonEnvelope<u64> = serde_json::from_str(&json).unwrap();
        assert_eq!(env, back);
    }
}