# Budget/Cashflow Phase 1.6 — User category rules for import-review candidates

Use this reference when extending or rerunning the user's Budget/Cashflow import-review rule engine after Phase 1.4/1.5 source-aware candidate cleanup.

## Scope and safety gates

- Treat this as a review-candidate reclassification pass, not a productive import.
- Start with repo/runtime inspection and a verified runtime DB backup outside Git.
- Apply migrations before touching runtime candidates; schema changes should be additive and idempotent.
- Re-evaluate only open candidates for the requested year/source scope unless the user explicitly broadens it.
- Never call Confirm or write productive budget transactions during the rule pass.
- Report aggregate counts/statuses only; do not echo real amounts, raw rows, file names with sensitive details, or account identifiers.
- Record one audit event for the rule application summary and update each changed candidate with traceable rule metadata.

## Recommended schema / candidate metadata

Budget transaction candidates should carry enough explanation for review and later category changes:

- `proposed_category_id`
- `proposed_category_name`
- `confidence`
- `requires_review`
- `status`
- `classification`
- `review_reason`
- `rule_id`
- `rule_name`
- `covered_by_source` when another source is canonical

`rule_name` is important for the UI; it lets the user understand *why* a candidate was classified without reading internal IDs.

## Rule semantics learned from Phase 1.6

- Migros/Cumulus:
  - Migros CSV/receipt data is the source of truth for Migros expenses.
  - Credit-card Migros/Cumulus candidates should become `covered_by_migros` with `covered_by_source='migros_csv'` rather than category suggestions.
  - Migros receipt candidates below the configured small-receipt threshold can be `auto_categorized` as `Essen & Haushalt`.
  - Larger Migros receipts should stay `needs_review` because they may need splitting.
  - Do not use over-broad patterns such as plain `M ` for Migros matching; they create false positives against ordinary merchant text. Prefer normalized explicit patterns like `migros`, `cumulus`, and guarded `mmm `, and exclude `migrol` where fuel should belong to transport.
- Galaxus/Digitec:
  - Always keep review-required and splittable by default.
  - Suggested category may be Shopping/Electronics, but status should remain `needs_review` until the user confirms or splits.
- Subscriptions:
  - Apple, Google, Amazon Prime, Netflix, Disney/Disney Plus, Prime Video, Babbel/OpenAI-like recurring providers are good `subscription_auto` candidates when source context supports it.
- Health/medical:
  - Hospitals, pharmacies, labs, health foundations and supplement providers should map to `Gesundheit / Medizin` but remain explainable with rule metadata.
- Auto/transport:
  - Fuel providers, parking, SBB/airport/transport and car-related providers belong to `Auto / Transport`; beware Migrol fuel vs Migros groceries.
- Home/garden, pets, admin/other:
  - Use exact or near-exact merchant patterns, conservative confidence, and keep low-confidence admin/software/authority items review-friendly.

## Review UI filters to expose

A useful review page should provide separate filters/tabs for:

- all
- auto-categorized
- review-needed
- subscriptions
- Galaxus/Digitec
- Migros over threshold
- health/medical
- auto/transport
- shopping
- pets
- admin/unclear
- covered-by-Migros
- duplicates/transfers if those states already exist

Rows should show date, source, merchant/description, proposed category, confidence, status, rule name/reason, and actions for confirm, ignore, transfer marking and split preparation. Technical IDs belong in admin/debug context, not normal User Mode.

## Test pattern

Use TDD with focused synthetic candidates before runtime application:

1. Write tests for rule examples and review filters; verify RED if the function/schema does not exist yet.
2. Include false-positive regression tests for broad Migros patterns.
3. Assert category change/update and split preparation remain possible after auto-suggestion.
4. Assert no productive budget transaction is created by the rule application.
5. After runtime re-evaluation, verify aggregate candidate counts and recent productive transaction count remains zero.

## Verification and commit discipline

- Run backend compile and full pytest.
- Run frontend vitest and production build when API DTOs/UI changed.
- Run `git diff --check`.
- Run Git-safety checks for runtime DBs/spreadsheets/raw CSVs and secret scans; do not flag legitimate provider names such as `OpenFIGI` as secrets unless they appear in key-assignment/token shape.
- Stage only code/tests/docs; never stage runtime DB, build output, caches, source CSV/XLS/XLSX/PDF/DOCX, or secrets.
- Commit, push, and verify remote hash equality using the FinanceManager token/askpass pattern if required, without printing the token.
