Repository navigation
Radar spent less time reading things nobody looks at.
Performance (#3)
Three read paths the reader exercises constantly were paying for data that never reaches the screen. Measured on a database at the app's own retention ceiling — 40 feeds, 40,000 entries, roughly 1 GB of article bodies:
| before | after | |
|---|---|---|
/api/stats, cold page cache |
2167 ms | 2.7 ms |
/api/stats, warm |
30 ms | 2.0 ms |
/api/entries?limit=60, cold |
41 ms | 15 ms |
| read from SQLite per list page | 1.32 MB | 21 kB |
/api/catalog during a refresh |
224 ms | 37 ms |
Unread and saved counts no longer scan the database. SUM(is_read = 0) is an expression over every row, so drawing the sidebar meant reading the whole file, article bodies included. Counting each flag separately lets the existing indexes answer as covering indexes. This is one of the first requests made on launch and it re-polls every minute, so the cold figure is the one you feel.
Lists no longer load article bodies. A 60-item page pulled 1.32 MB out of SQLite to produce 32 kB of JSON, on every scroll, filter change and view switch. Lists now read a projection with no body in it. Opening an entry still gets the full text.
Refreshing gives the thread back. Parsing and writing a feed are synchronous, and on the desktop that happens on the same thread that serves the reader, so a refresh made everything else stutter. It now yields between feeds: median latency for an unrelated request during a refresh drops from 267 ms to 173 ms and twice as many get served.
The offline cache is bounded. The service worker put every API response into Cache Storage and never took anything out — every list page under every filter, plus every article ever opened. It is capped now, oldest evicted first.
Window position is written once per drag. On macOS moved is an alias of move, so it arrived on every frame of a drag and each one did a synchronous file write.
Mobile install (#2)
PWA installation assets are exposed to mobile installers, so the icon and standalone metadata resolve correctly when installing from a phone.
Versioning (#4)
/api/health and the MCP server handshake report the real version. Both were hardcoded and not touched by the release workflow, so 0.1.1 and 0.1.2 shipped announcing themselves as 0.1.0.
Installers for macOS, Windows and Linux are attached once the release build finishes.
On Apple Silicon, take the arm64 DMG. The x64 one runs under Rosetta 2 and is noticeably slower.