Skip to main content

Transaction categorization on Silvia Analyst

Status: phase 1 (shadow) in this PR, off by default. Plaid’s category mapping stays the fallback. User rules and hand edits always win. Silvia Analyst fills in what those miss, and every user fix becomes a training label.

Non-invasive by design

  • Two new tables, txcat_predictions and txcat_labels. Nothing existing gets a new column, trigger or foreign key.
  • Ids that point at existing tables (transaction_id, category uuids) are soft references with no FK, so existing tables never depend on txcat. Dropping the two tables removes the feature.
  • Phase 1 only reads existing tables. Users see nothing new.
  • The tables live in public with a txcat_ prefix rather than their own schema, because a new schema has to be exposed in the Supabase API settings before supabase-js can reach it.

Pipeline

Tables

How it maps onto existing tables

The model sees numbered categories and numbered transactions and answers with numbers. It never sees or writes a uuid, and a number outside the list is dropped.

Turning it on

  1. Apply supabase/migrations/20260925_02_txcat_shadow.sql.
  2. Set TXCAT_SHADOW_ENABLED=true (and optionally TXCAT_SHADOW_MAX_ROWS, default 500, at most 1000) in the environment.
  3. Set TXCAT_MODEL_VERSION to the model behind the endpoint (default silvia-analyst-1.0). The served name (quant-analyst) is the same across versions, so this is the only thing that tells them apart. Each version predicts once per transaction, so a new version re-predicts recent rows and two versions can be compared on the same transactions.
  4. The cron runs daily at 07:45 UTC. It needs QUANT_ANALYST_MODAL_URL and QUANT_ANALYST_MODAL_KEY; without them it returns skipped.

Reading the results

After a week, labels start landing. The first question is accuracy on user decisions, model vs the Plaid mapping:

Phase 2 (not in this PR)

Only if the model beats the Plaid mapping on user decisions: write transactions.category_uuid for rows with no rule_id, auto_categorized not false, and confidence above a cutoff picked from the phase 1 data, and record which rows were written so the change can be rolled back.