Local-first Brief: the landing leads with good news from your home

Per the owner's call (overrides the earlier "Brief sacred" stance): when a home is
set, the homepage opens with local good news first, not global. This is the hook —
you land and see awesome stories from YOUR corner first.

- queries.home_brief: local-first highlights (high/medium-confidence near, blended
  out to country then world so it's always a full, strong set), preferring already-
  summarized stories so the calm read stays rich. Recent window, ranked within tier.
- /api/brief gains a `home` param: private/no-store when set; over-fetches + caps so
  dismissal/boundary filtering never thins it; falls back to global top-up if needed.
- Landing UI: a Local <-> Global toggle ("📍 Near you / 🌍 Everywhere") when a home
  is set, the calm picker invite when not (dismissible), and Change. Default leads
  local; one tap back to the global brief. No home set => exactly today's behavior.

Backend + frontend tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-19 21:36:18 -04:00
parent 2239549799
commit d2a6293a13
7 changed files with 1784 additions and 16 deletions
+15
View File
@@ -81,6 +81,21 @@ def test_country_only_home_gates_near_on_confidence(app_db):
assert a5["section"] == "world" # low-conf home-country -> world, not vanished
def test_home_brief_leads_with_local(app_db):
# The landing's /api/brief?home=US-NY leads with high-confidence NY good news,
# tags items by section, and titles it "Close to home". The low-conf NY story (#5)
# is not elevated as local.
r = TestClient(app_db).get("/api/brief?home=US-NY&limit=10").json()
assert r["title"] == "Close to home"
near_ids = {it["id"] for it in r["items"] if it["section"] == "near"}
assert near_ids == {1, 2, 3, 4} # the high-conf NY stories
# near items all appear before any world item (local leads)
secs = [it["section"] for it in r["items"]]
if "near" in secs and "world" in secs:
assert max(i for i, s in enumerate(secs) if s == "near") < \
min(i for i, s in enumerate(secs) if s == "world")
def test_no_home_is_unchanged_and_unsectioned(app_db):
r = TestClient(app_db).get("/api/feed?limit=50").json()
assert all(it["section"] is None for it in r["items"])