# To do ## Errors in the log Checked production on 2026-09-14: 76 of 1,102 feeds carry a stored error. 55 are stale entries on the `davewiner` OPML's derived feeds, from before it left `config.toml` -- confirmed that fix is actually working: those feeds stopped being scanned six hours ago and the old error text was just never cleared. Of the rest, everything with a subscriber classifies cleanly through `explain_failure` (404, 401/403, DNS gone, a web page in place of the feed) except one: - [ ] **Explain a feed that fails to parse, not just one that fails to fetch.** `explain_failure` (`src/feed.rs:107`) turns an HTTP status or a DNS failure into a plain-English reason, but a feed that comes back 200 and then fails to parse as RSS or Atom falls through to `None` -- no reason, no suggested fix, ever, even after it has failed for a day. `doghouse` (`http://feeds2.feedburner.com/thedoghousediaries/feed`) is failing that way right now: "not RSS (reached end of input without finding a complete channel) and not Atom (unexpected end of input)" -- could be a permanently broken feed or a publisher that occasionally truncates the response; either way, once `FLAG_AFTER_SECS` (`src/web.rs:508`) passes a subscriber gets nothing in the sidebar, unlike every other failure class. Add a generic "this feed isn't coming back clean" reason for the parse-failure case, same as the others get. (`src/feed.rs`) ## Directory Overhaul - [ ] **Give feeds a real category, from the feed itself.** `ParsedFeed` only carries per-episode `categories` (`src/feed.rs:24`); nothing at the channel level survives parsing today, so there is nothing to browse the directory by. Parse `` (and its `` if present) off the channel the same way entry categories already are, keep the first one a feed reports rather than building a multi-tag facet, and add it to `FeedSummary` and the feeds table via a migration. Most feeds will not carry one; a feed with none counts only under "All". (`src/feed.rs`, `src/db.rs`) - [ ] **Expose category on `/api/popular` and `/api/directory`.** `PopularRow` (`src/web.rs`) is id, title, image, subscribers, subscribed today; add `category: Option` once a feed carries one, so the client can group and filter without a second request. - [ ] **Replace the flat alphabetical list with a category rail over an artwork grid.** Today Directory is a single-column list of rows: a thumbnail, a title, a subscriber count, a subscribe button (`renderListed`/`listFeeds`, `web/index.html:1649`). Put a horizontal row of category chips above it — "All" plus whatever categories actually occur in the catalogue, never an empty one — and turn the list itself into a grid of square cover-art tiles with the title underneath: podcast art is designed to be recognized at a glance, the way the app's own iPod-screen styling already leans on imagery over text. Keep the subscriber count as a small corner badge (the same treatment `unread` counts already get in the feed list) and move the subscribe button to appear on hover/focus instead of sitting on every row permanently. Selecting a chip filters the grid in place; the active chip gets the EQ-amber underline (`--accent2`) the level meter already uses, rather than a new color. No new palette and no new typeface — reuse `--bg`/`--fg`/`--accent`/ `--accent2` and the existing Lucida Grande stack so Directory still looks like the rest of ipx, not a bolted-on card kit: no border, shadow or radius beyond what the app already uses elsewhere. On phone width the chip row scrolls horizontally in place rather than wrapping, so it never pushes the grid down. Popular can stay a plain top-ten list for now, or get the same tile treatment later — worth deciding separately rather than folding into this. (`web/index.html`)