pub struct WorkflowRun { /* private fields */ }Expand description
The state of one in-flight workflow execution.
Implementations§
Source§impl WorkflowRun
impl WorkflowRun
Sourcepub fn new(
spec: &WorkflowSpec,
parent_session_id: &str,
) -> Result<WorkflowRun, DeepStrikeError>
pub fn new( spec: &WorkflowSpec, parent_session_id: &str, ) -> Result<WorkflowRun, DeepStrikeError>
Build from a spec. Validates dependency indices + acyclicity (reuses WorkflowSpec).
Sourcepub fn resume(
spec: &WorkflowSpec,
parent_session_id: &str,
submissions: &[Vec<WorkflowNode>],
submission_bases: &[u32],
completed: &[ResumedCompletion],
) -> Result<WorkflowRun, DeepStrikeError>
pub fn resume( spec: &WorkflowSpec, parent_session_id: &str, submissions: &[Vec<WorkflowNode>], submission_bases: &[u32], completed: &[ResumedCompletion], ) -> Result<WorkflowRun, DeepStrikeError>
W0-ABI resume: rebuild an in-flight run by replaying which node agent-ids already completed
(e.g. recovered from the session log after an interruption). Those nodes are pre-marked
done so ready_batch returns only the remaining work — the kernel then
continues the DAG from where it left off.
R3-1: submissions are the runtime Self::submit_nodes batches recorded (in order) before
the interruption, re-applied first so dynamically-appended nodes reconstruct. When
submission_bases records each batch’s original base index (from the
WorkflowNodesSubmitted observation), batches are re-applied at those EXACT indices,
gap-filling any interleaved runtime children (tournament entrants/judges) with inert
completed placeholders — so a later batch never shifts onto a child’s old index and every
completed id maps to the node it originally named. Without bases (legacy logs) batches
replay in order, which is exact only when submissions were the sole runtime appends.
Loop iterations complete under wf-node{N}-i{k}: replay advances the iteration cursor to
the highest recorded k+1 instead of discarding the finished work — the node re-arms at the
next iteration. It completes when max_iters is provably exhausted OR a recorded
loop_continue == false proves the semantic early stop (legacy signal-less logs still
re-run the final iteration).
A completed Classify node replays its recorded branch choice through the same prune logic
as Self::record_completion; with no recorded choice (legacy logs) every branch is pruned
— the same “no recognizable choice” contract as the live path, and strictly safer than
running a branch the original classification rejected.
A completed Tournament controller is NOT replayed (its children are runtime appends the
SDK never logs as node completions): a bracket unresolved at the interruption re-expands and
re-runs from its entrants — wasteful but faithful.
Sourcepub fn ready_batch(&self) -> Vec<usize>
pub fn ready_batch(&self) -> Vec<usize>
Node indices whose dependencies are satisfied and that have not yet started.
Sourcepub fn current_agent_id(&self, node: usize) -> String
pub fn current_agent_id(&self, node: usize) -> String
The agent id for a node’s current spawn. For a Spawn node this is the stable
wf-node{N}; for a Loop node it is wf-node{N}-i{k} where k is the count of iterations
already finished — so each iteration gets a distinct id without any new ABI (the SDK simply
spawns the id it is given and feeds it back as a sub_agent_completed).
Sourcepub fn manifest_for(&self, node: usize) -> IsolationManifest
pub fn manifest_for(&self, node: usize) -> IsolationManifest
Build the isolation manifest for a node’s current spawn, preserving its explicit isolation +
context-inheritance (the AgentRunSpec→from_spec path would overwrite these with
role defaults). Capability inheritance for workflow nodes is left to a later round.
Sourcepub fn quarantine_violation(&self, node: usize) -> bool
pub fn quarantine_violation(&self, node: usize) -> bool
The goal text for a node (for the spawn’s run spec / context injection).
W3 quarantine invariant: a quarantined node reads untrusted content and must run read-only.
Returns true if the node is Quarantined yet declares a write-capable isolation
(Shared/Worktree/Remote) — a privilege contradiction the kernel refuses to spawn,
turning the SDK’s “self-discipline” quarantine into an in-kernel, auditable enforcement.
Sourcepub fn spawn_info(&self, node: usize) -> WorkflowSpawnInfo
pub fn spawn_info(&self, node: usize) -> WorkflowSpawnInfo
The SDK-facing spawn descriptor for a node (agent id + goal + canonical role/isolation/ inheritance strings + model hint). The kernel owns the spec; this is how the goal reaches the host that runs the node.
Sourcepub fn mark_spawned(&mut self, node: usize, agent_id: &str)
pub fn mark_spawned(&mut self, node: usize, agent_id: &str)
Mark a node as spawned: start it in the graph and map its kernel agent id back
to the node for completion routing. (The live in-flight set is the executor’s
SuspendState::SubAgentAwait.agent_ids — the single source of in-flight truth.)
Sourcepub fn mark_denied(&mut self, node: usize)
pub fn mark_denied(&mut self, node: usize)
Mark a node as denied by the syscall gate: fail it in the graph (dependents stay pending and will never become ready). Does not enter the live batch.
Sourcepub fn record_completion(
&mut self,
agent_id: &str,
result: LoopResult,
) -> Option<usize>
pub fn record_completion( &mut self, agent_id: &str, result: LoopResult, ) -> Option<usize>
Record a completed sub-agent against its node. Returns the node index if agent_id
belonged to this workflow, else None.
For a Loop node this counts the finished iteration: while more iterations remain
(< max_iters) the node is re-armed (set_ready) — so the next ready_batch/spawn round
runs wf-node{N}-i{k+1} — and the node stays non-terminal, keeping its dependents pending.
Only when the loop is exhausted is the node completed, promoting its dependents.
Sourcepub fn expand_ready_controllers(&mut self)
pub fn expand_ready_controllers(&mut self)
Expand every tournament controller node whose dependencies are now satisfied (status
Ready) into its entrant children. The controller is moved to Running (it spawns no agent
of its own) and stays non-terminal until its bracket resolves. Called by the executor before
each spawn round, so a controller behind upstream deps expands the moment those complete.
Sourcepub fn submit_nodes_from(
&mut self,
submitter: Option<&str>,
nodes: Vec<WorkflowNode>,
) -> Vec<usize>
pub fn submit_nodes_from( &mut self, submitter: Option<&str>, nodes: Vec<WorkflowNode>, ) -> Vec<usize>
Append a batch of nodes to the in-flight DAG at runtime — the kernel side of the dynamic
“submit nodes” capability, generalizing the tournament’s Self::append_child. A running
node, on completion, can ask for more work to be spawned: unknown-size discovery
(loop-until-done) and per-item fan-out (e.g. a claim-extractor spawning one verifier per
claim) both reduce to “append these nodes now”.
Each submitted node’s depends_on is interpreted batch-relative and backward-only: index
d refers to the d-th node of this submission, and only d < this node's position is
honored — so a submission can carry its own internal forward chain (extractor → dependents)
while forward/self/out-of-range references are dropped rather than stranding the node behind
an unsatisfiable dependency. Nodes with no (remaining) deps are immediately Ready, exactly
like tournament entrants, and flow through the unchanged gated spawn loop — so quota / depth /
quarantine apply per node with no new gate. Returns the appended node indices (their
agent ids are the deterministic wf-node{idx}).
Pure graph mutation: the caller (state machine) is responsible for routing the trigger
through evaluate_syscall before calling this, keeping the kernel’s zero-I/O contract.
G1 no-privilege-escalation: when submitter names a NodeTrust::Quarantined node, every
node in this submission is coerced to Quarantined before append. A quarantined agent read
untrusted content (which may be adversarial), so the topology it asks for is itself untrusted:
it must not be able to launch a trusted (or write-capable) child and thereby escape its
sandbox. This is transitive taint — a quarantined origin’s descendants inherit quarantine —
the topological analogue of a process spawned by an untrusted process inheriting its label.
Trusted (or absent) submitters pass through unchanged. The coercion is enforced here in the
kernel rather than trusting the SDK, and composes with the spawn-time
Self::quarantine_violation gate (a coerced node that also asked for write isolation is
then denied at spawn).
pub fn submit_nodes(&mut self, nodes: Vec<WorkflowNode>) -> Vec<usize>
Sourcepub fn owns_agent(&self, agent_id: &str) -> bool
pub fn owns_agent(&self, agent_id: &str) -> bool
Whether agent_id belongs to this workflow.
Sourcepub fn is_agent_quarantined(&self, agent_id: &str) -> bool
pub fn is_agent_quarantined(&self, agent_id: &str) -> bool
R3-3: whether the node behind agent_id is Quarantined (it read untrusted content). The
kernel uses this to label that node’s output as untrusted-origin when it crosses into the
trusted parent context — the provenance half of the cross-boundary contract (shaping the
output into a structured summary stays the SDK’s job; the kernel cannot inspect content).
Sourcepub fn outcome(&self) -> (Vec<String>, Vec<String>)
pub fn outcome(&self) -> (Vec<String>, Vec<String>)
Outcome at finish: (completed_agent_ids, failed_agent_ids) by node. Nodes left
Pending/Ready (stalled behind a gated dependency) appear in neither.
Sourcepub fn abort_outcome(&self) -> (Vec<String>, Vec<String>)
pub fn abort_outcome(&self) -> (Vec<String>, Vec<String>)
#2-B abort: outcome when the workflow is preempted — every node that has not already
Completed counts as failed (running / ready / pending all abort). Used to emit a terminal
WorkflowCompleted when an InterruptNow tears the whole WorkflowRun down.