feat(types): recurring costs in the dataset, schema 7

Recurrence is two orthogonal fields, not a list of special cases: a kind
(everyNMonths / everyNDays / everyNWeeks) and an anchoring (calendar /
lastCharge). The phone bill that recharges early when its data cap is hit is
everyNDays(30) anchored to lastCharge — the domain never learns what a data cap
is, because confirming the occurrence early already records the date.

Purchase.source pairs occurrenceDate (identity: which slot this claims) with
Purchase.date (truth: when the money moved). They differ whenever a bill is
paid off schedule, and lastCharge measures from the latter.

RecurringCost.amount is a single mutable Money with no RuleVersion-style
series. Safe only because confirmed purchases hold what was actually paid;
under projection-only it would destroy history.

The 6 -> 7 step writes an empty array and reads nothing. Decimals took 6.
This commit is contained in:
Lucas Winther committed 2026-09-03 03:41:48 +02:00
1 parent de333685a2
commit a456aadf35
9 files changed
+156 -1

No files matched your search

+1
View File
@@ -49,6 +49,7 @@ const data: Dataset = {
},
],
purchases: [spend("a", "food", 500, "2026-01-10"), spend("b", "games", 300, "2026-02-10")],
recurring: [],
};
describe("monthView", () => {