Live-verified against the backend API: 13/20 top stories are 5+ days old by firstSeenAt but still score 90+. Freshness decays from lastUpdatedAt (cluster last touched) instead of the actual news event age, and it compounds with the known over-clustering bug (#2) — tangential articles keep attaching to old clusters, resetting their clock indefinitely. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.4 KiB
Backlog & status
Source-of-truth tracker. The Gitea issue tracker is currently empty (0 issues) —
run scripts/create-issues.sh with a token to populate it. [client] = iOS,
[backend] = the platform service on the Docker host, [ci] = build/test.
Status: 🔴 open · 🟡 mitigated client-side (real fix still pending) · 🟢 done.
Backend — data quality (highest priority)
- 🟡 [backend] F1 mis-classified into tech/finance/politics. No sport category, so
F1 (100% F1 sources) scatters across topics: "Monaco Grand Prix…" →
tech, "F1 reports 35% CO2…" →finance, "McLaren launch appeal…" →politics. Add asport/f1topic and route motorsport sources there. Client mitigation shipped: F1 pill matches clear F1 headlines + a majority of F1 sources, and F1 is excluded from All/Tech/Finance. Backend still mis-tags. - 🔴 [backend] Catastrophic over-clustering — unrelated articles merged on a single shared word. Newly confirmed on-device: a story merged a Russian-film-director article + "Who's afraid of Michael Jackson?" + "Chelsea Jackson Roberts" (wellness) — grouped on the surname Jackson. Another merged "Gunfire at Niger airport" + "L.A. County Whiteman Airport crash" + "Niger fintech". Result: wrong headline, summary, topic, and inflated signal. Raise the TF-IDF threshold hard (~0.22 → 0.45–0.55) and require multiple shared distinctive terms / named-entity overlap, with a tight time window. If still over-merging, move to sentence embeddings (all-MiniLM-L6-v2, cosine ≥ ~0.6). Make canonical headline + summary come from the same representative article. No client fix is possible — the story object itself is wrong.
- 🔴 [backend] Add accurate per-story tags (topic + region). So the client can read tags (sport, uganda, south-africa, …) instead of keyword-guessing. Unblocks #6.
- 🔴 [backend] Topic-classifier coverage for the 47 feeds. science/world/tech mapping.
- 🔴 [backend] Freshness score decays from
lastUpdatedAt(cluster last touched), not from the actual news event age — old stories never leave the top of the feed. Confirmed live on/api/v1/stories: 13 of the top 20 stories are 5+ days old byfirstSeenAtbut still score 90+; the #1 story (story_511c67eb064d) hasfirstSeenAt: 2026-06-17,lastUpdatedAt: 2026-07-09(21 days later),freshnessScore: 1.0, signal 100. Compounds with #2 (over-clustering): a loose cluster keeps absorbing tangential articles indefinitely (this story's timeline includes "Security forces ready for June 30 marches: Ramaphosa" — unrelated to the football story it's attached to), each attachment resetslastUpdatedAtto now, so the cluster's clock never runs out and its canonical headline drifts to whatever was clustered last (list view showed "South Africa stun South Korea…"; story detail showed "Updated FIFA rankings after Bafana Bafana exit" for the samestory_id). Fix: decay freshness fromfirstSeenAt(or the newest article whose relevance to the cluster core is verified), not from "last touched." Tightening the TF-IDF threshold in #2 should also reduce how often unrelated articles keep a stale cluster's clock alive. No client fix possible — the story object's freshness field itself is wrong before it reaches the app.
Backend — features
- 🔴 [backend] Server-side push for breaking alerts (APNs or ntfy). For breaking-story notifications while the app is closed. Client does local notifications + background refresh only.
Client
- 🔴 [client] Move interest filters server-side once tags (#3) exist. Today's pills are client-side keyword/headline matches on loaded stories. Refined since: regions match headline-only (no polluted summaries/outlets), regions exclusive, F1 by source majority, East Africa removed.
- 🔴 [client] SSID-based trusted networks. Needs Access WiFi Information entitlement (device + paid account). Approximated by LAN reachability today.
- 🔴 [client] Optional in-app WireGuard tunnel. NetworkExtension; entitlement + device. Deferred.
- 🔴 [client] App icon + launch assets.
AppIconis an empty placeholder. - 🔴 [client] Flesh out Latest / Search tabs. Saved is now bookmarks; Latest/Search still minimal.
- 🔴 [client] Verify hero image loading.
AsyncImagevs real feedimageUrls. - 🔴 [client] Offline-first polish. Pre-cache top stories.
CI
- 🔴 [ci] Add unit/UI tests + a test matrix leg. Build matrix compiles, runs no tests.
- 🔴 [ci] Backend CI build matrix. Python 3.11–3.13 + lint + Docker build/health probe.
🟢 Shipped
Signal feed + detail + reader + feed manager · LAN⇄Tailscale connectivity · notifications
(morning/evening briefings + breaking alerts) with Open-Meteo weather · device code signing
· feed resilience (no blank-on-refresh, ignore cancelled, coalesced WS refresh) · clearer
empty states (polling / unreachable+host / offline / caught-up) · deterministic feed order ·
6-line summary preview · pinned filters (F1 split out, regions exclusive & headline-matched,
Finance/Tech by topic) · swipe actions (short→Save / long→Mark read, right→Share) ·
read/seen handling (seen-tracking with per-load snapshot, read stories collapse into a
"Read" shelf with compact rows, "all caught up" state).