feat: wire external rules pipeline into ingress and dispatch

- Add DispatchContext field to Task model for rule metadata storage
- Add BlocklistEmails config (BLOCKLIST_EMAILS env var)
- Wire rules.Pipeline into IMAPWatcher, replacing inline whitelist check
- Pass rule metadata through DispatchContext to OpenClaw dispatch
- Remove isWhitelisted method (now handled by WhitelistRule)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-28 06:38:37 +07:00
co-authored by Claude Opus 4.7
parent ab992abc26
commit aa05e3f7c0
9 changed files with 69 additions and 31 deletions
+1 -1
View File
@@ -27,4 +27,4 @@ func (p *Pipeline) Evaluate(ctx EmailContext) RuleResult {
}
}
return merged
}
}
+3 -3
View File
@@ -95,12 +95,12 @@ type stubRule struct {
result RuleResult
}
func (s *stubRule) Name() string { return s.name }
func (s *stubRule) Name() string { return s.name }
func (s *stubRule) Evaluate(_ EmailContext) RuleResult { return s.result }
type trackingRule struct {
called bool
}
func (t *trackingRule) Name() string { return "tracker" }
func (t *trackingRule) Evaluate(_ EmailContext) RuleResult { t.called = true; return Accept() }
func (t *trackingRule) Name() string { return "tracker" }
func (t *trackingRule) Evaluate(_ EmailContext) RuleResult { t.called = true; return Accept() }
+1 -1
View File
@@ -38,4 +38,4 @@ func (r RuleResult) WithMetadata(key, value string) RuleResult {
type Rule interface {
Name() string
Evaluate(ctx EmailContext) RuleResult
}
}
+1 -1
View File
@@ -39,4 +39,4 @@ func TestEmailContext_Fields(t *testing.T) {
if ctx.Sender != "user@example.com" {
t.Fatal("sender mismatch")
}
}
}
+1 -1
View File
@@ -27,4 +27,4 @@ func (r *WhitelistRule) Evaluate(ctx EmailContext) RuleResult {
return Accept()
}
return Reject("not whitelisted")
}
}