9334caf533
Deterministic default (ListBasedTextFilter) backed by a configurable JSON term list, with normalization (case-fold, leetspeak substitutions, stripped punctuation/spacing between letters) so trivial evasion doesn't slip through. Supports both reject (blocking) and redact (asterisk replacement) modes. TextFilter is a Protocol, leaving an explicit extension point for a future third-party moderation provider. Standalone module, not wired into any router/endpoint -- sibling chat tasks depend on this one. No DB/migration work. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y2FESCaMXeJpC9gSctiEeD