Skip to main content

AfterRunAuditMiddleware

Struct AfterRunAuditMiddleware 

Source
pub struct AfterRunAuditMiddleware { /* private fields */ }
Expand description

Blueprint-declared after-run audit hook layer (GH #34).

Wraps every spawn. After a matched step’s inner signal SETTLES (Ok), dispatches the Blueprint-declared audit agent(s) for that step as an independent, synthetic sub-task — via Engine::start_task + Engine::dispatch_attempt_with, the same “recursive swarming” path a Role::Worker token is allow-listed for (types::WORKER_SWARM_VERBS) — reusing the AUDITED step’s own worker token. Findings are persisted as an OutputEvent::Artifact named "audit:<step_ref>" on the AUDITED step’s own output tail. Downstream steps read those findings via WorkerPayload.context.steps["audit:<step_ref>"] (fold-final drops them from the BP-chain value, but Engine::submit_output dual-writes every Artifact into OutputStore keyed by its own name — see src/core/engine.rs).

§Invariant (observational-only, binding — issue.md #1/#2/#3)

Every failure in the audit path (spawn/dispatch failure, audit worker failure, submit failure) is tracing::warn!-logged and swallowed. The audited step’s own signal, returned to the caller, is ALWAYS the original inner signal, bit-for-bit — same signal?; ...; Ok(()) shape as SeniorEscalationMiddleware above, so an inner Err short-circuits the audit entirely and propagates untouched, and an inner Ok(()) always returns as Ok(()) regardless of what happens inside the audit.

§Recursion guard

An agent name declared as an AuditDef.agent (an “auditor”) is never itself audited — even if a real flow Step happens to be named after a declared auditor (e.g. a Blueprint audits every step via steps: None and also has a flow Step literally named after the auditor). The audit’s OWN dispatch additionally never revisits this layer to begin with: it goes through router (the raw CompiledAgentTableCompiler::compile’s name→adapter table), not the fully-layered stack this middleware itself sits inside, so there is no path back into AfterRunAuditWrapped::spawn from an audit dispatch. The name-set check in audit_def_matches_step (below) is a second, independent belt-and-suspenders guard for the real-flow-Step scenario.

Wired conditionally by service::task_launch::TaskLaunchService::launch (empty Blueprint.audits → no layer, invariant #4 — byte-identical behavior).

Implementations§

Source§

impl AfterRunAuditMiddleware

Source

pub fn new(defs: Vec<AuditDef>, router: Arc<CompiledAgentTable>) -> Self

Holds the audit defs relevant to wiring, and the compiled name→adapter table (Compiler::compile’s CompiledBlueprint.router) used to dispatch each audit agent by name via Engine::start_task + Engine::dispatch_attempt_with — the narrowest handle that resolves an agent name to its SpawnerAdapter without re-entering this same layer (see the module comment’s Recursion guard section).

Trait Implementations§

Source§

impl SpawnerLayer for AfterRunAuditMiddleware

Source§

fn wrap(&self, inner: Arc<dyn SpawnerAdapter>) -> Arc<dyn SpawnerAdapter>

Wraps inner in this layer’s behaviour, returning a new SpawnerAdapter that delegates to inner (directly or via wrap_join) while adding this layer’s cross-cutting effect.

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

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

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

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

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

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

impl<T> MaybeSend for T

Source§

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

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + 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
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + 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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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.
Source§

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

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

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

fn with_current_subscriber(self) -> WithDispatch<Self>

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