5eb2ec7bcfbcb9e149585bbdf47749bda0a49802
The count and the list were the same question spelled two ways in one method: the sidebar counts scope by $closedSlugs, read from ticketing_statuses, while the `unassigned` and `mine` list branches carried a hand-written ["resolved", "closed"] that predates the `merged` status. So a correctly merged ticket — status merged, merged_into_id set, its own Show page already calling it read-only — stayed in the queue agents pull new work from, and the page contradicted itself on screen: "Unassigned 4" beside five rendered rows. Both queues now scope by $closedSlugs, so they exclude exactly what their own counts exclude. The scoping is by STATUS and not by merged_into_id on purpose: #938 rows (pointer set, status still open) are live, editable work until a human repairs them, and dropping them out of the queue would hide the rows that most need one. There is a NEGCTRL test for that. Also, the secondary finding: ?filter=closed was accepted, silently returned the All-Open set and was echoed back in props.filters as though a Closed view existed. The sidebar has six views and that is not one of them, so an unrecognised filter normalises to `all` and says so. The list is now a constant that savePrefs() validates against too, rather than the same six slugs written out twice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dashboard-ticketing
Description
Languages
PHP
100%