- Shipped
- September 3, 2026 at 6:08 AM UTC
- Author
- Kamo
- Commit
- cfdc206
GET **************** takes the SAME query string GET the lead detail page draws — across every lead the filter bar matches. "What has been said to the leads I am working" is a question about a set, and until now the only way to ask it was to open them one at a time. The filter translation moves to LeadGridFilters so both endpoints resolve a query string identically; a second copy would drift, and the way it drifts is a timeline covering different leads from the grid that produced it. Two different bounds, for two different reasons. Calls, voicemails, texts and e-mails are unbounded: LEAD_COMMUNICATIONS carries ORG_ID and is indexed on (ORG_ID, OCCURRED_AT), so one keyset query walks the org's correspondence newest-first and tests each row against the grid predicate as a correlated EXISTS — the same cost whether seven leads matched or seventy thousand. Notes and chat cannot be: they live in MEDIA_OBJS, which carries no org and no lead, and the only join back is LEADS.STREAM_GUID, which is not indexed. Those two resolve the matching leads first, capped at 1000, and the response says when it capped rather than quietly dropping history. Authorisation is the lead timeline's, applied in SQL. An entry carries a lead's own number or address plus message content, so LeadCommsReadGate now also states its rule over the three shapes a lead can have and emits the matching predicate. Writing it a second time is where the bug was: the first draft read "unassigned needs VIEW_UNASSIGNED_LEADS" and missed that refusal() falls THROUGH that check to the contact-info one, which would have put every pooled lead's correspondence in front of a member holding only the pool right. The two forms are now pinned to each other exhaustively — every right combination against every shape. Unlike an account's rollup this does NOT collapse an event that reached two matched leads. Two reasons pointing the same way: each row names the lead it belongs to and "this call reached both" is a fact about the book being worked, and collapsing rows out of a single fixed-size page can leave the survivor last twin as a fresh entry the client cannot de-duplicate. The criteria queries are pulled into LeadGridCommsQueries as pure functions so LeadGridCommunicationsSqlTest can render them against real Hibernate metadata. That matters here more than usual: the grid's own specification already emits EXISTS subqueries, and this nests it inside another one — which is exactly where this service's Hibernate 6.2.13 and the shared library's 6.5 differ.