CLAUDE.md, AGENTS.md, ARCHITECTURE.md and TODO.md all said no browser exists
in this environment, so appearance had never been verified by anyone. Chrome
is on PATH. Its own --screenshot flag is what fails: it fires on the load
event, before this app's async IndexedDB read resolves, and captures a blank
page — which is presumably how the claim took hold.
scripts/screenshot.ts drives CDP instead: waits past the load event, seeds
IndexedDB via --eval-file and reboots the app with --reload, clicks with
--click, applies shadcn's class-based dark palette with --dark, and reports
console errors and uncaught exceptions. A page that renders blank from a
thrown error looks identical to an empty one, so the console output is half
the value.
Two defects found by simply looking:
- The month table's numeric columns had no horizontal padding, so figures ran
into each other: "+7,175.00 DKK4,200.00 DKK". Now padded.
- Dev logged "The script has an unsupported MIME type ('text/html')" on every
boot, because registerServiceWorker asks for sw.js and the "/*" catch-all
answered with the HTML shell. Dev now serves an inert worker.
Confirmed working, first time seen: the carry meter (including red where a post
is overspent), the Task 5 rule-history editor, the Task 6 "change from here"
control, and baked FX rates showing as "manual - 2026-09-01" in Settings.
Recorded in the docs, with the limits stated: this container's fontconfig maps
every generic family to a monospace face, so screenshots need a FONTCONFIG_FILE
override or you will chase a font bug that does not exist; Chrome starts from
an empty profile each run; and no screenshot can judge how a design feels.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
5.4 KiB
TODO
Work queued for whoever picks this up next, human or agent. Ordered. Each item says enough to act on without re-deriving the reasoning.
Current state: branch feature/versioned-rules, 9 commits ahead of main,
not merged, not pushed. 288 tests passing, bunx tsc --noEmit clean,
bun run build succeeds. Versioned allocation rules are COMPLETE, all six
tasks. Neither new editing surface has been seen in a browser — see section 5.
1. Time-versioned allocation rules — DONE, all six tasks
Spec: docs/superpowers/specs/2026-09-02-versioned-allocation-rules-design.md
Plan: docs/superpowers/plans/2026-09-02-versioned-allocation-rules.md
Ledger + extracted briefs: .superpowers/sdd/2026-09-02-versioned-allocation-rules/
| Task | What | Commit |
|---|---|---|
| 1 | Post.rules: RuleVersion[] replaces standingRule |
68712e7 |
| 2 | v1 -> v2 migration | 15dcf93, 1214d2b |
| 3 | setRuleFrom / removeRuleFrom actions |
de128e3 |
| 4 | JSON import validation for the rule series | 1cb91d3 |
| 5 | Rule-history editor in Settings | e3023d0 |
| 6 | "Change from here" control in the month view | f94e458 |
Tasks 3-6 were executed by hand rather than dispatched. Every deviation from the briefs is recorded in the ledger's task log with its reasoning; four of them fixed real defects in the brief code (JSX that would not compile, a component that pre-filled the previous post's rule, a number field that could not be cleared, and missing validation that let a NaN allocation into the fold). Worth a read before reviewing the diff.
Not yet done for this feature: nobody has independently reviewed tasks 3-6, and no browser has seen the two new editing surfaces.
2. Baked FX rates — designed and approved, not built
So a fresh install can convert a EUR purchase on day one instead of erroring.
build.tsfetches DKK/USD/EUR at build time and embeds them viadefine; on any network failure it falls back to committed constants rather than failing the build. Fetched rates getsource: "api"with the build date; the fallback constants getsource: "manual", so Settings never claims a hardcoded number came from an API.- They seed a new dataset only. They must NOT act as a fallback whenever a
rate is missing — that would undo a deliberate decision: clearing a rate
removes the row so
MissingRateErrorsurfaces, instead of silently converting money at a number the user never chose. - Domain purity forces the shape:
createSeedDatasettakes the rates as an argument; the env read lives in a newsrc/store/bakedRates.ts, in the store layer, using thetry/catchaccessor pattern (see CLAUDE.md gotchas).
3. Visual redesign
The owner's words: "right now it looks a bit boring, simple and ugly. We want sleek, modern, and nice to use." Sequencing was their explicit choice: finish all six rules tasks first, then redesign everything.
PRODUCT.md exists and holds product truth. There is no DESIGN.md; the
incumbent visual world is the --budget-* tokens in src/index.css plus the
design contract summarised in ARCHITECTURE.md. A redesign should treat that as
evidence and anti-reference, not as something to preserve.
4. Smaller items, in no particular order
confirmImporthas no.catch(src/ui/routes/settings/DataSection.tsx). A failed import write is an unhandled rejection with no error shown. One line.- PNG icons 192/512 are not shipped, so Chrome's install prompt is incomplete. Binary assets cannot be generated in the agent environment; a human needs to add them.
round2insrc/store/actions.tshardcodes 2 decimals rather than readingCURRENCY_DIGITS. Correct for DKK/USD/EUR; silently wrong the day a non-2dp currency is added. Same latent issue insliceTotal(src/domain/plans.ts).EMPTY_FIGURES(src/domain/fold.ts) is exported non-frozen and returned by shared reference fromfiguresFor. No consumer mutates it today;Object.freezeis a one-line hardening.buildWorkbookcallsmonthViewper (post, month), making a full ODS export O(posts x months^2). Fine at personal-budget scale.- The dev-only
src/manifest.webmanifestplaceholder hardcodesscope: "/". Harmless in production, misleading if you dev-serve under a subpath.
5. Still needs a human
scripts/screenshot.ts drives headless Chrome, so the list here is much
shorter than it was. Seen and confirmed working: the carry meter (it
renders, and shows red where a post is overspent), the rule-history editor in
Settings, the "change from here" control, the baked FX rates arriving in a
fresh dataset, and every route at desktop and mobile widths.
Genuinely outstanding:
- How it looks and feels. A screenshot proves a layout is not broken. It cannot tell you the design is good, and the container's fonts are not the owner's fonts.
- Offline behaviour, the install prompt, and the update prompt. The
dev server now serves a deliberately inert
sw.js, so dev exercises registration but nothing else. - the generated
.odsopening in a real spreadsheet (validated structurally: mimetype first and stored, well-formed XML, numeric cells). - keyboard flow in fast entry — Tab traversal, Backspace-to-remove, and focus placement after a row auto-appends. Drivable over CDP in principle; not yet done.
- GitHub Actions has never been executed.