Feature: filter transactions by automatic-categorization status (`AI` / `AI history`)
Author: joshiarnavCreated Sep 16, 2026Updated Sep 16, 2026
Summary
After running auto-categorization (Bayes pre-pass since #3465, then the LLM), users need a way to review what was categorized for them. Add an AI filter to Transactions with two independent checkboxes:
- AI — an automatic (
aiorbayes)category_idenrichment exists and still equals the current category. - AI history — an automatic category enrichment exists but the current category differs (overridden by user / rule / import).
Selecting both = either (OR). Composes with all existing filters (account, date, type, status, amount, category, tag, merchant).
Query semantics
Use EXISTS (SELECT 1 FROM data_enrichments …) predicates rather than a join, so a transaction with both an ai and a bayes row cannot appear twice or double-count in the summary totals (same reasoning as the tag filter fix in #3174).
AI:EXISTS(de WHERE de.enrichable = transaction AND attribute_name = 'category_id' AND source IN ('ai','bayes') AND de.value = to_jsonb(transactions.category_id::text))AI history: an automatic enrichment exists and no automatic enrichment matches the current category (so the two sets are disjoint and match the badge semantics).
UI
- New nav item AI (icon
sparkles) in the filter popover with two checkboxes, localized labels/descriptions. - Active-filter chips read "AI" / "AI history", not the raw param values.
- The desktop popover nav column is
md:h-80with eight items and no vertical scrolling; a ninth item overflows. Make the nav columnmd:overflow-y-autoin the same PR rather than growing the popover.
Acceptance criteria
AI/AI history/ both return the expected rows; disjointness holds.- Composes with another filter (e.g. category) without duplicating rows or totals.
- Controller permits the new param; chips render localized labels; clearing a chip works.
- Filter nav remains fully reachable at the existing popover height.
Transaction::Searchtests + controller/view tests.
Source: we-promise/sure