c3ae613bf431577d2e3be0219f5b888b1ef6e7d5
Completes phase C1 — until now the plugin classified mail that nobody could see or steer. Router (§C.6): settings with merge semantics, allow/deny rules, a per-message verdict lookup, learn, and stats. Two behaviours worth naming. A banner threshold above the move threshold is silently capped rather than refused, because a banner past the move score can never be seen — everything that far up is already in Junk. And /learn moves the message even when the engine is unreachable: teaching is best-effort, but filing is what the user actually asked for. UI: settings.page (thresholds in plain language, per-account toggles, the two lists, the privacy switch, activity); message.banner for the uncertain middle, offering Move to Junk / Not spam / Always trust sender; message.actions with Spam / Not spam. The banner mounts on every message but renders only for a `banner` verdict — a spam warning on ordinary mail is worse than no warning. Bundle serving is allow-listed by filename, so /ui/../hook.py is a 404 rather than a file read. Tests cover the defaults, merge semantics, the threshold cap, rule normalisation and idempotency, stats degrading to empty when Rspamd is absent, and RLS isolation: one user cannot see another's rules or settings, nor delete a rule whose id they know. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SqJYt7jD7oUEkoY68sBZo
Description
No description provided
11 MiB
Languages
Python
57.3%
TypeScript
31.7%
JavaScript
8.1%
Shell
1.5%
HTML
0.8%
Other
0.5%