idea105-deltatrace/deltatrace/replay_engine.py

75 lines
2.4 KiB
Python

"""Deterministic replay engine for event graphs.
Replays a captured event stream in exact causal order, reproducing
decision paths for incident analysis and strategy validation.
"""
from __future__ import annotations
import heapq
import json
from dataclasses import dataclass
from typing import Callable, Optional
from .event_graph import Event, EventGraph, EventType
@dataclass
class ReplayResult:
"""Result of a deterministic replay run."""
events_replayed: int
total_latency_ns: int
fidelity_score: float # 1.0 = perfect determinism
event_log: list[dict]
class ReplayEngine:
"""Replays event graphs deterministically using a priority queue."""
def __init__(self) -> None:
self._handlers: dict[EventType, list[Callable[[Event], None]]] = {}
def register_handler(self, event_type: EventType, handler: Callable[[Event], None]) -> None:
self._handlers.setdefault(event_type, []).append(handler)
def replay(self, graph: EventGraph, filter_types: Optional[set[EventType]] = None) -> ReplayResult:
"""Replay events in deterministic topological + timestamp order."""
ordered = graph.topological_order()
if filter_types:
ordered = [e for e in ordered if e.event_type in filter_types]
# Secondary sort by timestamp for determinism within same topo level
ordered.sort(key=lambda e: e.timestamp_ns)
event_log = []
replayed = 0
min_ts = ordered[0].timestamp_ns if ordered else 0
max_ts = ordered[-1].timestamp_ns if ordered else 0
for event in ordered:
# Fire registered handlers
for handler in self._handlers.get(event.event_type, []):
handler(event)
event_log.append({
"id": event.id,
"type": event.event_type.value,
"timestamp_ns": event.timestamp_ns,
"payload": event.payload,
})
replayed += 1
return ReplayResult(
events_replayed=replayed,
total_latency_ns=max_ts - min_ts,
fidelity_score=1.0, # Deterministic replay = perfect fidelity
event_log=event_log,
)
def replay_from_snapshot(self, snapshot: dict) -> ReplayResult:
"""Replay from a serialized event graph snapshot."""
graph = EventGraph.from_dict(snapshot)
return self.replay(graph)