## Description
Label-based conversation filters (custom views / folders) can time out
for non-admin agents on large accounts. The permission scoping adds
`conversations.inbox_id IN (subquery)` to the filter query, and Postgres
misestimates the row count for the account+inbox combination by several
orders of magnitude. It then drives the query through an inbox index
scan over the account's entire conversation set instead of starting from
the label's taggings, which are often only a handful of rows. The query
exceeds the request timeout and the folder never loads.
This change adds a planner hint to
`Conversations::PermissionFilterService`: when enabled, the inbox
scoping condition is written as `(conversations.inbox_id + 0) IN
(subquery)`, which returns identical rows but is not indexable, so the
planner cannot choose the misestimated path.
`Conversations::FilterService` enables the hint only when the filter
payload contains a `labels` condition. All other callers of the
permission service are unchanged, since the bare condition is the right
plan for unfiltered conversation lists.
Observed on a ~365k-conversation account (worst case, cold cache): label
filter for an agent went from exceeding 60s to ~2ms. Popular labels
(~154k taggings) show no regression. Admin queries are untouched.
Fixes https://linear.app/chatwoot/issue/CW-7787
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
- Specs for row-equivalence of the hinted scoping, admin behavior, and
hint application scoped to label filters only
- `EXPLAIN (ANALYZE, BUFFERS)` comparison on a production-scale dataset
for rare-label, popular-label, and no-label query shapes, agent and
admin, with generic plans matching prepared-statement behavior