pub struct EventLog { /* private fields */ }Expand description
An append-only event log backed by a JSONL file.
Implementations§
Source§impl EventLog
impl EventLog
Sourcepub fn open(session_dir: &Path) -> Result<Self, EventLogError>
pub fn open(session_dir: &Path) -> Result<Self, EventLogError>
Open or create an event log for the given session directory.
The session directory is typically .treeship/sessions/<session_id>/.
If the directory does not exist, it will be created.
Initialization reads the counter sidecar in O(1) when present and consistent with events.jsonl’s byte size; falls back to an O(N) line count (and rewrites the sidecar) when the sidecar is missing, short-read, or stale from a crashed previous appender.
Sourcepub fn append(&self, event: &mut SessionEvent) -> Result<(), EventLogError>
pub fn append(&self, event: &mut SessionEvent) -> Result<(), EventLogError>
Append a single event to the log.
The event’s sequence_no is set automatically. Under contention from
multiple writer processes, the sequence number is re-derived from the
on-disk line count under an exclusive flock so two parallel writers
never collide.
Sourcepub fn read_all(&self) -> Result<Vec<SessionEvent>, EventLogError>
pub fn read_all(&self) -> Result<Vec<SessionEvent>, EventLogError>
Read all events from the log.
Per-line tolerant: a single malformed line (unknown event type, missing required field, truncated JSON from a crashed writer) is logged to stderr and skipped, not propagated as an error. The caller – session close, in particular – composes a receipt from whatever events parse, instead of dropping every event when any one is bad.
Why this matters: events.jsonl is append-only and written by
hooks, daemons, SDKs, and bridges from multiple processes. A
single bad event from one buggy emitter would otherwise nuke
the entire receipt’s side_effects / agent_graph / timeline.
Real-world repro: a hook that emitted events with an unknown
type field caused side_effects.files_written to come back
empty even though the rest of the events in the log were valid
agent.wrote_file events the aggregator would have happily
processed.
Sourcepub fn read_all_with_stats(
&self,
) -> Result<(Vec<SessionEvent>, usize), EventLogError>
pub fn read_all_with_stats( &self, ) -> Result<(Vec<SessionEvent>, usize), EventLogError>
Same as read_all but returns the count of malformed lines that
were skipped during parsing alongside the valid events.
Codex adversarial review finding #8: skipping malformed events on stderr only is silent data loss from the verifier’s perspective. The receipt gets sealed under a merkle root that represents only the events that successfully parsed – a downstream consumer cannot tell whether the receipt is complete or whether N events were silently dropped.
session::close calls this and stores the count on
receipt.proofs.event_log_skipped. treeship package verify
surfaces it as a WARN when nonzero so the receipt’s
completeness signal is visible without breaking byte-identical
re-verification of pre-existing receipts.
Sourcepub fn event_count(&self) -> u64
pub fn event_count(&self) -> u64
Return the current event count.