#3598·sure

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 (ai or bayes) category_id enrichment 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-80 with eight items and no vertical scrolling; a ninth item overflows. Make the nav column md:overflow-y-auto in 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::Search tests + controller/view tests.