Struct SopEngine
pub struct SopEngine { /* private fields */ }Expand description
Central SOP orchestrator: loads SOPs, matches triggers, manages run lifecycle.
Implementations§
Source§impl SopEngine
impl SopEngine
Sourcepub fn new(config: SopConfig) -> SopEngine
pub fn new(config: SopConfig) -> SopEngine
Create a new engine with the given config. Call reload() to load SOPs.
Sourcepub fn with_store(self, store: Arc<dyn SopRunStore>) -> SopEngine
pub fn with_store(self, store: Arc<dyn SopRunStore>) -> SopEngine
Inject a durable run-state store (used by build_sop_engine). Default is
an ephemeral in-memory store, so callers that don’t set one keep today’s
behavior exactly.
Sourcepub fn with_metrics(self, metrics: Arc<SopMetricsCollector>) -> SopEngine
pub fn with_metrics(self, metrics: Arc<SopMetricsCollector>) -> SopEngine
Inject the metrics collector. build_sop_engine passes the process-shared
collector so the engine’s completion metrics and the SOP tools’ reports
observe one set; the default per-engine collector keeps tests isolated.
Sourcepub fn with_run_notifier(self, tx: Sender<SopRunSummary>) -> SopEngine
pub fn with_run_notifier(self, tx: Sender<SopRunSummary>) -> SopEngine
Attach a live run-change notifier. build_sop_engine wires the gateway’s
sender here so run transitions push to the Runs WebSocket. Returns the
engine unchanged when never called (tests, headless embedders).
Sourcepub fn subscribe_run_changes(&self) -> Option<Receiver<SopRunSummary>>
pub fn subscribe_run_changes(&self) -> Option<Receiver<SopRunSummary>>
Subscribe to the live run-change feed if a notifier is attached. Each
item is a fresh SopRunSummary for the run that just transitioned.
Sourcepub fn with_capabilities(
self,
capabilities: Arc<SopCapabilityRegistry>,
) -> SopEngine
pub fn with_capabilities( self, capabilities: Arc<SopCapabilityRegistry>, ) -> SopEngine
Inject a deterministic capability registry. Tests and future daemon wiring can replace the built-ins without adding another execution path.
Sourcepub fn with_approval_broker(self, broker: Arc<ApprovalBroker>) -> SopEngine
pub fn with_approval_broker(self, broker: Arc<ApprovalBroker>) -> SopEngine
Inject the approval broker (built from [sop.approval] config). Defaults to
a pass-through; build_sop_engine replaces it with the configured broker.
Sourcepub fn approval_broker(&self) -> Arc<ApprovalBroker> ⓘ
pub fn approval_broker(&self) -> Arc<ApprovalBroker> ⓘ
The approval broker (membership + quorum authorization). Callers that must deliver an escalation to a policy’s second route read it here.
Sourcepub fn resolve_via_broker(
&mut self,
run_id: &str,
decision: ApprovalDecision,
principal: ApprovalPrincipal,
) -> Result<BrokerOutcome, Error>
pub fn resolve_via_broker( &mut self, run_id: &str, decision: ApprovalDecision, principal: ApprovalPrincipal, ) -> Result<BrokerOutcome, Error>
Resolve a gate or deterministic checkpoint THROUGH the broker (membership +
quorum), then its single transition owner.
This is the entry point out-of-band surfaces (gateway / CLI / tools) should
call so a [sop.approval] policy is enforced; with no policy it is exactly
resolve_gate for a WaitingApproval run or the historical checkpoint
resolver for a PausedCheckpoint run. The broker is cloned out first so it
does not borrow self while self is mutated by the chokepoint.
Sourcepub fn restore_runs(&mut self)
pub fn restore_runs(&mut self)
Reconstruct in-flight runs from the store at startup (durable backends). No-op for the in-memory default. Does not overwrite already-present runs.
Sourcepub fn is_gate_reference_superseded(
&self,
run_id: &str,
reference_revision: u32,
) -> bool
pub fn is_gate_reference_superseded( &self, run_id: &str, reference_revision: u32, ) -> bool
A prompt becomes stale only after a replacement presentation is durable. A gate can update its in-memory revision before its parked snapshot saves; finalizing the old prompt in that window would leave operators without a recoverable replacement after a crash.
Sourcepub fn active_runs(&self) -> &HashMap<String, SopRun>
pub fn active_runs(&self) -> &HashMap<String, SopRun>
Return all active (in-flight) runs.
Sourcepub fn get_run(&self, run_id: &str) -> Option<&SopRun>
pub fn get_run(&self, run_id: &str) -> Option<&SopRun>
Look up a run by ID (active or finished).
Sourcepub fn match_trigger(&self, event: &SopEvent) -> Vec<&Sop>
pub fn match_trigger(&self, event: &SopEvent) -> Vec<&Sop>
Match an incoming event against all loaded SOPs and return the names of SOPs whose triggers match.
Sourcepub fn wants_source(&self, source: SopTriggerSource) -> bool
pub fn wants_source(&self, source: SopTriggerSource) -> bool
True when any loaded SOP has a trigger of this source. Fan-in callers use this as a cheap pre-filter before building and dispatching an event.
Sourcepub fn can_start(&self, sop_name: &str) -> bool
pub fn can_start(&self, sop_name: &str) -> bool
Check whether a new run can be started for the given SOP (respects cooldown and concurrency limits).
Sourcepub fn evaluate_admission(&self, sop_name: &str) -> SopAdmission
pub fn evaluate_admission(&self, sop_name: &str) -> SopAdmission
A2: decide how to admit a matched trigger for sop_name under its
SopAdmissionPolicy. Admit still passes through the authoritative CAS in
start_run; the other outcomes are surfaced by the dispatch layer so a
non-admitted trigger is never silently lost. A cooldown or unknown SOP drops
regardless of policy (a cooldown is a deliberate rate limit, not backpressure).
AUTHORITY: within a SINGLE daemon this decision is authoritative - the engine
Mutex serializes evaluate_admission + the CAS claim, so two triggers cannot
both admit past the policy. The exec-slot cap is additionally CAS-authoritative
via the shared store even ACROSS engines. The pending-approval pool
(max_pending_approvals), however, is only ADVISORY across engines: a run
parks at approval only AFTER it has executed, so its pending slot cannot be
atomically pre-reserved at admission time, and two engines sharing a store can
each admit a run that later parks. Making the pending cap cross-engine-
authoritative requires a store-level two-phase reservation (a follow-up); the
single-daemon deployment - the common case - is fully authoritative today.
pub fn start_run( &mut self, sop_name: &str, event: SopEvent, ) -> Result<SopRunAction, Error>
pub fn advance_step( &mut self, run_id: &str, result: SopStepResult, ) -> Result<SopRunAction, Error>
pub fn approve_step(&mut self, run_id: &str) -> Result<SopRunAction, Error>
Sourcepub fn decide_checkpoint(
&mut self,
run_id: &str,
decision: ApprovalDecision,
) -> Result<SopRunAction, Error>
pub fn decide_checkpoint( &mut self, run_id: &str, decision: ApprovalDecision, ) -> Result<SopRunAction, Error>
Resolve a checkpoint decision (PausedCheckpoint). Approve resumes the
success path (records the checkpoint Completed, pipes forward down
routing.next); Deny takes the failure path (records the checkpoint
Failed and routes through the step’s on_failure, exactly like a step
that failed execution). This is the single entry point for both outcomes;
callers never branch on status. approve_step is the Approve-only alias.
Sourcepub fn finished_runs(&self, sop_name: Option<&str>) -> Vec<&SopRun>
pub fn finished_runs(&self, sop_name: Option<&str>) -> Vec<&SopRun>
List finished runs, optionally filtered by SOP name.
Sourcepub fn run_summaries(&self, sop_name: Option<&str>) -> Vec<SopRunSummary>
pub fn run_summaries(&self, sop_name: Option<&str>) -> Vec<SopRunSummary>
Summaries of every run the engine currently holds: live runs from the
active set plus retained terminal runs, newest first by start time.
This is the enumeration the Runs surface polls; it never touches the
durable store directly, so it reflects exactly what the running engine
knows (active set + max_finished_runs retention window).
Sourcepub fn deterministic_savings(&self) -> &DeterministicSavings
pub fn deterministic_savings(&self) -> &DeterministicSavings
Return cumulative deterministic execution savings.
Sourcepub fn save_proposal(&self, proposal: &ProposalRecord) -> Result<(), StoreError>
pub fn save_proposal(&self, proposal: &ProposalRecord) -> Result<(), StoreError>
Save a procedural-memory proposal into the shared SOP store. This is the production-facing engine surface EPIC F consumes for approval/write-back.
Sourcepub fn load_proposal(
&self,
id: &str,
) -> Result<Option<ProposalRecord>, StoreError>
pub fn load_proposal( &self, id: &str, ) -> Result<Option<ProposalRecord>, StoreError>
Load a procedural-memory proposal by id from the shared SOP store.
Sourcepub fn list_proposals(
&self,
status: Option<ProposalStatus>,
) -> Result<Vec<ProposalRecord>, StoreError>
pub fn list_proposals( &self, status: Option<ProposalStatus>, ) -> Result<Vec<ProposalRecord>, StoreError>
List procedural-memory proposals, optionally filtered by lifecycle status.
Sourcepub fn start_deterministic_run(
&mut self,
sop_name: &str,
event: SopEvent,
) -> Result<SopRunAction, Error>
pub fn start_deterministic_run( &mut self, sop_name: &str, event: SopEvent, ) -> Result<SopRunAction, Error>
Start a deterministic SOP run. Steps execute sequentially without LLM round-trips. Returns the first action (DeterministicStep or CheckpointWait).
pub fn drive_headless_deterministic( &mut self, run_id: &str, first_action: SopRunAction, ) -> Result<SopRunAction, Error>
Sourcepub fn advance_deterministic_step(
&mut self,
run_id: &str,
step_output: Value,
step_timestamps: Option<(String, Option<String>)>,
) -> Result<SopRunAction, Error>
pub fn advance_deterministic_step( &mut self, run_id: &str, step_output: Value, step_timestamps: Option<(String, Option<String>)>, ) -> Result<SopRunAction, Error>
Advance a deterministic run with the output of the current step. The output is piped as input to the next step.
Sourcepub fn resume_deterministic_run(
&mut self,
state: DeterministicRunState,
) -> Result<SopRunAction, Error>
pub fn resume_deterministic_run( &mut self, state: DeterministicRunState, ) -> Result<SopRunAction, Error>
Resume a deterministic run from persisted state.
Sourcepub fn load_deterministic_state(
path: &Path,
) -> Result<DeterministicRunState, Error>
pub fn load_deterministic_state( path: &Path, ) -> Result<DeterministicRunState, Error>
Load a persisted deterministic run state from a JSON file.
pub fn check_approval_timeouts(&mut self) -> Vec<SopRunAction>
pub fn run_maintenance_tick(&mut self) -> MaintenanceSummary
Sourcepub fn set_sops_for_test(&mut self, sops: Vec<Sop>)
pub fn set_sops_for_test(&mut self, sops: Vec<Sop>)
Replace loaded SOPs (for testing from other modules).
pub fn last_finished_run(&self, sop_name: &str) -> Option<&SopRun>
pub fn finish_run( &mut self, run_id: &str, status: SopRunStatus, reason: Option<String>, ) -> Result<SopRunAction, Error>
Sourcepub fn approval_config(&self) -> &SopApprovalConfig
pub fn approval_config(&self) -> &SopApprovalConfig
The live [sop.approval] config - the single source of truth for approval
groups and policies. The broker resolves membership/policy from this at
use-time rather than holding a cloned copy that could drift on reload.
Sourcepub fn current_step_policy_name(&self, run_id: &str) -> Option<String>
pub fn current_step_policy_name(&self, run_id: &str) -> Option<String>
The name of the approval policy that applies to the run’s current step, if
that step names one. Read surfaces collapse unavailable live state to
None; the broker uses the fallible lookup above to fail closed.
Sourcepub fn run_events(
&self,
run_id: &str,
) -> Result<Vec<SopEventRecord>, StoreError>
pub fn run_events( &self, run_id: &str, ) -> Result<Vec<SopEventRecord>, StoreError>
Ordered event/ledger history for a run (from the durable store).
pub fn resolve_gate( &mut self, run_id: &str, decision: ApprovalDecision, principal: ApprovalPrincipal, ) -> Result<ResolveOutcome, Error>
Auto Trait Implementations§
impl Freeze for SopEngine
impl !RefUnwindSafe for SopEngine
impl Send for SopEngine
impl Sync for SopEngine
impl Unpin for SopEngine
impl UnsafeUnpin for SopEngine
impl !UnwindSafe for SopEngine
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<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§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