Commit Graph
9 Commits
Author SHA1 Message Date
Lucas Winther 7cccd7a41a feat: add month breakdown and session backups
Continuous Integration / docker-build-and-push (push) Successful in 35s
Continuous Integration / lint-and-test (push) Successful in 17s
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 d3c14857fc feat: show budget folders on month page 2026-09-30 00:50:42 +02:00
Lucas Winther c34aa846b9 feat: add budget folder schema and migration 2026-09-29 20:25:47 +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
Lucas WintherandClaude Opus 5 bd5a01e03e chore(tooling): make the screenshot recipe work with no setup
Two things this session depended on lived only in a scratchpad, so the next
agent would have had to reinvent them from a prose hint:

- scripts/screenshot-fonts.conf, now applied by screenshot.ts itself. Without
  it this container renders every generic font family as Fira Code and the UI
  looks monospaced in a way no user sees — a trap that nearly produced a "fix"
  for a font bug that does not exist.
- scripts/demo-data.ts, which seeds a visibly synthetic dataset. Without it
  every screenshot shows an app full of zeros, because Chrome starts from a
  fresh profile each run.

CLAUDE.md now carries the two-command recipe verbatim instead of "point
FONTCONFIG_FILE at an override", and says why --reload is mandatory. Verified
from a clean shell with no environment set.

Also flags docs/superpowers/plans/2026-09-01-budget-app.md as a historical
record: its snippets still show CURRENCIES and CURRENCY_DIGITS, which no
longer exist, and an agent reading it as current would be misled.

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