Files
Michael Freno 26729fa5e6 feat(feed): make episode cache bound user-configurable (date window or count)
Add episodeCacheMode/count/days preferences (default: date, 60 days).
Apply the bound when reading instead of writing, so a preference change
takes effect without a refetch; the full parse cache stays intact so
fetch-more can page beyond the bound. Thread the window through
load/saveFeedsToFile and update tests and task docs.
2026-08-12 15:41:22 -04:00

1.8 KiB

Bounded Feed Lifecycle

Objective: Bound feed episode storage to a rolling 30-day persisted window (older episodes volatile-only unless downloaded), keep feed loading nonblocking, and surface all load/download activity in a global top-right indicator.

Status legend: [ ] todo, [~] in-progress, [x] done

Tasks

  • 01 — persisted-retention-window → 01-persisted-retention-window.md
  • 02 — volatile-episode-merge → 02-volatile-episode-merge.md
  • 03 — nonblocking-feed-refresh → 03-nonblocking-feed-refresh.md
  • 04 — global-activity-indicator → 04-global-activity-indicator.md

Dependencies

  • 02 depends on 01 (the volatile merge preserves exactly what 01 drops from disk)
  • 03 depends on 01 (debounced persistence layers onto the pruning save path)
  • 03 depends on 02 (incremental per-feed apply consumes the merge helper from 02)
  • 04 depends on 03 (the indicator subscribes to the activity wiring added across refresh/load-more paths in 03)

Exit criteria

  • After any refresh + save, config.json feeds[*].episodes contains only episodes with pubDate within the last 30 days or episodes marked completed in downloads.json; loading a legacy config prunes stale episodes on first launch.
  • The volatile episode list and pagination cache are bounded by the same 30-day window as persistence: only in-window episodes are cached/loadable, and everything in-window is (no episode-count ceiling).
  • A refresh batch never exceeds a fixed fetch concurrency, applies each feed's result as it lands (no Promise.all barrier), and persistence writes are debounced; keyboard input stays responsive throughout.
  • The top-right indicator is visible iff at least one feed refresh, fetch-more, subscribe fetch, search, or episode download is in flight, hidden otherwise.
  • bun test and bun run lint pass.