pub struct RunStore { /* private fields */ }Expand description
JSONL run-trace store rooted at <car_dir>/runs/.
Stateless across calls — each append opens, writes, and closes the run’s file. Flush points are sparse (turn granularity), so there is no long-lived file handle to manage, and a concurrently-restarting daemon always sees a consistent on-disk tail.
Implementations§
Source§impl RunStore
impl RunStore
Sourcepub fn new(runs_root: PathBuf, retention: RetentionConfig) -> Self
pub fn new(runs_root: PathBuf, retention: RetentionConfig) -> Self
Construct a store rooted at runs_root (the runs/ dir itself).
Use RunStore::from_journal_dir from the daemon, which derives
the root from the configured journal dir; this constructor is the
test/embedder seam.
Sourcepub fn from_journal_dir(journal_dir: &Path) -> Self
pub fn from_journal_dir(journal_dir: &Path) -> Self
Derive the store from the daemon’s journal dir. The journal lives
at ~/.car/journals, so the run store is its sibling
~/.car/runs; retention is read from ~/.car/config.toml. When
the journal dir has no parent (a bare relative path), the store
falls back to journal_dir/../runs resolved lexically.
Sourcepub fn append_records(
&self,
agent_id: &str,
run_id: &str,
records: &[RunRecord],
) -> Result<()>
pub fn append_records( &self, agent_id: &str, run_id: &str, records: &[RunRecord], ) -> Result<()>
Append one or more RunRecords to a run’s file, creating it 0600
on first write. Records are written one JSONL line each, in order.
This is the single low-level flush primitive the wiring calls at
each boundary: RunStarted on runs.start, RunTurns as the
recorder produces them, and the terminal RunEnded/Incomplete on
runs.complete/disconnect.
Sourcepub fn write_started(&self, started: &RunStarted) -> Result<()>
pub fn write_started(&self, started: &RunStarted) -> Result<()>
Append the RunStarted line + create the run file (runs.start).
Sourcepub fn append_turns(
&self,
agent_id: &str,
run_id: &str,
turns: &[RunRecord],
) -> Result<()>
pub fn append_turns( &self, agent_id: &str, run_id: &str, turns: &[RunRecord], ) -> Result<()>
Append RunTurn records (the recorder’s per-proposal output).
Sourcepub fn write_ended(&self, ended: &RunEnded) -> Result<()>
pub fn write_ended(&self, ended: &RunEnded) -> Result<()>
Append the terminal RunEnded line (runs.complete or the
disconnect-Incomplete path).
Sourcepub fn get_run_trace(&self, run_id: &str) -> Option<Vec<RunRecord>>
pub fn get_run_trace(&self, run_id: &str) -> Option<Vec<RunRecord>>
Load a run’s full ordered trace from disk by run_id — the U5
runs.get_trace read path. Works after a restart when memory is
empty. Resolves run_id -> agent_id by scanning the tree, then
reads the JSONL. A corrupt/partial trailing line is skipped, so the
prior valid records still load (never fails the whole run).
Returns None when no file exists for the run_id.
Sourcepub fn get_run_trace_for(
&self,
agent_id: &str,
run_id: &str,
) -> Option<Vec<RunRecord>>
pub fn get_run_trace_for( &self, agent_id: &str, run_id: &str, ) -> Option<Vec<RunRecord>>
Load a run’s trace given both keys (cheaper — no tree scan). Used
by list_runs internally and available to callers that already
know the owning agent.
Sourcepub fn list_runs(&self, agent_id: &str) -> Vec<RunSummary>
pub fn list_runs(&self, agent_id: &str) -> Vec<RunSummary>
List an agent’s runs newest-first — the U5 runs.list read path.
Each summary is built from the run file’s records (head for
RunStarted, tail for the terminal record, count of Turns).
Returns an empty Vec for an agent with no runs (the empty-state).
Sourcepub fn agent_for_run(&self, run_id: &str) -> Option<String>
pub fn agent_for_run(&self, run_id: &str) -> Option<String>
Resolve the owning agent_id for a run_id from disk. Mirrors
Self::resolve_run_path but returns the agent dir name — U5’s
authorization check (KTD10) needs run_id -> agent_id to verify
ownership before serving a trace.
Sourcepub fn gc(&self) -> usize
pub fn gc(&self) -> usize
Retention GC (R6) — call on daemon boot. Per agent: keep the most
recent max_per_agent completed runs and drop any completed
run older than max_age_days, whichever is more restrictive. An
in-progress run (no terminal record) is NEVER evicted. Returns the
number of run files removed.
Sourcepub fn adopt_orphans(&self) -> usize
pub fn adopt_orphans(&self) -> usize
Adopt crash-orphaned runs at boot (FIX 4). A daemon crash mid-run
leaves an on-disk run with RunStarted (+ Turns) but no terminal
RunEnded, so it reads InProgress forever and the GC — which never
evicts an in-progress run — can never reclaim it. The file leaks
across every crash.
This runs at store construction/boot, BEFORE gc(). At that moment
the in-memory runs map is always empty, so any run that is
InProgress on disk cannot have a live harness writing to it — it is
necessarily a crashed prior process. We append an Incomplete
terminal RunEnded marker to adopt it, making it terminal and thus
age-GC-eligible (so a later gc() in the same boot can reclaim it).
Returns the number of runs adopted. Best-effort: an unwritable file is skipped rather than failing startup.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for RunStore
impl RefUnwindSafe for RunStore
impl Send for RunStore
impl Sync for RunStore
impl Unpin for RunStore
impl UnsafeUnpin for RunStore
impl UnwindSafe for RunStore
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
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