ADR-0010: Loop and spend safety¶
Status: Accepted Date: 2026-09-28 Deciders: Alex Nodeland
Context¶
Rules that run LLM workflows, whose output can be new events that other rules watch, can loop forever and can spend without bound. A misconfigured rule should fail safe, not run up a bill.
Decision¶
- Causation depth. Every event records the causal chain it belongs to (
correlation_id) and, when a run emitted it, the chain's depth. Publishing beyond the stream's limit (8 by default) is rejected withdepth_exceeded, which fails the run with a clear error. - Throttles on rules cap firings per scope and period.
- Emit allowlists.
EventContext(emit=[...])limits the event types an agent can publish; the reactor enforces it. - Concurrency limits per reactor, rule and stream bound the runs executing at once.
- Timeouts per action cancel a run that takes too long; it is then retried or dead-lettered like any failure.
- Usage limits.
AgentActionpasses pydantic-aiUsageLimitsthrough.
Options considered¶
| Option | Stops runaway loops | Bounds spend |
|---|---|---|
| Depth limit, throttles, allowlists, limits and timeouts (chosen) | Yes | Yes |
| Document the risk and leave it to applications | No | No |
| Forbid rules from reacting to events runs emit | Yes | Partly, and it rules out useful chains |
Consequences¶
- Easier: a mistaken rule stops at a known depth and rate, with an error an operator can see.
- Harder: legitimate long chains need a higher limit, set explicitly per stream.
Action items¶
- [ ] Implement causation and depth checks (RFC-0001 phases 1 and 2), and allowlists and usage limits (phase 3).