docs: prune TODO.md, and correct four claims that were no longer true
TODO.md becomes a TODO again: only work that is actually queued. Five of
its seven sections were finished work, and their reasoning has permanent
homes — the rules moved to AGENTS.md (the baked rates seed a new dataset
only, never a fallback), the rest is in the commit messages and the
specs. 215 lines to 131.
The four corrections, all of them things a reader would have believed:
- README said the install prompt could not work because the manifest
"only ships an SVG icon". It has shipped 192x192 and 512x512 PNGs since
f50c65b. Now stated as unverified rather than incomplete, which is what
it actually is.
- TODO said no browser had seen the two rule-editing surfaces, while its
own section 5 listed both as seen and confirmed.
- TODO said "merged to main" when the last three commits were on a
branch.
- scripts/screenshot.ts explained its own existence by saying
ARCHITECTURE.md and TODO.md claim no browser can run here. Both now say
the opposite — partly because of that script.
ARCHITECTURE.md's gotchas section now says AGENTS.md holds the
enforceable form of those rules and this holds the mechanism, so a reader
hitting the overlap knows which is canonical.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
824c2f5f59
commit
a039176aa3
4 files changed
+117
-180
No files matched your search
@@ -8,7 +8,7 @@ your browser — there is no server and no account.
|
||||
|
||||
```bash
|
||||
bun install
|
||||
bun --hot src/index.ts # dev server with hot reload
|
||||
bun run dev # dev server with hot reload, on :3000
|
||||
bun test # run the test suite
|
||||
bun run build # production build into dist/
|
||||
```
|
||||
@@ -37,8 +37,12 @@ the source in the repository settings.
|
||||
|
||||
Everything is stored in this browser's IndexedDB. **Export regularly** from
|
||||
Settings → Your data: the JSON export is both your backup and how you move your
|
||||
budget to another device. Import replaces everything and downloads a backup of
|
||||
your current data first.
|
||||
budget to another device.
|
||||
|
||||
Both destructive actions there — Import, and "Reset everything" — download a
|
||||
backup of your current data before replacing it, and abort if that download
|
||||
fails. Reset puts the app back to a brand-new install: the three starter posts,
|
||||
the DKK/USD/EUR currency table, this month at zero income, no purchases.
|
||||
|
||||
## Known limitations
|
||||
|
||||
@@ -46,12 +50,20 @@ your current data first.
|
||||
browser's site data, or move to a different browser or device, your budget is
|
||||
gone unless you exported it first. The JSON export is not just a nice-to-have
|
||||
backup — it is the only way to move a budget between devices.
|
||||
- **The install prompt is incomplete.** `manifest.webmanifest` currently only
|
||||
ships an SVG icon. Chrome requires PNG icons at 192×192 and 512×512 to offer
|
||||
the "Install app" prompt; until those are added, the app works fine as a
|
||||
regular tab but won't be installable on Chrome/Chromium.
|
||||
- **Installing and offline use are unverified.** The manifest ships the SVG plus
|
||||
192×192 and 512×512 PNG icons, and the service worker demonstrably installs,
|
||||
activates and precaches every asset — but nobody has yet confirmed that Chrome
|
||||
offers its "Install app" prompt, or loaded the app with the network actually
|
||||
cut. It works as a regular tab regardless.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Design: `docs/specs/2026-09-01-budget-app-design.md`
|
||||
- Implementation plan: `docs/plans/2026-09-01-budget-app.md`
|
||||
- `docs/ARCHITECTURE.md` — layers, data flow, and why the non-obvious choices are
|
||||
what they are.
|
||||
- `docs/PRODUCT.md` — who this is for and what must never break.
|
||||
- `AGENTS.md` — the rules for changing this codebase, and the test that catches
|
||||
each one when broken. `CLAUDE.md` and `GEMINI.md` point at it.
|
||||
- `docs/TODO.md` — what is still queued.
|
||||
- `docs/specs/` — one design document per piece of work, each
|
||||
recording the alternatives that were rejected.
|
||||
- `docs/plans/` — task-by-task implementation plans.
|
||||
+10
-2
@@ -126,6 +126,10 @@ Adding a "missing" guard here is a regression, not a fix:
|
||||
|
||||
## Gotchas paid for with real bugs
|
||||
|
||||
`AGENTS.md` §2 carries the enforceable one-line form of these, with the test
|
||||
that fails when each reappears. What follows is the *mechanism* behind them,
|
||||
which is the part worth reading once.
|
||||
|
||||
- **Never read `event.target.value` inside a `mutate()` callback.** `mutate`
|
||||
defers behind the queue and a write; React resets a controlled input's DOM
|
||||
value long before the callback runs, so you read the *old* value and commit
|
||||
@@ -175,7 +179,11 @@ timing that happy-dom does not reproduce.
|
||||
|
||||
## Where the reasoning lives
|
||||
|
||||
- `AGENTS.md` — the rules, in enforceable one-line form, and which test fails
|
||||
when one is broken. This file holds the reasoning; that one holds the rule.
|
||||
- `docs/PRODUCT.md` — durable product truth: who it is for, what must never break.
|
||||
- `docs/TODO.md` — queued work, with the reasoning behind each decision already made.
|
||||
- `docs/specs/` — design decisions and the alternatives rejected.
|
||||
- `docs/TODO.md` — what is *still* queued, each item carrying the reasoning already
|
||||
settled. Finished work is not kept there; it is in the commit messages.
|
||||
- `docs/specs/` — design decisions and the alternatives rejected, one document
|
||||
per piece of work.
|
||||
- `docs/plans/` — task-by-task implementation plans.
|
||||
+80
-164
@@ -1,13 +1,16 @@
|
||||
# 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.
|
||||
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.
|
||||
|
||||
**Current state:** merged to `main`. 443 tests passing, `bunx tsc --noEmit`
|
||||
clean, `bun run build` succeeds on both the live-fetch and offline paths.
|
||||
Sections 2, 4 and 7 are DONE. Section 3 (redesign) is 2 of 4 sub-projects in.
|
||||
Section 6 (currencies) is DONE. Every screen has now actually been looked at —
|
||||
see section 5.
|
||||
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 state:** 443 tests passing, `bunx tsc --noEmit` clean, `bun run build`
|
||||
succeeds on both the live-fetch and offline paths. The month view redesign and
|
||||
the reset button are on branch `month-view-and-reset`, not yet merged to `main`.
|
||||
|
||||
**Schema is at version 3.** v1 -> v2 made allocation rules a dated series;
|
||||
v2 -> v3 moved currencies into the dataset. Both migrations are
|
||||
@@ -15,79 +18,31 @@ behaviour-preserving by construction and tested as such.
|
||||
|
||||
---
|
||||
|
||||
## 1. ~~Time-versioned allocation rules~~ — DONE, all six tasks
|
||||
## 1. Visual redesign, sub-project 3 — Year, Summary, Post detail
|
||||
|
||||
**Spec:** `docs/specs/2026-09-02-versioned-allocation-rules-design.md`
|
||||
**Plan:** `docs/plans/2026-09-02-versioned-allocation-rules.md`
|
||||
**Ledger + extracted briefs:** `.superpowers/sdd/2026-09-02-versioned-allocation-rules/`
|
||||
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."*
|
||||
|
||||
| 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` |
|
||||
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.
|
||||
|
||||
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.
|
||||
**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.
|
||||
|
||||
Not yet done for this feature: nobody has independently reviewed tasks 3-6, and
|
||||
no browser has seen the two new editing surfaces.
|
||||
**Three things sub-project 2 settled that these screens should inherit rather
|
||||
than re-decide** (spec: `2026-09-02-month-view-design.md`):
|
||||
|
||||
## 2. ~~Baked FX rates~~ — DONE (`b4e1933`)
|
||||
|
||||
So a fresh install can convert a EUR purchase on day one instead of erroring.
|
||||
Built as designed, all three build paths verified (live fetch, unreachable
|
||||
endpoint, `SKIP_FX_FETCH=1`), and confirmed in the real UI: Settings shows
|
||||
USD 6.449532 / EUR 7.474959 as `manual · 2026-09-01` on a fresh dataset.
|
||||
The reasoning below is kept because it is the reasoning, not a plan.
|
||||
|
||||
- `build.ts` fetches DKK/USD/EUR at build time and embeds them via `define`;
|
||||
on any network failure it falls back to **committed constants** rather than
|
||||
failing the build. Fetched rates get `source: "api"` with the build date;
|
||||
the fallback constants get `source: "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 `MissingRateError` surfaces, instead of silently
|
||||
converting money at a number the user never chose.
|
||||
- Domain purity forces the shape: `createSeedDataset` takes the rates as an
|
||||
**argument**; the env read lives in a new `src/store/bakedRates.ts`, in the
|
||||
store layer, using the `try/catch` accessor pattern (see AGENTS.md gotchas).
|
||||
|
||||
## 3. Visual redesign — sub-projects 1 and 2 of 4 DONE
|
||||
|
||||
The owner's words: *"right now it looks a bit boring, simple and ugly. We want
|
||||
sleek, modern, and nice to use."* Then, 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."*
|
||||
|
||||
**Spec:** `docs/specs/2026-09-02-design-foundation-design.md`
|
||||
|
||||
**The diagnosis, which should shape the rest:** 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.
|
||||
|
||||
| # | Sub-project | State |
|
||||
|---|---|---|
|
||||
| 1 | Design foundation — two-theme tokens, theme toggle, self-hosted Inter + JetBrains Mono, one Section/Stat card, table furniture | DONE (`bb3c661`) |
|
||||
| 2 | Month view | DONE. Date-grouped purchases (`a159189`), then the header, the post rows and the carry meter |
|
||||
| 3 | Year, Summary, Post detail | on the new foundation but not rethought. The 12-month matrix only fits by scrolling — decide whether compact number formatting replaces that |
|
||||
| 4 | Dialogs and fast entry | untouched. Native `<select>` elements are still browser-default, and `up`/`down`/`archive` are bare text buttons |
|
||||
|
||||
**Sub-project 2, for whoever does 3 and 4.** Spec:
|
||||
`docs/specs/2026-09-02-month-view-design.md`. Three things it
|
||||
settled that the reporting screens should follow rather than re-decide:
|
||||
|
||||
- **Meter geometry is `src/ui/meterSegments.ts`**, pure and tested, with
|
||||
- **Meter geometry lives in `src/ui/meterSegments.ts`**, pure and tested, with
|
||||
`<Meter>` 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
|
||||
@@ -96,120 +51,81 @@ settled that the reporting screens should follow rather than re-decide:
|
||||
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 and has more columns to lose.
|
||||
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.
|
||||
|
||||
Also worth knowing: `src/ui/cssTokens.test.ts` matches source *text*, so it
|
||||
flags a token named in a code comment as readily as one in a `style` — which is
|
||||
exactly what it did to the comment explaining it.
|
||||
## 2. Visual redesign, sub-project 4 — dialogs and fast entry
|
||||
|
||||
**Watch for:** the brand teal is `--primary`, never `--accent` — shadcn's
|
||||
`--accent` is a hover *background* whose paired foreground must move with it.
|
||||
`src/cssPairs.test.ts` enforces the pairing, and `src/ui/cssTokens.test.ts`
|
||||
fails if a component names a token `index.css` does not define. That second
|
||||
guard exists because renaming `--rule` silently made the carry meter paint
|
||||
nothing: an undefined custom property inside `linear-gradient()` invalidates
|
||||
the whole declaration without warning.
|
||||
Untouched. Native `<select>` elements are still browser-default, and
|
||||
`up` / `down` / `archive` in Settings are bare text buttons. Covers the purchase
|
||||
dialog, the split editor, the plan editor and bulk entry.
|
||||
|
||||
## 4. ~~Smaller items~~ — ALL DONE
|
||||
There is already a spec for fast-entry *behaviour* —
|
||||
`2026-09-02-fast-entry-refinements-design.md`. Read it before restyling, so the
|
||||
visual work does not fight it.
|
||||
|
||||
All six, `b9be882` / `71e8fc9` / `f50c65b`. Three were worse than recorded:
|
||||
## 3. Currency work deliberately left undone
|
||||
|
||||
- `confirmImport` now guards its write, and a source-level check covers the
|
||||
whole UI (`b9be882`).
|
||||
- The PNG icons **were** generatable here — Chrome is on PATH and rasterizes
|
||||
the SVG exactly. `scripts/make-icons.ts` produces them; they are committed,
|
||||
precached, and pixel-verified against the source (`f50c65b`).
|
||||
- Split values now round by what they MEAN — money in "fixed" mode, a
|
||||
percentage in "percent" mode. Narrower than the note claimed: `round2` was
|
||||
always right for `Rule.percent`, which is not money (`b9be882`).
|
||||
- `EMPTY_FIGURES` is frozen (`b9be882`).
|
||||
- The ODS export was **not** "fine at personal-budget scale": 30 posts over 10
|
||||
years took 7983 ms synchronously on the main thread. Now 135 ms, with
|
||||
byte-identical output (`71e8fc9`).
|
||||
- The dev manifest did not merely hardcode `scope: "/"` — it was never served
|
||||
at all; the catch-all answered with the HTML shell. One definition now feeds
|
||||
the build and the dev server (`b9be882`).
|
||||
|
||||
## 6. ~~User-defined currencies, and amounts that carry their currency~~ — DONE
|
||||
|
||||
Both `cdece63`. `Currency` is an open string code and `Dataset.currencies` is
|
||||
the authority on validity, symbols and decimal places; the purchase total
|
||||
field reads "30$" as USD 30.
|
||||
|
||||
**The part worth knowing before touching money again:** `roundMoney(amount,
|
||||
digits)` takes a digit count, and its ~29 call sites each resolve digits from
|
||||
the dataset with `digitsFor`. The argument is required deliberately — every
|
||||
currency the app shipped with uses two decimals, so a default of 2 would leave
|
||||
a missed call site passing every test and silently wrong for the first
|
||||
zero-decimal currency added. `src/domain/currencyDigits.test.ts` is the only
|
||||
test that can tell a real implementation from one that assumes 2: it drives a
|
||||
JPY-style currency through rounding, both FX directions, both split modes,
|
||||
plan division, the fold and the month view.
|
||||
|
||||
Left undone, deliberately:
|
||||
All three were decided against at the time, not forgotten. Reopen only with a
|
||||
reason.
|
||||
|
||||
- **The income field and the split editor's fixed-amount fields do not parse a
|
||||
currency yet** — only the purchase total does. Same helper
|
||||
(`parseMoneyInput`), same three-line pattern; the income field is arguably
|
||||
wrong to make multi-currency at all, since a month has one income.
|
||||
- **No currency picker convenience.** Adding one means typing the code, name,
|
||||
symbol and decimals by hand. A bundled ISO 4217 list would be nicer, and is
|
||||
pure data.
|
||||
currency** — only the purchase total does. Same helper (`parseMoneyInput`),
|
||||
same three-line pattern. The income field is arguably wrong to make
|
||||
multi-currency at all, since a month has one income.
|
||||
- **No currency picker convenience.** Adding a currency means typing the code,
|
||||
name, symbol and decimals by hand. A bundled ISO 4217 list would be nicer, and
|
||||
is pure data.
|
||||
- **Symbol collisions resolve to the first currency defined with that symbol.**
|
||||
Fine for one "$" currency; if the owner adds two, typing the code
|
||||
disambiguates and nothing warns them. Tested, documented, not solved.
|
||||
|
||||
## 7. ~~Reset to a fresh install~~ — DONE
|
||||
## 4. Nobody has independently reviewed the rule-history editing surfaces
|
||||
|
||||
Settings > Your data > "Reset everything…". The owner asked for a reset that
|
||||
includes the currencies and the seed categories, and chose fresh-install state
|
||||
over an empty dataset: the three starter posts, the DKK/USD/EUR table, the
|
||||
baked rates, this month at zero income, no purchases.
|
||||
Tasks 3-6 of the versioned-allocation-rules work — `setRuleFrom` /
|
||||
`removeRuleFrom`, the JSON import validation, the Settings rule-history editor,
|
||||
and the month view's "change from here" — were executed by hand rather than
|
||||
dispatched, and no second pair of eyes has been over the diff.
|
||||
|
||||
- `store.reset()` calls the same `createSeedDataset(currentMonth, seedRates)`
|
||||
that `load()` uses on a first run, through the same write queue. Seeding
|
||||
lives in the store, not the UI, so "reset" and "a brand-new browser" cannot
|
||||
drift apart.
|
||||
- The confirm panel reuses the import flow's shape and its **order of
|
||||
operations**: the JSON backup downloads BEFORE the destructive write, and a
|
||||
backup that fails aborts the reset. This is the user's only copy.
|
||||
- Verified in Chrome by clicking through and reading IndexedDB back: 3 seed
|
||||
posts, DKK/USD/EUR, both baked manual rates, 0 purchases, one month at zero
|
||||
income.
|
||||
Worth reading first: the task log in
|
||||
`.superpowers/sdd/2026-09-02-versioned-allocation-rules/` records every deviation
|
||||
from the original briefs 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.
|
||||
|
||||
Both surfaces have since been seen working in a browser. What is missing is
|
||||
review, not verification.
|
||||
|
||||
## 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.
|
||||
`scripts/screenshot.ts` drives headless Chrome, so this list is much shorter
|
||||
than it was. Already seen and confirmed working: the carry meter (including red
|
||||
where a post is overspent), the rule-history editor, "change from here", the
|
||||
baked FX rates arriving in a fresh dataset, the reset writing a fresh dataset to
|
||||
IndexedDB, and every route at desktop and mobile widths in both themes.
|
||||
|
||||
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** and the **install prompt**. The service worker itself
|
||||
is no longer unverified: it demonstrably installs, activates, claims the
|
||||
page, precaches all 11 assets, and applies an update cleanly (`e6da85e`) —
|
||||
before that fix it had never installed once, in any environment, because
|
||||
`cache.addAll` rejects on a duplicate request. What is still unverified is
|
||||
a real offline load with the network actually cut, and Chrome's install
|
||||
prompt appearing.
|
||||
- the generated **`.ods` opening in a real spreadsheet** (validated
|
||||
structurally: mimetype first and stored, well-formed XML, numeric cells).
|
||||
- **the pre-destructive backup actually landing as a file.** Both the import
|
||||
and the reset flow download a JSON backup before replacing the dataset, and
|
||||
the code path demonstrably runs (the reset proceeds only when it returns
|
||||
success). Whether headless Chrome wrote the file is not observable here, so
|
||||
nobody has yet confirmed the backup is openable — only that it was issued.
|
||||
- **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.
|
||||
- **Offline behaviour** and the **install prompt**. The service worker itself is
|
||||
no longer unverified: it demonstrably installs, activates, claims the page,
|
||||
precaches all 11 assets, and applies an update cleanly (`e6da85e`). What is
|
||||
still unverified is a real offline load with the network actually cut, and
|
||||
Chrome's install prompt appearing.
|
||||
- **The pre-destructive backup actually landing as a file.** Import and reset
|
||||
both download a JSON backup before replacing the dataset, and only proceed
|
||||
when that reports success — but headless Chrome's download is not observable
|
||||
here, so the backup is *issued*, never confirmed openable.
|
||||
- **The generated `.ods` opening 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.
|
||||
@@ -7,11 +7,12 @@
|
||||
* [--eval=<js>|--eval-file=<path>] [--dark] [--reload]
|
||||
* [--profile=<dir>] [--eval-after-file=<path>]
|
||||
*
|
||||
* Why this exists: docs/ARCHITECTURE.md and docs/TODO.md both say nothing here can run a
|
||||
* browser, so appearance has never been verified. Chrome IS available, but its
|
||||
* plain `--screenshot` flag fires on the load event — before this app's async
|
||||
* IndexedDB read resolves, which captures an empty page. Driving CDP directly
|
||||
* lets us wait, act, and read console errors.
|
||||
* Why this exists: the docs used to say nothing here could run a browser, so
|
||||
* appearance went unverified for a long time. Chrome IS available — but its
|
||||
* plain `--screenshot` flag fires on the load event, before this app's async
|
||||
* IndexedDB read resolves, so it captures an empty page, which is how that
|
||||
* belief survived. Driving CDP directly lets us wait, act, and read console
|
||||
* errors.
|
||||
*
|
||||
* This does NOT replace a human: it cannot judge feel, and it renders with one
|
||||
* font stack on one platform. It does prove a layout exists and is not broken.
|
||||
|
||||
Reference in new issue
Block a user