wasm4pm 26.6.10

High-performance process mining algorithms in WebAssembly for JavaScript/TypeScript
Documentation
// Auto-generated by ggen from wasm4pm-compat.ttl --- DO NOT EDIT
// Graduation surface: Replay Authority
// Regenerate with: ggen sync --template wasm4pm-replay.tera

//! Process Replay Authority Module
//!
//! This module is the wasm4pm graduation surface for token-based simulation,
//! path finding, and execution profiling. It wraps the structure-only witness
//! markers from `wasm4pm_compat` with actual replay and simulation implementations.
//!
//! # What this IS
//!
//! - A container for token replay engines (step-wise execution, parallel paths, etc.)
//! - Token carrier for [`crate::evidence::Evidence<T, State, ReplayWitness>`]
//! - The graduation boundary where replay and simulation logic executes
//! - A zero-unsafe-code zone (forbid unsafe)
//!
//! # What this is NOT
//!
//! - Not a type-only namespace (actual replay logic lives here)
//! - Not a witness marker (those stay in wasm4pm-compat)
//! - Not a conformance checker (fitness checks go to conformance module)
//!
//! # Graduation Condition
//!
//! A process form graduates to this module when:
//! 1. Its wasm4pm-compat witness is structurally valid
//! 2. A concrete replay algorithm is ready to implement
//! 3. The algorithm can work with [`Evidence`] carriers and produce execution traces

use std::marker::PhantomData;

/// Replay authority marker — carries replay and simulation semantics.
///
/// All replay operations are bound to a replay witness, which names
/// the replay algorithm (token replay, simulation, path finding) and its
/// foundational model.
#[derive(Debug, Clone, Copy)]
pub struct ReplayAuthority {
    _phantom: PhantomData<()>,
}

impl ReplayAuthority {
    /// Create a replay authority.
    pub const fn new() -> Self {
        ReplayAuthority {
            _phantom: PhantomData,
        }
    }

    /// The witness this authority is bound to.
    pub const fn witness_key() -> &'static str {
        "wasm4pm-replay"
    }
}

impl Default for ReplayAuthority {
    fn default() -> Self {
        Self::new()
    }
}

/// Replay engine trait.
///
/// Implement this trait for each concrete replay algorithm.
/// The algorithm executes token-based replay, simulation, and path-finding
/// operations on process models and event logs.
pub trait ReplayEngine<M> {
    /// Replay a process model against event log evidence.
    ///
    /// # Arguments
    ///
    /// - `_model`: the process model to replay against
    /// - `log_events`: event sequence to replay
    ///
    /// # Returns
    ///
    /// Execution trace with replay results.
    fn replay(&self, _model: &M, log_events: &[LogEvent]) -> ReplayTrace;
}

/// Event in a process log.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogEvent {
    /// Activity name
    pub activity: String,
    /// Event timestamp
    pub timestamp: u64,
    /// Optional case/object ID
    pub case_id: Option<String>,
}

impl LogEvent {
    /// Create a new log event.
    pub fn new(activity: String, timestamp: u64) -> Self {
        LogEvent {
            activity,
            timestamp,
            case_id: None,
        }
    }

    /// Set the case/object ID for this event.
    pub fn with_case_id(mut self, case_id: String) -> Self {
        self.case_id = Some(case_id);
        self
    }
}

/// Replay execution trace.
///
/// Records the step-by-step execution of a process model during replay,
/// including which transitions fired, which paths were taken, and where
/// deviations occurred.
#[derive(Debug, Clone)]
pub struct ReplayTrace {
    /// Sequence of fired transitions
    pub transitions: Vec<String>,
    /// Number of successful steps
    pub successful_steps: usize,
    /// Number of missed activities
    pub missed_activities: usize,
    /// Number of remaining tokens
    pub remaining_tokens: usize,
    /// Execution log
    pub log: Vec<String>,
}

impl ReplayTrace {
    /// Create a new replay trace.
    pub fn new() -> Self {
        ReplayTrace {
            transitions: Vec::new(),
            successful_steps: 0,
            missed_activities: 0,
            remaining_tokens: 0,
            log: Vec::new(),
        }
    }

    /// Check if replay was successful (no missed activities, no remaining tokens).
    pub fn is_successful(&self) -> bool {
        self.missed_activities == 0 && self.remaining_tokens == 0
    }

    /// Record a fired transition.
    pub fn fire_transition(&mut self, transition: String) {
        self.transitions.push(transition);
        self.successful_steps += 1;
    }

    /// Record a missed activity.
    pub fn miss_activity(&mut self, activity: String) {
        self.missed_activities += 1;
        self.log.push(format!("Missed activity: {}", activity));
    }
}

impl Default for ReplayTrace {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn replay_authority_construction() {
        let _auth = ReplayAuthority::new();
        assert_eq!(ReplayAuthority::witness_key(), "wasm4pm-replay");
    }

    #[test]
    fn replay_authority_default() {
        let _auth = ReplayAuthority::default();
        assert_eq!(ReplayAuthority::witness_key(), "wasm4pm-replay");
    }

    #[test]
    fn log_event_creation() {
        let event = LogEvent::new("submit".to_string(), 1000);
        assert_eq!(event.activity, "submit");
        assert_eq!(event.timestamp, 1000);
        assert_eq!(event.case_id, None);
    }

    #[test]
    fn log_event_with_case_id() {
        let event = LogEvent::new("submit".to_string(), 1000).with_case_id("case-001".to_string());
        assert_eq!(event.case_id, Some("case-001".to_string()));
    }

    #[test]
    fn replay_trace_creation() {
        let trace = ReplayTrace::new();
        assert!(trace.is_successful());
        assert_eq!(trace.successful_steps, 0);
    }

    #[test]
    fn replay_trace_with_deviation() {
        let mut trace = ReplayTrace::new();
        trace.fire_transition("t1".to_string());
        trace.miss_activity("submit".to_string());
        assert!(!trace.is_successful());
        assert_eq!(trace.successful_steps, 1);
        assert_eq!(trace.missed_activities, 1);
    }

    #[test]
    fn replay_trace_default() {
        let trace = ReplayTrace::default();
        assert!(trace.is_successful());
        assert_eq!(trace.missed_activities, 0);
        assert_eq!(trace.remaining_tokens, 0);
    }
}