pub trait RunStore: Send + Sync {
Show 15 methods
// Required methods
fn name(&self) -> &str;
fn create<'life0, 'async_trait>(
&'life0 self,
record: RunRecord,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn get<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
) -> Pin<Box<dyn Future<Output = Result<RunRecord, RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn list_by_task<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 TaskId,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn append_step_entry<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
entry: StepEntry,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn append_degradation<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
entry: DegradationEntry,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn update_status<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
status: RunStatus,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn try_transition<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
from: RunStatus,
to: RunStatus,
) -> Pin<Box<dyn Future<Output = Result<bool, RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn acquire_assignee<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
slot: &'life2 str,
op: &'life3 str,
desc: &'life4 str,
) -> Pin<Box<dyn Future<Output = Result<(u64, Option<Assignee>), RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait;
fn vacate_assignee<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
slot: &'life2 str,
expected_gen: u64,
) -> Pin<Box<dyn Future<Output = Result<VacateOutcome, RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn set_result<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
result_ref: Value,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn set_input_json<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
input_json: String,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn list_running<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn list<'life0, 'life1, 'async_trait>(
&'life0 self,
filter: &'life1 RunListFilter,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
}Expand description
Persistence interface for Run records — one kick of a Task, in the
issue #13 ID hierarchy.
Required Methods§
Sourcefn create<'life0, 'async_trait>(
&'life0 self,
record: RunRecord,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn create<'life0, 'async_trait>(
&'life0 self,
record: RunRecord,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Create a new Run row. Returns Duplicate if record.id is already
stored.
This is the one door into the store that carries a caller-built
RunRecord, so it is where the assignment axis is checked rather
than assumed: a record whose current holds a generation above
next_generation is refused with
RunStoreError::AssigneeGenerationAhead (A2, see
RunRecord::validate_assignment_generations). Implementations must
run that check before persisting anything. The rest of the record —
step_entries, status, timestamps — is still trusted as given.
Sourcefn get<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
) -> Pin<Box<dyn Future<Output = Result<RunRecord, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn get<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
) -> Pin<Box<dyn Future<Output = Result<RunRecord, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Fetch a Run by id.
Sourcefn list_by_task<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 TaskId,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list_by_task<'life0, 'life1, 'async_trait>(
&'life0 self,
task_id: &'life1 TaskId,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
List every Run kicked from task_id, ascending by created_at
(oldest kick first).
Sourcefn append_step_entry<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
entry: StepEntry,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn append_step_entry<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
entry: StepEntry,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Append one step-trace entry to a Run’s step_entries, bumping
updated_at to now.
Sourcefn append_degradation<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
entry: DegradationEntry,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn append_degradation<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
entry: DegradationEntry,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Append one worker-reported degradation to a Run’s degradations
(GH #32), bumping updated_at to now. Independent of
Self::append_step_entry — degradations never flow through step
OUTPUT/fold.
Sourcefn update_status<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
status: RunStatus,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn update_status<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
status: RunStatus,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Update a Run’s status, bumping updated_at to now.
Sourcefn try_transition<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
from: RunStatus,
to: RunStatus,
) -> Pin<Box<dyn Future<Output = Result<bool, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn try_transition<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
from: RunStatus,
to: RunStatus,
) -> Pin<Box<dyn Future<Output = Result<bool, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Atomically transition a Run’s status from from to to, bumping
updated_at to now — the compare-and-set primitive the resume path
(POST /v1/runs/:id/resume) uses to guard against a double resume
racing the same Interrupted Run into Running twice.
Returns Ok(true) when a row with this id AND current status
from was found and flipped to to; Ok(false) when the row’s
current status was not from (a concurrent transition already won,
or the Run is absent). Never a hard error for the status-mismatch /
absent case — the boolean is the caller’s race signal.
Sourcefn acquire_assignee<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
slot: &'life2 str,
op: &'life3 str,
desc: &'life4 str,
) -> Pin<Box<dyn Future<Output = Result<(u64, Option<Assignee>), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn acquire_assignee<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
slot: &'life2 str,
op: &'life3 str,
desc: &'life4 str,
) -> Pin<Box<dyn Future<Output = Result<(u64, Option<Assignee>), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Assign this Run’s slot to op — the model’s Assign event
(§4.3).
slot is the Blueprint-declared Operator seat (operator_ref) the
assignment applies to; only that key of
RunRecord::current is touched, so assigning one seat never
disturbs another’s holder.
Bumps the Run’s generation counter G by one and stamps the new
value onto a freshly minted Assignee, which replaces
current[slot] (A4 / Q3: the previously stored Assignee
is returned untouched, never rewritten in place). G is Run-wide,
so this advances the same counter every other slot’s events advance.
updated_at is bumped to now.
A8: this succeeds regardless of who holds the slot — a live
holder is displaced (last writer wins); there is no exclusion and
no rejection path for a contended slot. The only refusals are
A9 (an empty or whitespace-only desc returns
RunStoreError::AssigneeDescRequired) and an empty slot
(returns RunStoreError::AssigneeSlotRequired); an unknown id
returns RunStoreError::NotFound.
The read of G and the write of both columns happen atomically, so
two concurrent acquires can never read the same G and hand out a
duplicate generation — including when they name different slots.
Returns (new generation, the holder this call displaced from this slot) — the caller needs both to tell whether it took over from
someone and under which generation it now dispatches.
Sourcefn vacate_assignee<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
slot: &'life2 str,
expected_gen: u64,
) -> Pin<Box<dyn Future<Output = Result<VacateOutcome, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn vacate_assignee<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
slot: &'life2 str,
expected_gen: u64,
) -> Pin<Box<dyn Future<Output = Result<VacateOutcome, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Release the holder of this Run’s slot — the model’s Vacant
event (§4.3) — but only while that seat still holds the
generation the caller observed. Other slots keep their holders.
expected_gen is the gen of the Assignee the caller read and
decided about. The comparison and the write happen in one critical
section (the same transaction / lock acquire_assignee uses), so a
concurrent acquire either lands before the check — and the
release becomes a no-op — or after the write, which is an ordinary
A8 takeover of an already-Vacant seat. There is no window in
which a stale reader deletes a newer holder. See VacateOutcome
for why the generation has to travel with the call at all; this is
the only release verb, because both production callers (A7 at
AssigneeRouter::execute and O8’s cascade) are stale readers,
and an unconditional sibling would exist only to be picked by
mistake.
A4: a release that actually happens bumps the Run-wide
generation counter exactly like Assign does; it just mints no
Assignee. A subsequent Self::acquire_assignee — on this slot
or any other — therefore continues from the bumped value rather than
reusing the generation the released holder had. updated_at is
bumped to now. A VacateOutcome::Stale result is not an
assignment event and writes nothing at all: the counter counts
events, and a release that did not release is not one.
An already-Vacant slot therefore answers
Stale { current: None } rather than burning a generation — no
generation can match an absent holder. An empty slot returns
RunStoreError::AssigneeSlotRequired and an unknown id returns
RunStoreError::NotFound.
Sourcefn set_result<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
result_ref: Value,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_result<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
result_ref: Value,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Set a Run’s terminal result_ref, bumping updated_at to now.
Sourcefn set_input_json<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
input_json: String,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_input_json<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
input_json: String,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Replace the opaque launch snapshot after pre-dispatch binding has
enriched it (for example with immutable bound_agents).
Sourcefn list_running<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn list_running<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
List every Run currently Running (issue #35 ST2 boot sweep +
ST4 occupancy check reuse this). No ordering guarantee.
Sourcefn list<'life0, 'life1, 'async_trait>(
&'life0 self,
filter: &'life1 RunListFilter,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn list<'life0, 'life1, 'async_trait>(
&'life0 self,
filter: &'life1 RunListFilter,
) -> Pin<Box<dyn Future<Output = Result<Vec<RunRecord>, RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
List Runs matching filter, newest-first (created_at
descending) — the GET /v1/runs collection read.
Sourcefn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn delete<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 RunId,
) -> Pin<Box<dyn Future<Output = Result<(), RunStoreError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Delete a Run row (the DELETE /v1/runs/:id retention operation).
The caller is responsible for pruning the sibling trace stream
(crate::store::trace::RunTraceStore::delete_run) — the two
stores are deliberately uncoupled at the trait level.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".