Skip to content

Unified ExpenseCategory taxonomy + AI expense-category prompt

What / Why

First steps of merging "Expense Receipts" and "Service Invoices" into a single expense concept β€” one category taxonomy + GL map shared by the Telegram receipt pipeline and the vendor-invoice path, so a Telegram-uploaded SaaS bill no longer gets mis-binned as fnb/other. Multi-phase; additive so far (no Firestore migration).

DONE (origin/nightly, NOT main)

  • Phase 0 β€” taxonomy (1123f52d) β€” lib/accounting/expenseCategories.ts: EXPENSE_CATEGORIES (18-leaf superset of the two legacy enums ReceiptCategory + VendorCategory, snake_case so existing Firestore values stay valid without migration), EXPENSE_CATEGORY_LABEL/_HINT/_TO_GL (merged, zero GL conflicts β€” verified leaf-for-leaf). Owner-locked collapses: receipt stationary β†’ office (both 6300); the two others unify. receiptCategoryToExpense / vendorCategoryToExpense adapters + coerceExpenseCategory for read-time normalisation; dev-time GL-drift assertion. (Merged #738.)
  • Codex P2 (732bda6b) β€” coerceExpenseCategory coerces labels + synonyms, not just slugs.
  • Phase 1 prep β€” AI prompt (4cb42c7c, merged #740) β€” lib/ai/expensePrompt.ts builds a prompt fragment listing all 18 unified categories + synonym hints, spliced into the Telegram receipt processor's category section (replaces receipt-only RECEIPT_CATEGORY_HINT). GL codes deliberately omitted from the prompt (arbitrary numbers don't help the model + risk leaking).
  • Few-shot (22653f80) β€” 8 worked examples for the disambiguation boundaries Gemini fumbles (gas vs transportation, groceries vs fnb, office vs production, vendor-invoice SaaS shape).

REMAINING (per the commit messages)

  • Schema + type cutover (the "follow-up PR") β€” the output schema still constrains accepted slugs to RECEIPT_CATEGORIES; Gemini sees all 18 categories with hints, but any non-receipt slug (e.g. cloud_services, audio_software, productivity) falls through to other via the existing schema-rejection fallback. The schema + type cutover to the full 18-leaf set is NOT yet landed.
  • Downstream: writer/reader/Firestore cutover to the unified taxonomy (Phase 0 was additive only).

T-066 (receipt auto-categorize consumes receiptCategoryToGl) Β· [[project_receipts_subsystem_state]] Β· [[feedback_honor_system_design]] (cloud agent's area β€” coordinate before touching the writer/schema)