Skip to content
docsv0.8.0

InterceptionSlot

The family's single canonical interception primitive (KEYSTONE, core 0.5). Events dispatched through {@see \Milpa\Interfaces\Event\MilpaEventDispatcherInterface} stay ALWAYS readonly — pure notification data, never the vector for veto or short-circuit. This class is the one and only escape hatch: a single mutable object, dispatched ALONGSIDE the readonly event (never in place of it), that a handler mutates to veto or short-circuit and that the emitter reads back after `dispatch()` returns to decide what to do next. Wire it into the payload as `['event' => $readonlyEvent, 'slot' => $slot]` — see the emitter<->slot contract documented on {@see \Milpa\Interfaces\Event\MilpaEventDispatcherInterface::dispatch()}. Atomicity (hallazgo (b) of the adversarial review that hardened this design): {@see shortCircuit()} is the ONLY way this class ever sets a result. It sets the result AND marks the slot stopped in the same call, so {@see hasResult()} and {@see isStopped()} can NEVER disagree — there is no intermediate state where a result exists but the slot isn't stopped, or the slot is stopped but a result was only half-set. There is deliberately no bare `setResult()`. {@see stop()} alone is pure veto: it stops propagation without ever touching the result.

InterceptionSlot::stop()

public function stop(): void

Veto: stop propagation without supplying a replacement result. Use for pure veto semantics — e.g. `plugin.booting`: a feature-flag plugin skips another plugin's boot without producing a "result" for it. After this call {@see isStopped()} is true and {@see hasResult()} stays false.

InterceptionSlot::isStopped()

public function isStopped(): bool

True once {@see stop()} or {@see shortCircuit()} has been called on this slot.

InterceptionSlot::shortCircuit()

public function shortCircuit(?mixed $result): void

Short-circuit: atomically supply a replacement result AND stop propagation. The only way to set a result on this slot — by design there is no bare `setResult()` that could leave {@see hasResult()} true while {@see isStopped()} is false, or vice versa. Use for cache/veto-with-replacement semantics: a handler supplies `$result` in place of the work the emitter would otherwise do (e.g. a cache plugin short-circuits `tool.executing` with a cached `ToolResult`).

Parameters

Parameters of shortCircuit()
NameTypeDescription
$resultmixedthe replacement result the emitter reads back via {@see getResult()}

InterceptionSlot::hasResult()

public function hasResult(): bool

True once {@see shortCircuit()} has supplied a replacement result on this slot.

InterceptionSlot::getResult()

public function getResult(): ?mixed

The replacement result supplied via {@see shortCircuit()}, or null if none was set. Callers MUST check {@see hasResult()} first — a null return is ambiguous between "no result was set" and "the handler short-circuited with a literal null result".