pub struct SessionEventLog { /* private fields */ }Implementations§
Source§impl SessionEventLog
impl SessionEventLog
Sourcepub async fn open(session_dir: &Path) -> Result<Self, SessionError>
pub async fn open(session_dir: &Path) -> Result<Self, SessionError>
Open (creating if absent) the events.jsonl log under session_dir.
Validates the existing file per INV-SP-2, dropping a torn trailing line from the
in-memory result, then opens the file in append mode for subsequent writes. Sets
file/directory permissions to 0o700/0o600 on Unix (spec §4.1); a no-op on other
platforms.
Does not take the cross-process advisory lock, and never physically truncates the file
(even if a torn tail is found) — safe for read-only tooling that may run alongside a live
writer whose in-flight, not-yet-fsynced line could otherwise be mistaken for “torn” and
destroyed (#5487 Finding B). The session’s owning actor/agent process should use
Self::open_exclusive instead, which does perform the physical repair.
§Errors
Returns SessionError::Io if the directory or file cannot be created, or
SessionError::Serde surfaces only via Self::read_all, never here (torn lines are
discarded, not treated as fatal).
Sourcepub async fn open_allow_unverified(
session_dir: &Path,
) -> Result<Self, SessionError>
pub async fn open_allow_unverified( session_dir: &Path, ) -> Result<Self, SessionError>
Open the events.jsonl log under session_dir like Self::open, but skip
hash-chain verification for this handle’s whole lifetime — see
Self::open_exclusive_allow_unverified’s doc for the full contract (this is its
lockless counterpart, for read-only tooling such as sessions resume --print --allow-unverified).
§Errors
Returns any error Self::open can return other than SessionError::Integrity
(which this method exists specifically to bypass).
Sourcepub async fn open_exclusive(session_dir: &Path) -> Result<Self, SessionError>
pub async fn open_exclusive(session_dir: &Path) -> Result<Self, SessionError>
Open the events.jsonl log under session_dir like Self::open, but additionally
take a non-blocking, exclusive advisory lock (flock(2) on Unix, mirroring
zeph-scheduler’s PidFile) enforcing INV-D2’s single-writer invariant.
Intended for the session’s owning actor/agent process. On non-Unix targets the lock
is a no-op (the workspace has no vetted cross-platform advisory-locking primitive), so
this degrades to Self::open’s behavior there.
§Errors
Returns SessionError::AlreadyLocked if another process already holds the session’s
write lock, or any error Self::open can return.
Sourcepub async fn open_exclusive_allow_unverified(
session_dir: &Path,
) -> Result<Self, SessionError>
pub async fn open_exclusive_allow_unverified( session_dir: &Path, ) -> Result<Self, SessionError>
Open the events.jsonl log under session_dir like Self::open_exclusive, but
skip hash-chain verification for this one open.
This is the deliberate, logged override an operator invokes explicitly (e.g. zeph sessions resume <id> --allow-unverified) after being shown a detected chain-integrity
failure — never a silent fallback. Per spec-069 FR-004’s fail-closed-by-default posture:
callers on an unattended path (durable resume, the crash-orphan sweep, automatic
sub-agent transcript reload) must never call this — only a human-attended path with an
explicit, deliberate opt-in may bypass verification. read_all/read_chunked on the
returned handle also skip chain verification (a dedicated allow_unverified flag carried
on Self, threaded through every subsequent read — not implemented by nulling the
key ring, which would instead re-trigger the normal “no key configured” fail-closed path
and make this override indistinguishable from a plain hard failure), so the whole session
is treated as best-effort-trusted, matching the legacy posture, for as long as this
handle is held.
Scope of the bypass: this skips cryptographic chain verification only. It does
not bypass the structural torn-tail/internal-malformed-line check (S1, the private
peek_confirms_trailing_torn helper) — a line that fails to parse as JSON is still a
hard error even with this override, since that is a distinct failure class (structural
corruption, not a cryptographic tamper verdict) that this override was never meant to
paper over. An operator with a genuinely corrupt (non-tamper) internal-malformed-line
session cannot recover it via --allow-unverified.
§Errors
Returns any error Self::open_exclusive can return other than
SessionError::Integrity (which this method exists specifically to bypass).
Sourcepub fn last_seq(&self) -> Option<u64>
pub fn last_seq(&self) -> Option<u64>
The highest seq durably appended so far, or None if the log is empty.
Sourcepub async fn append(
&self,
turn_id: Option<u64>,
parent_seq: Option<u64>,
kind: SessionEvent,
) -> Result<SessionEventEnvelope, SessionError>
pub async fn append( &self, turn_id: Option<u64>, parent_seq: Option<u64>, kind: SessionEvent, ) -> Result<SessionEventEnvelope, SessionError>
Append one event, assigning it the next monotonic seq, and fsync before returning.
The single write_all + sync_all pair is the atomicity boundary INV-SP-2 relies on: a
crash mid-write can only ever corrupt this one trailing line.
When history-chain verification is configured, the chain-link read-modify-write
(canonicalize with chain: None, hash, then serialize again with the computed hash) is
folded into the same critical section as seq assignment and the physical write/fsync
(S2) — on-disk order always matches chain order, exactly as it already had to for seq
(#5487).
§Errors
Returns SessionError::Serde if the event cannot be JSON-encoded, or
SessionError::Io if the write or fsync fails.
Sourcepub async fn finalize(&self) -> Result<(), SessionError>
pub async fn finalize(&self) -> Result<(), SessionError>
Finalize this handle: if a vault-anchor store is configured (issue #6449) and this
handle’s lifetime saw at least one chained append, persist an Anchor recording the
current (epoch, count, head) — a prefix commitment as of this clean close, not a
guarantee against every possible future truncation (see the module docs’ session prefix
residual note).
Written last, after every append is durably fsynced, so a crash before this point leaves the log present with no anchor, which is always benign (never a false tamper signature).
A no-op, not an error, when no anchor store is configured or this handle never chained.
§Errors
Returns SessionError::Integrity if the configured anchor store’s put fails. Callers
should treat this as best-effort and log rather than fail the whole close/shutdown flow —
the session log itself is already safely written.
Sourcepub async fn read_all(&self) -> Result<Vec<SessionEventEnvelope>, SessionError>
pub async fn read_all(&self) -> Result<Vec<SessionEventEnvelope>, SessionError>
Read and validate every event currently in the log, dropping a torn trailing line from
the result (INV-SP-2). Only physically repairs the file if this handle was opened via
Self::open_exclusive — see that method’s doc comment.
§Errors
Returns SessionError::Io if the file cannot be read, or SessionError::Integrity
if hash-chain verification fails (S1: this check always runs before any torn-tail
repair).
Auto Trait Implementations§
impl !Freeze for SessionEventLog
impl !RefUnwindSafe for SessionEventLog
impl !UnwindSafe for SessionEventLog
impl Send for SessionEventLog
impl Sync for SessionEventLog
impl Unpin for SessionEventLog
impl UnsafeUnpin for SessionEventLog
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more