expenseCategory() is already declared in AiRuleLearnerTest; Pest loads all
test files into one scope, so the duplicate top-level function fatally aborted
the full suite. Rename to splitTestExpenseCategory().
- keep editing an already-split transaction working when the flag is off:
only resend splits when the split content actually changed or was undone
- make the dashboard cashflow summary and the Transaction Analysis screen
split-aware (per-line category/type + tag attribution)
- skip split transactions on bulk label assignment (labels live on lines),
matching the existing bulk-category skip
- reject splitting a zero-amount transaction
- split editor no longer shows a green 'Remaining: 0' with a dead Save button
when a line is still zero
- add isSplit() helper, UUID split-line keys, clarify allocation docblocks
Add per-line splitting: a transaction can be divided into lines, each with
its own category, amount and labels, summing to the transaction total. The
transaction's own category is nulled and the lines become the source of truth.
- transaction_splits + label_split tables, TransactionSplit model
- split/unsplit via the existing PATCH update (validated: sum, sign, min 2)
- shared effective-allocation layer (SQL + collection) so every category
breakdown (dashboard top categories, cashflow sankey/trend/breakdown,
dashboard analytics, MCP spending) attributes split lines correctly
- budgets attribute per line (category + label match), aggregated per period
- list shows the per-line breakdown, collapsing non-matching lines into a
'Rest' row under a category/label filter; bulk category assignment skips
split transactions
- gated behind the TransactionSplitting Pennant feature