pub struct ApprovalLedger { /* private fields */ }Expand description
An append-only ledger of human-in-the-loop decisions, keyed by fingerprint (last decision wins). Optionally persisted as JSONL so the approval state survives restarts — HITL decisions are durable harness state, not transient prompts.
Concurrency: a single writer per journal file is assumed. The
stateless FFI opens a fresh ledger per call, so a product that drives
approvals from multiple processes against one journal must serialize
those writes itself (e.g. route them through the daemon). Reads
tolerate the writer appending concurrently; a torn final line is
skipped on load and counted in ApprovalLedger::skipped_on_load.
Implementations§
Source§impl ApprovalLedger
impl ApprovalLedger
pub fn new() -> ApprovalLedger
Sourcepub fn with_journal(path: impl Into<PathBuf>) -> Result<ApprovalLedger, Error>
pub fn with_journal(path: impl Into<PathBuf>) -> Result<ApprovalLedger, Error>
Create a ledger backed by a JSONL journal at path, loading any
existing decisions. Each line is one ApprovalRecord; the last
line for a fingerprint wins, so a later rejection overrides an
earlier approval.
Sourcepub fn skipped_on_load(&self) -> usize
pub fn skipped_on_load(&self) -> usize
Number of unparseable lines skipped during the load. Nonzero means the journal is corrupt or was torn by a concurrent writer.
Sourcepub fn record(
&mut self,
record: ApprovalRecord,
) -> Result<&ApprovalRecord, Error>
pub fn record( &mut self, record: ApprovalRecord, ) -> Result<&ApprovalRecord, Error>
Record a decision, persisting it to the journal when configured. Returns the stored record.
A journal write failure is an error, not best-effort (review A7):
callers emit ApprovalRecorded audit events on the strength of this
call, so a decision that only landed in memory must not be reported
as durable. On Err the decision is NOT stored (memory and journal
stay consistent — both lack it) and the caller must surface the
failure. An in-memory ledger (no journal) cannot fail.
Sourcepub fn lookup(&self, fingerprint: &str) -> Option<&ApprovalRecord>
pub fn lookup(&self, fingerprint: &str) -> Option<&ApprovalRecord>
The current decision for a fingerprint, if any.
pub fn all(&self) -> impl Iterator<Item = &ApprovalRecord>
Sourcepub fn record_decision(
&mut self,
fingerprint: &str,
required_tier: PermissionTier,
decision: ApprovalDecision,
reviewer: &str,
reason: &str,
evidence: Option<String>,
) -> Result<ApprovalRecord, Error>
pub fn record_decision( &mut self, fingerprint: &str, required_tier: PermissionTier, decision: ApprovalDecision, reviewer: &str, reason: &str, evidence: Option<String>, ) -> Result<ApprovalRecord, Error>
Build and record a decision against an explicit
fingerprint — the ledger-level twin of
PermissionGate::record_for_fingerprint, for callers that share
ONE ledger across many gates/sessions (e.g. the daemon’s shared
approval substrate) and so must not route the write through any
single session’s gate. Errs when the journal write fails (the
decision is then NOT recorded — see Self::record).
Trait Implementations§
Source§impl Debug for ApprovalLedger
impl Debug for ApprovalLedger
Source§impl Default for ApprovalLedger
impl Default for ApprovalLedger
Source§fn default() -> ApprovalLedger
fn default() -> ApprovalLedger
Auto Trait Implementations§
impl Freeze for ApprovalLedger
impl RefUnwindSafe for ApprovalLedger
impl Send for ApprovalLedger
impl Sync for ApprovalLedger
impl Unpin for ApprovalLedger
impl UnsafeUnpin for ApprovalLedger
impl UnwindSafe for ApprovalLedger
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> ErasedDestructor for Twhere
T: 'static,
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