Commit Graph
9 Commits
Author SHA1 Message Date
Lucas Winther 7cccd7a41a feat: add month breakdown and session backups
Continuous Integration / lint-and-test (push) Successful in 17s
Continuous Integration / docker-build-and-push (push) Successful in 35s
Allow recurring costs and confirmations to remain unassigned when created from a purchase without a post. Add browser backup retention and restore controls, with coverage and documentation updates.
2026-10-01 04:01:49 +02:00
Lucas WintherandClaude Opus 5.5 933027cb1b Merge main into the anchored model
Main moved on by 27 commits since this branch forked, including three schema
steps of its own (budget folders, placement, nested bills). Resolutions worth
knowing:

- The anchored-model migration becomes 10 -> 11; main's 7 -> 10 run first.
- Main's nextUnconfirmedOccurrenceOnOrAfter walked the calendar grid for
  every cost, which would have shown the slot-model "next due" for an
  anchored bill in the budget tree. Both walks are now generators and the
  lookup dispatches on anchoring, like occurrencesOf.
- A folder's "Bills due" summed only occurrences, and an anchored bill's
  charges are never occurrences, so a charged phone plan read as 0 due.
  budgetTree now adds an anchored bill's charges in the month.
- Main's RecurringSection (with RecurringSplitEditor) supersedes this
  branch's split editor; the anchoring rules are ported onto it: start-date
  validation via startDateNeedsDay, month precision hidden for lastCharge,
  the anchoring control locked once a cost has charges.
- PurchaseDialog keeps main's placement control. The "Recurring cost" select
  replaces main's "Unlink from bill" checkbox, since "None" does the same.
  A bill created from the dialog nests under its post like one from Settings.
- Dropped main's "bounded projection ignores invalid confirmations" test: it
  exercised slot confirmations on a lastCharge cost, which no longer exist.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-30 16:51:17 +02:00
Lucas Winther 85a21c58eb feat: place purchases and bills in budget hierarchy 2026-09-30 13:48:49 +02:00
Lucas Winther b0e8145d2e feat: support unassigned purchases and allocation status
Continuous Integration / lint-and-test (push) Successful in 13s
Continuous Integration / docker-build-and-push (push) Successful in 35s
Allow month-only purchases to start finance plans. Keep unbudgeted posts distinct from explicit zero rules in overspend reporting.
2026-09-30 13:10:10 +02:00
Lucas Winther abf57a963f docs: explain budget folder placement and totals 2026-09-30 00:50:42 +02:00
Lucas WintherandClaude Opus 5 49811f6795 docs(recurring): two schedules, and why they must not be unified
AGENTS.md §1's old invariant was half wrong the moment anchored costs lost
their slots: occurrenceDate is identity for calendar only. The replacement says
what each schedule is and, more usefully, warns against collapsing them —
that collapse is exactly the bug where paying twice in September pushed the
next charge to November.

§2's termination bullet now describes a defensive assert rather than a live
guard, because the anchored walk steps forward from a real date and the grid
walk never rebases. Also added the anchoring-change-refused-once-charged
guard, which was undocumented in AGENTS.md despite having its own test suite
and UI-level guard.

DECISIONS.md, PRODUCT.md, ARCHITECTURE.md and TODO.md catch up to what
shipped: two projection models and the three guards it deleted, a recurring
cost charging more than once per cycle and being creatable from the purchase
dialog, the anchored walk beside the grid walk, and schema 8 at 730 tests.
The 2026-09-03 spec gets a header note pointing at the new spec and nothing
else — it stays an accurate record of what was decided then.

Demo data seeds two charges in one month on an anchored cost (Car insurance),
so the fixed behaviour is the first thing a screenshot shows.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-06 00:05:36 +02:00
Lucas Winther 405cf0bf2d docs+chore: everyNMonths is n-generic too; stop the demo double-charging Rent
PRODUCT.md described recurring costs as repeating "monthly, every N days,
or every N weeks", understating everyNMonths, which supports an interval
like the other two kinds.

demo-data.ts gave "Rent" both an ordinary monthly purchase and a
never-confirmed recurring cost from 2026-06 onward, so the demo's Rent
Projected read as double-charged for June through September. The ordinary
purchase now stops once the recurring cost exists.
2026-09-04 07:58:09 +02:00
Lucas Winther 0d2aa519b7 docs(recurring): record the invariants and what they cost
Two rules that only review catches, so they go in AGENTS.md §1: occurrences are
computed and never stored, and a confirmation's date and its slot are different
facts. Collapsing the second pair into one field would silently delete the
phone-bill behaviour, which is why it is written down rather than left to the
types.

§2 gets the termination guard. n >= 1 is rejected at both write boundaries
rather than clamped, and the walk throws rather than breaking, because a bill
silently dropped from a budget is worse than a visible error.

Demo data seeds a monthly rent and a 28-day subscription — the second is what
puts two occurrences in one month, which is the case worth looking at. It also
seeds a biweekly cost and a lastCharge-anchored one, so every recurrence kind
and both anchorings show up in Settings and the month view.

DECISIONS.md, PRODUCT.md, ARCHITECTURE.md and TODO.md are updated to match:
schema is at 7, the month view carries a second Projected balance beside
Remaining, and TODO.md records what a week of real use — not a test — will
have to answer.
2026-09-03 19:03:35 +02:00
Lucas WintherandClaude Opus 5 d83edccc79 docs: move the long-form docs into docs/, without the superpowers nesting
ARCHITECTURE, PRODUCT and TODO move out of the repository root, and
docs/superpowers/{specs,plans} flattens to docs/{specs,plans}:
"superpowers" names the tool that wrote those documents, not a kind of
document.

No content changes. This commit is the move, plus the roughly thirty
cross-references the move invalidated.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-02 21:56:59 +02:00