- Shipped
- August 21, 2026 at 11:59 PM UTC
- Author
- Kamo
- Commit
- 54acc0c
SecurityService serves the roster the chat UI is built from, so it has to answer with the same verdicts MediaService enforces with -- one shared evaluator, or the product offers conversations the backend then refuses and it reads as a broken chat rather than as a policy. The roster is annotated, never filtered. A member the policy blocks keeps their name, photo and presence and loses only the chat affordance, which then carries the organization's own explanation. Hiding them would have been less work and would have made the roster lie about who works here. Verdicts for the whole roster resolve in one pass off one cached snapshot. Asking per member would have put an evaluation -- and on a cold cache, a query -- inside a loop that already runs once per colleague. A policy read that fails leaves every row unannotated rather than failing the roster: the send path is still the authority, so the cost is a confusing affordance, not an unenforced policy.