af-workflow 0.2.0

Spec-driven workflow chassis: typed node expressions composed into a branched DAG. Port of agent_core/workflow/v2.
Documentation
//! What a step node returns. Port of `platform/types.py` Pass / Drop / FanOut.

use crate::event::Event;

/// The outcome of running one event through one [`crate::node::StepNode`].
#[derive(Debug, Clone)]
pub enum StepResult {
    /// Forward the (possibly derived) event to the next step.
    Pass(Event),
    /// Stop propagation here. Filters and sink terminals return this.
    Drop {
        reason: String,
        /// Stable machine-readable code for material business outcomes. A
        /// routine filter drop leaves this empty.
        exit_reason: Option<String>,
    },
    /// Forward several events. Only nodes that declare `produces_fan_out`
    /// may return this; the validator bans fan-out upstream of `execute.*`.
    FanOut(Vec<Event>),
}

impl StepResult {
    pub fn drop(reason: impl Into<String>) -> Self {
        StepResult::Drop {
            reason: reason.into(),
            exit_reason: None,
        }
    }

    /// A material gate/drop that recorders should persist as a run step.
    pub fn gate(exit_reason: impl Into<String>) -> Self {
        let code = exit_reason.into();
        StepResult::Drop {
            reason: code.clone(),
            exit_reason: Some(code),
        }
    }
}