Skip to main content

SopEngine

Struct SopEngine 

pub struct SopEngine { /* private fields */ }
Expand description

Central SOP orchestrator: loads SOPs, matches triggers, manages run lifecycle.

Implementations§

Source§

impl SopEngine

Source

pub fn new(config: SopConfig) -> Self

Create a new engine with the given config. Call reload() to load SOPs.

Source

pub fn with_store(self, store: Arc<dyn SopRunStore>) -> Self

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.

Source

pub fn with_metrics(self, metrics: Arc<SopMetricsCollector>) -> Self

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.

Source

pub fn with_run_notifier(self, tx: Sender<SopRunSummary>) -> Self

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).

Source

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.

Source

pub fn with_capabilities(self, capabilities: Arc<SopCapabilityRegistry>) -> Self

Inject a deterministic capability registry. Tests and future daemon wiring can replace the built-ins without adding another execution path.

Source

pub fn with_approval_broker(self, broker: Arc<ApprovalBroker>) -> Self

Inject the approval broker (built from [sop.approval] config). Defaults to a pass-through; build_sop_engine replaces it with the configured broker.

Source

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.

Source

pub fn resolve_via_broker( &mut self, run_id: &str, decision: ApprovalDecision, principal: ApprovalPrincipal, ) -> Result<BrokerOutcome>

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.

Source

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.

Source

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.

Source

pub fn reload(&mut self, workspace_dir: &Path)

Load/reload SOPs from the configured directory.

Source

pub fn sops(&self) -> &[Sop]

Return all loaded SOP definitions.

Source

pub fn active_runs(&self) -> &HashMap<String, SopRun>

Return all active (in-flight) runs.

Source

pub fn get_run(&self, run_id: &str) -> Option<&SopRun>

Look up a run by ID (active or finished).

Source

pub fn get_sop(&self, name: &str) -> Option<&Sop>

Look up an SOP by name.

Source

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.

Source

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.

Source

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).

Source

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.

Source

pub fn start_run( &mut self, sop_name: &str, event: SopEvent, ) -> Result<SopRunAction>

Source

pub fn advance_step( &mut self, run_id: &str, result: SopStepResult, ) -> Result<SopRunAction>

Source

pub fn cancel_run(&mut self, run_id: &str) -> Result<()>

Cancel an active run.

Source

pub fn approve_step(&mut self, run_id: &str) -> Result<SopRunAction>

Source

pub fn decide_checkpoint( &mut self, run_id: &str, decision: ApprovalDecision, ) -> Result<SopRunAction>

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.

Source

pub fn finished_runs(&self, sop_name: Option<&str>) -> Vec<&SopRun>

List finished runs, optionally filtered by SOP name.

Source

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).

Source

pub fn deterministic_savings(&self) -> &DeterministicSavings

Return cumulative deterministic execution savings.

Source

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.

Source

pub fn load_proposal( &self, id: &str, ) -> Result<Option<ProposalRecord>, StoreError>

Load a procedural-memory proposal by id from the shared SOP store.

Source

pub fn list_proposals( &self, status: Option<ProposalStatus>, ) -> Result<Vec<ProposalRecord>, StoreError>

List procedural-memory proposals, optionally filtered by lifecycle status.

Source

pub fn start_deterministic_run( &mut self, sop_name: &str, event: SopEvent, ) -> Result<SopRunAction>

Start a deterministic SOP run. Steps execute sequentially without LLM round-trips. Returns the first action (DeterministicStep or CheckpointWait).

Source

pub fn drive_headless_deterministic( &mut self, run_id: &str, first_action: SopRunAction, ) -> Result<SopRunAction>

Source

pub fn advance_deterministic_step( &mut self, run_id: &str, step_output: Value, step_timestamps: Option<(String, Option<String>)>, ) -> Result<SopRunAction>

Advance a deterministic run with the output of the current step. The output is piped as input to the next step.

Source

pub fn resume_deterministic_run( &mut self, state: DeterministicRunState, ) -> Result<SopRunAction>

Resume a deterministic run from persisted state.

Source

pub fn load_deterministic_state(path: &Path) -> Result<DeterministicRunState>

Load a persisted deterministic run state from a JSON file.

Source

pub fn check_approval_timeouts(&mut self) -> Vec<SopRunAction>

Source

pub fn run_maintenance_tick(&mut self) -> MaintenanceSummary

Source

pub fn set_sops_for_test(&mut self, sops: Vec<Sop>)

Replace loaded SOPs (for testing from other modules).

Source

pub fn last_finished_run(&self, sop_name: &str) -> Option<&SopRun>

Source

pub fn finish_run( &mut self, run_id: &str, status: SopRunStatus, reason: Option<String>, ) -> Result<SopRunAction>

Source

pub fn config(&self) -> &SopConfig

Read-only config access for the approval resolver.

Source

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.

Source

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.

Source

pub fn run_events( &self, run_id: &str, ) -> Result<Vec<SopEventRecord>, StoreError>

Ordered event/ledger history for a run (from the durable store).

Source

pub fn resolve_gate( &mut self, run_id: &str, decision: ApprovalDecision, principal: ApprovalPrincipal, ) -> Result<ResolveOutcome>

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,