moonreplaykit

    Deterministic state-machine replay, checkpoint validation and divergence diagnostics for MoonBit.

    deterministic-replay
    event-journal
    state-machine
    divergence
    checkpoint
    Download zip
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    4 months ago
    Downloads
    43

    No dependencies

    #MoonReplayKit

    Deterministic state-machine replay, checkpoint validation, branch comparison, divergence diagnostics, and portable replay evidence for MoonBit.

    #Highlights

    • Generic append-only hash-linked journals and deterministic reducers.
    • Full replay and checkpoint resume with state and journal anchors.
    • Branch and reducer-version divergence diagnostics.
    • Invariant failure localization and shortest reproducing prefixes.
    • Merkle-style evidence roots over event and transition-state fingerprints.
    • Logarithmic inclusion proofs that verify without the full state history.
    • First evidence divergence lookup for equal-length replay trees.
    • Backend-neutral core with no I/O, clock, randomness, or third-party runtime.

    #Evidence Example

    let report = @moonreplaykit.replay(
    journal,
    initial_state,
    payload_fingerprint,
    state_fingerprint,
    reducer,
    )

    let tree = @moonreplaykit.build_replay_evidence(
    journal,
    report,
    payload_fingerprint,
    ).unwrap()

    let proof = @moonreplaykit.replay_inclusion_proof(
    journal,
    report,
    tree,
    sequence,
    ).unwrap()

    assert_true(@moonreplaykit.verify_replay_inclusion(proof))

    The built-in fingerprint is deterministic and intended for replay integrity, comparison, and regression evidence. It is not a cryptographic signature.

    See the repository README and docs/ for design rationale and full examples.

    ChainIssue

    pub(all) enum ChainIssue {
    UnexpectedSequence(Int, Int, Int)
    BrokenPreviousHash(Int, Int, Int)
    InvalidEventHash(Int, Int, Int)
    } derive(Eq,
    Debug
    )

    Why a journal failed structural validation.

    ChainValidation

    pub(all) enum ChainValidation {
    Valid(Int, Int)
    Invalid(ChainIssue)
    } derive(Eq,
    Debug
    )

    Structural validation result for an event journal.

    Checkpoint

    pub(all) struct Checkpoint[S] {
    sequence : Int
    state : S
    state_hash : Int
    journal_hash : Int
    }

    A state snapshot anchored to a verified journal boundary.

    Divergence

    pub(all) struct Divergence {
    sequence : Int
    kind : DivergenceKind
    left_hash : Int
    right_hash : Int
    message : String
    } derive(Eq,
    Debug
    )

    A stable, serializable explanation of a replay divergence.

    DivergenceKind

    pub(all) enum DivergenceKind {
    StateMismatch
    StatusMismatch
    LengthMismatch
    EventMismatch
    } derive(Eq,
    Debug
    )

    The first point where two executions no longer agree.

    InvariantResult

    pub(all) enum InvariantResult {
    Holds(Int)
    Violated(Int, Int, String)
    ReplayFailed(ReplayStatus)
    } derive(Eq,
    Debug
    )

    Result of checking an invariant over every replayed prefix.

    Journal

    pub struct Journal[P] {
    records : Array[JournalEvent[P]]
    }

    In-memory append-only journal.

    Persistence adapters can reconstruct a journal with from_events and then call validate before allowing replay.

    Journal::append

    fn[P] Journal::append(self : Journal[P], kind : String, payload : P, correlation_id : String, payload_fingerprint : (P) -> String) -> JournalEvent[P]

    Appends one event and returns its complete journal record.

    Journal::events

    fn[P] Journal::events(self : Journal[P]) -> Array[JournalEvent[P]]

    Returns a copy suitable for persistence or diagnostics.

    Journal::from_events

    fn[P] Journal::from_events(events : Array[JournalEvent[P]]) -> Journal[P]

    Reconstructs a journal from externally loaded events.

    The caller must validate the returned journal before replay.

    Journal::get

    fn[P] Journal::get(self : Journal[P], index : Int) -> JournalEvent[P]?

    Returns an event by zero-based index.

    Journal::hash_at

    fn[P] Journal::hash_at(self : Journal[P], sequence : Int) -> Int?

    Returns the hash-chain anchor at a sequence boundary.

    Journal::length

    fn[P] Journal::length(self : Journal[P]) -> Int

    Returns the number of events in the journal.

    Journal::new

    fn[P] Journal::new() -> Journal[P]

    Creates an empty event journal.

    Journal::prefix

    fn[P] Journal::prefix(self : Journal[P], count : Int) -> Journal[P]

    Returns a journal containing the first count events.

    The returned journal preserves the original hash evidence and should still be validated before replay.

    Journal::tail_hash

    fn[P] Journal::tail_hash(self : Journal[P]) -> Int

    Returns the current hash-chain tail, or zero for an empty journal.

    Journal::validate

    fn[P] Journal::validate(self : Journal[P], payload_fingerprint : (P) -> String) -> ChainValidation

    Validates sequence continuity and the complete event hash chain.

    JournalEvent

    pub(all) struct JournalEvent[P] {
    sequence : Int
    kind : String
    payload : P
    correlation_id : String
    previous_hash : Int
    hash : Int
    }

    A journal event together with the evidence required to verify its position.

    MigrationReport

    pub(all) struct MigrationReport[S] {
    compatible : Bool
    old_report : ReplayReport[S]
    new_report : ReplayReport[S]
    first_divergence : Divergence?
    }

    Result of comparing two reducer versions against the same journal.

    ReplayBranch

    pub struct ReplayBranch[P] {
    name : String
    base_sequence : Int
    journal : Journal[P]
    }

    A named alternative history forked from a journal boundary.

    ReplayBranch::append

    fn[P] ReplayBranch::append(self : ReplayBranch[P], kind : String, payload : P, correlation_id : String, payload_fingerprint : (P) -> String) -> JournalEvent[P]

    Appends one event to the alternative history.

    ReplayBranch::base_sequence

    fn[P] ReplayBranch::base_sequence(self : ReplayBranch[P]) -> Int

    Returns the source sequence where the branch was created.

    ReplayBranch::fork

    fn[P] ReplayBranch::fork(name : String, source : Journal[P], sequence : Int, payload_fingerprint : (P) -> String) -> ReplayBranch[P]?

    Forks a branch from the first sequence events of a source journal.

    Returns None when the source is invalid or the boundary is out of range.

    ReplayBranch::journal

    fn[P] ReplayBranch::journal(self : ReplayBranch[P]) -> Journal[P]

    Returns a copy of the branch journal.

    ReplayBranch::name

    fn[P] ReplayBranch::name(self : ReplayBranch[P]) -> String

    Returns the branch name.

    ReplayEvidenceTree

    pub(all) struct ReplayEvidenceTree {
    event_count : Int
    root : Int
    levels : Array[Array[Int]]
    } derive(Eq,
    Debug
    )

    Merkle-style deterministic commitment over event and state evidence.

    This is an integrity and comparison structure, not a cryptographic signature.

    ReplayInclusionProof

    pub(all) struct ReplayInclusionProof {
    sequence : Int
    event_hash : Int
    state_hash : Int
    leaf_hash : Int
    siblings : Array[Int]
    sibling_on_left : Array[Bool]
    root : Int
    } derive(Eq,
    Debug
    )

    Portable logarithmic proof that one transition belongs to an evidence root.

    ReplayReport

    pub(all) struct ReplayReport[S] {
    status : ReplayStatus
    initial_sequence : Int
    applied_events : Int
    final_sequence : Int
    final_state : S
    final_state_hash : Int
    journal_tail_hash : Int
    state_hashes : Array[Int]
    }

    Evidence produced by a replay.

    ReplayStatus

    pub(all) enum ReplayStatus {
    Completed
    Rejected(Int, String)
    InvalidJournal(ChainIssue)
    InvalidCheckpoint(String)
    } derive(Eq,
    Debug
    )

    Replay completion status.

    Transition

    pub(all) enum Transition[S] {
    Accepted(S)
    Rejected(String)
    }

    The result of applying one event to an application state.

    build_replay_evidence

    fn[P, S] build_replay_evidence(journal : Journal[P], report : ReplayReport[S], payload_fingerprint : (P) -> String) -> ReplayEvidenceTree?

    Builds a deterministic commitment over every event and resulting state.

    The journal chain, replay boundary, state evidence length, and tail anchor must all agree. Invalid or partial reports return None.

    checkpoint_from_report

    fn[S] checkpoint_from_report(report : ReplayReport[S]) -> Checkpoint[S]?

    Creates a checkpoint from the final verified boundary of a replay report.

    compare_histories

    fn[P] compare_histories(left : Journal[P], right : Journal[P], payload_fingerprint : (P) -> String) -> Divergence?

    Locates the first structural difference between two event histories.

    compare_reducer_versions

    fn[P, S] compare_reducer_versions(journal : Journal[P], initial_state : S, payload_fingerprint : (P) -> String, state_fingerprint : (S) -> String, old_reducer : (S, JournalEvent[P]) -> Transition[S], new_reducer : (S, JournalEvent[P]) -> Transition[S]) -> MigrationReport[S]

    Replays one journal through old and new reducer versions.

    Compatibility means both versions completed and every state boundary has the same fingerprint.

    compare_reports

    fn[S] compare_reports(left : ReplayReport[S], right : ReplayReport[S]) -> Divergence?

    Compares the transition evidence from two replay reports.

    divergence_kind_name

    fn divergence_kind_name(kind : DivergenceKind) -> String

    Returns a stable machine-readable label for a divergence kind.

    event_fingerprint

    fn event_fingerprint(previous_hash : Int, sequence : Int, kind : String, correlation_id : String, payload_fingerprint : String) -> Int

    Combines journal metadata and an application-provided payload fingerprint.

    event_to_json

    fn[P] event_to_json(event : JournalEvent[P], payload_json : (P) -> String) -> String

    Encodes one journal event. payload_json must return a valid JSON value.

    events_by_correlation

    fn[P] events_by_correlation(journal : Journal[P], correlation_id : String) -> Array[JournalEvent[P]]

    Returns events carrying a given correlation identifier.

    events_by_kind

    fn[P] events_by_kind(journal : Journal[P], kind : String) -> Array[JournalEvent[P]]

    Returns events with an exact application event kind.

    events_in_range

    fn[P] events_in_range(journal : Journal[P], first_sequence : Int, last_sequence : Int) -> Array[JournalEvent[P]]

    Returns events in an inclusive sequence range.

    This is an investigation view, not a replayable journal. Original sequence and hash evidence remain attached to every returned event.

    find_first_invariant_failure

    fn[P, S] find_first_invariant_failure(journal : Journal[P], initial_state : S, payload_fingerprint : (P) -> String, state_fingerprint : (S) -> String, reducer : (S, JournalEvent[P]) -> Transition[S], invariant : (S) -> String?) -> InvariantResult

    Checks an invariant at the initial state and after every accepted event.

    The invariant returns None when the state is valid or a stable diagnostic message when it is violated. The first violation is therefore the shortest replay prefix that reproduces the failure.

    fingerprint_text

    fn fingerprint_text(text : String) -> Int

    Stable non-cryptographic fingerprint used for deterministic replay evidence.

    This function is deliberately identical on every MoonBit backend. It is intended for change detection and replay comparison, not for security.

    first_evidence_divergence

    fn first_evidence_divergence(left : ReplayEvidenceTree, right : ReplayEvidenceTree) -> Int?

    Locates the first differing one-based transition.

    Equal-length trees are searched by descending only into the first unequal subtree. A length mismatch returns the first missing transition boundary.

    journal_to_json

    fn[P] journal_to_json(journal : Journal[P], payload_json : (P) -> String) -> String

    Encodes a journal as a stable JSON array.

    json_escape

    fn json_escape(value : String) -> String

    Escapes a string for use as a JSON string value.

    minimal_failing_prefix

    fn[P, S] minimal_failing_prefix(journal : Journal[P], initial_state : S, payload_fingerprint : (P) -> String, state_fingerprint : (S) -> String, reducer : (S, JournalEvent[P]) -> Transition[S], invariant : (S) -> String?) -> Journal[P]?

    Returns the shortest journal prefix that reproduces an invariant failure.

    replay

    fn[P, S] replay(journal : Journal[P], initial_state : S, payload_fingerprint : (P) -> String, state_fingerprint : (S) -> String, reducer : (S, JournalEvent[P]) -> Transition[S]) -> ReplayReport[S]

    Replays a complete validated journal from an initial state.

    payload_fingerprint and state_fingerprint must be deterministic. reducer must not depend on time, randomness, I/O, or mutable global state.

    replay_evidence_to_json

    fn replay_evidence_to_json(tree : ReplayEvidenceTree) -> String

    Encodes the portable summary of a replay evidence tree.

    replay_from_checkpoint

    fn[P, S] replay_from_checkpoint(journal : Journal[P], checkpoint : Checkpoint[S], payload_fingerprint : (P) -> String, state_fingerprint : (S) -> String, reducer : (S, JournalEvent[P]) -> Transition[S]) -> ReplayReport[S]

    Continues a validated journal from an anchored checkpoint.

    replay_inclusion_proof

    fn[P, S] replay_inclusion_proof(journal : Journal[P], report : ReplayReport[S], tree : ReplayEvidenceTree, sequence : Int) -> ReplayInclusionProof?

    Creates an inclusion proof for a one-based event sequence.

    replay_inclusion_proof_to_json

    fn replay_inclusion_proof_to_json(proof : ReplayInclusionProof) -> String

    Encodes an inclusion proof without application state serialization.

    replay_report_to_json

    fn[S] replay_report_to_json(report : ReplayReport[S], state_json : (S) -> String) -> String

    Encodes the summary and final state of a replay report.

    state_json must return a valid JSON value.

    replay_status_name

    fn replay_status_name(status : ReplayStatus) -> String

    Returns a stable machine-readable label for a replay status.

    verify_determinism

    fn[P, S] verify_determinism(journal : Journal[P], initial_state : S, payload_fingerprint : (P) -> String, state_fingerprint : (S) -> String, reducer : (S, JournalEvent[P]) -> Transition[S]) -> Bool

    Runs the same replay twice and checks the complete transition evidence.

    This catches reducers that accidentally read time, randomness, or mutable ambient state even when their final states happen to match.

    verify_replay_inclusion

    fn verify_replay_inclusion(proof : ReplayInclusionProof) -> Bool

    Verifies a portable inclusion proof without the full journal or state list.