Approvals are session-scoped. Interrupts are run-scoped.
Approval Routing
Approval events originate from the active backend run, but ownership stays at the session aggregate.
Flow:
- the backend emits
:approval_requested ASM.Run.Serverwraps it as%ASM.Event{}- the run notifies
ASM.Session.Server - the session indexes
approval_idto the owning run pid ASM.approve/3routes the final decision back to that run
If the approval is not resolved before approval_timeout_ms, the run emits:
:approval_resolveddecision: :denyreason: "timeout"
That timeout path also clears the session approval index so stale approvals do not remain routable.
Interrupt Control
ASM.interrupt/2 always targets a run id.
- queued runs are removed from the session queue before they start
- active runs call the resolved backend's
interrupt/1 - the run then emits a terminal
user_cancellederror
The caller never needs to know whether the run is executing on the core lane, SDK lane, or a remote node.
Remote Execution
Remote execution does not change the public control surface:
- approvals still resolve through the local
ASM.Session.Server - active remote runs still interrupt through the local
ASM.Run.Server - the same timeout and
user_cancelledsemantics apply in local and remote mode