--- type: ADR id: "0002" title: "Ingress uses a configurable external rules pipeline before dispatch" status: active date: 2026-04-28 --- ## Context The IMAP ingress flow previously hardcoded whitelist and idempotency checks directly in processMessage. There was no extension point for operator-defined policy such as sender blocking or context-based routing. The flow mixed internal safety rules (anti-loop) with configurable policy (whitelist). ## Decision Separate internal safety checks (anti-loop, idempotency) from external configurable rules. External rules run in a pipeline after safety checks. Each rule implements a `Rule` interface that evaluates `EmailContext` and returns `RuleResult` (accept/reject + metadata). Rule metadata is persisted as `DispatchContext` on the Task and passed to OpenClaw dispatch. Pipeline order: anti-loop (internal) → idempotency (internal) → external rules → threading → save → dispatch. ## Options considered - **Pipeline with Rule interface** (chosen): extensible, testable, each rule is isolated. - **Keep everything in processMessage**: simpler but not configurable or testable. - **Plugin-based rules via config files**: more flexible but over-engineered for current needs. ## Consequences New rules can be added by implementing the Rule interface and registering in config. Whitelist and blocklist are now env-configurable and independently testable. Future rules (domain routing, context selection) fit the same pipeline. Task model has a new DispatchContext column (auto-migrated).