From 94e7a189b68f1bc3dbd7c65b5319e881f9ec2cdf Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Thu, 3 Sep 2026 03:29:39 +0200 Subject: [PATCH] docs(plans): task-by-task plan for recurring costs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ten tasks. One through five are the domain and run in strict order: day arithmetic, types and the 6 -> 7 migration, the occurrence walk, expected charges, then the fold's second track. Six and seven (actions, import validation) need only the types. Eight and nine are the two UI surfaces. Ten is demo data, documents and screenshots. Task 2 deliberately leaves one test red. The behaviour-preservation guard — every post in every month folds identically, projected equal to remaining — is written where the risk is created and goes green in task 5, where the field it asserts on exists. Writing it out caught four things the spec could not: - A fold assertion of -4000 where the accumulators give 4000. Left in, the implementer would have changed working code to match a wrong expectation. - A second reachable cause for the walk's termination throw. Under lastCharge, a confirmation dated more than one step before the slot it claims moves the cursor backwards; a valid calendar series never can. The message now names both causes, because they need different fixes, and there is a test. - parseMoneyInput takes (text, options, fallback). The options list is what makes "30$" resolve to USD rather than the fallback. - demo-data.ts builds through actions.*, not literals, so the seeding task uses addRecurringCost with the ids already in scope. Task 10 ends by stating what screenshots do NOT prove: how it looks and feels, the overdue count against a real backlog, and whether two-stage confirmation matches how the owner actually reconciles. --- docs/plans/2026-09-03-recurring-costs.md | 3037 ++++++++++++++++++++++ 1 file changed, 3037 insertions(+) create mode 100644 docs/plans/2026-09-03-recurring-costs.md diff --git a/docs/plans/2026-09-03-recurring-costs.md b/docs/plans/2026-09-03-recurring-costs.md new file mode 100644 index 0000000..e92be97 --- /dev/null +++ b/docs/plans/2026-09-03-recurring-costs.md @@ -0,0 +1,3037 @@ +# Recurring Costs Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Bills that repeat — rent monthly, a subscription every 28 days, a phone bill every 30 days whose clock restarts when the data cap is hit — project as *expected* charges and are confirmed into real purchases when the money moves. + +**Architecture:** A new `RecurringCost` entity projects occurrence dates through a pure walk (`src/domain/occurrences.ts`) built on new pure day arithmetic (`src/domain/days.ts`). Occurrences are computed on every fold and never stored. The fold gains a second balance track — `projected` alongside `remaining` — fed by unconfirmed occurrences. Confirming one writes an ordinary `Purchase` carrying `source: { recurringId, occurrenceDate }`, which suppresses that slot on the next fold. + +**Tech Stack:** Bun (runtime, test runner, bundler, package manager), TypeScript, React 19, Tailwind 4, shadcn/ui. No new dependencies. + +**Spec:** `docs/specs/2026-09-03-recurring-costs-design.md` — read it before Task 1. The plan argues from the spec; where they disagree, the spec wins and the plan is wrong. + +## Global Constraints + +Copied verbatim from `AGENTS.md`. Every task's requirements implicitly include these. + +- **Bun only.** `bun test`, `bun install`, `bun run