# TODO Work still queued, for whoever picks it up next, human or agent. Ordered. Each item says enough to act on without re-deriving the reasoning. Finished work is not listed here. It is in the commit messages, and the decisions behind it are in `docs/specs/` — one spec per sub-project, each recording the alternatives that were rejected. Rules that outlived their task moved to `AGENTS.md`. **Current feature worktree state:** budget folders and recurring cost placement are implemented. 707 tests passing across 54 files. `bunx tsc --noEmit` is clean; `bun run --bun build` succeeds using the committed seed rates when live-fetch is unavailable. The runtime override bypasses a broken local Bun shim. **Schema is at version 8.** v1 -> v2 made allocation rules a dated series; v2 -> v3 moved currencies into the dataset; v3 -> v4 drops a stored rate-service URL that can no longer work; v4 -> v5 adds sterling to an existing dataset; v5 -> v6 collapses per-currency decimals into one dataset-wide setting; v6 -> v7 adds `Dataset.recurring`; v7 -> v8 adds budget folders and assigns existing posts and recurring bills a deterministic mixed sibling order under Unfiled. All seven are behaviour-preserving by construction — not one changes a stored figure — and are tested as such. A migration applies **on load, in memory**; it is written back on the next mutation, not by `load()` itself. So a freshly migrated dataset shows the new shape immediately while IndexedDB still holds the old version for a while. That is not a bug, but it will mislead you if you verify a migration by reading IndexedDB instead of the app. --- ## 1. Folder rename blur during an in-flight save A folder name draft can remain unsaved if the owner changes it while a rename save is in flight and then blurs the field before that save finishes. Preserve the newer draft and ensure the blur requests a subsequent save after the pending write completes. Cover the delayed-write sequence with a UI interaction test, including the final persisted name and any surfaced write error. ## 2. Recurring split editor interaction coverage `RecurringSplitEditor` has coverage for destination selection and dedicated post creation, but its rendered split mode and value controls lack a focused interaction test. Exercise the real controls to switch percentage/fixed mode and edit a split value, then assert the resulting splits and remainder behavior. Keep this scoped to the editor's user interaction; domain split calculations already have their own tests. ## 3. Visual redesign, sub-project 3 — Year, Summary, Post detail The owner's brief for the whole redesign: *"right now it looks a bit boring, simple and ugly. We want sleek, modern, and nice to use."* On scoping: both themes with a toggle, a full rethink of every screen, purchases compact and grouped by date, ship a webfont — and *"override everything you want for this step."* Sub-projects 1 (design foundation, `bb3c661`) and 2 (month view, `7b71811`) are done, each with a spec in `docs/specs/`. These three screens are on the new foundation but have not been rethought. The open question is the 12-month matrix: it only fits by scrolling, and compact number formatting may be what replaces that rather than a scroll container. **The diagnosis that shaped the decomposition, which still applies:** a design system already existed and was never wired up. `src/index.css` defined the paper/ink/teal palette with a contract document behind it, while the app painted shadcn's default white and near-black; the tokens reached the screen in two places only. Doing the foundation last is how that happened. Do not repeat it — extend the foundation rather than styling a screen locally. **Three things sub-project 2 settled that these screens should inherit rather than re-decide** (spec: `2026-09-02-month-view-design.md`): - **Meter geometry lives in `src/ui/meterSegments.ts`**, pure and tested, with `` as the only thing that paints it. A third meter belongs there too, not inline in a component. Negatives clamp rather than invert, because a segment of negative width puts the gradient's stops out of order and paints something arbitrary instead of failing. - **Two markups, not one reflowing grid.** The post table is a real `` from `sm:` up and a list of two-line blocks below it. At 390px the layout genuinely stops being a table, and `role="table"` on it would describe rows and columns that no longer exist on screen. The year matrix faces the same question with more columns to lose. - **State the currency once per table, not per cell.** Every figure in the post table is base currency, so `formatSignedAmount` prints bare numbers and the legend names DKK once. This is what stopped "+4,219.61 DKK" wrapping on a phone. `formatMoney` is still right wherever an amount can be in some other currency — every purchase row, for one. ## 4. Visual redesign, sub-project 4 — dialogs and fast entry Untouched. Native `