Scope dial v2: Nearby / Region / Country / World radius on the homepage

Codex-approved evolution: the reader controls the "emotional radius" of the landing.

- Census-region "Regional" grain (geo.region_of / region_states). Scope-aware tiering
  (queries.home_tiers): closest->widest lead, confidence-gated on state + region, never
  a hard filter — blends outward so the set is always full. 'world' = the global brief.
- queries.home_brief takes a scope; /api/brief gains a scope param (nearby|region|
  country|world). Country-only / non-US homes collapse to country.
- Homepage dial replaces the 2-button toggle: adaptive stops (4 with a US state, else
  Country/World), persisted scope, "Good news closest first" framing. Concrete, soft
  section labels (Around New Jersey / Across the Northeast / Across the US / Around the
  world) so the reader sees the dial worked.

Backend 366 + frontend tests green. (Latest feed still on v1 local-first; aligning it
to the dial is the immediate follow-up.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-19 21:59:32 -04:00
parent d2a6293a13
commit 3486f3102a
5 changed files with 168 additions and 61 deletions
+6 -5
View File
@@ -2187,6 +2187,7 @@ def create_app() -> FastAPI:
prefs: str | None = Query(None),
exclude: str = Query("", description="comma-separated article ids the reader has dismissed"),
home: str | None = Query(None, max_length=8, description="local-first highlights: 'US' or 'US-NY'"),
scope: str = Query("nearby", pattern="^(nearby|region|country|world)$", description="radius dial"),
) -> BriefResponse:
# The default highlights are global (date-keyed, no session) → edge-cacheable
# so a new visitor's "Gathering the good news…" resolves from their POP, not
@@ -2203,13 +2204,13 @@ def create_app() -> FastAPI:
now = datetime.now(timezone.utc)
excl = {int(x) for x in exclude.split(",") if x.strip().lstrip("-").isdigit()}
with get_conn() as conn:
if home_country:
# The reader's home leads the landing: local good news first, blended out
# to country/world so it's always a full, sexy set. Over-fetch to survive
# dismissal/boundary filtering, then cap to limit.
if home_country and scope != "world":
# The reader's home + scope dial lead the landing: closest-first good news,
# blended outward so it's always a full set. Over-fetch to survive dismissal/
# boundary filtering, then cap to limit. scope='world' = the global brief.
meta = queries.brief(conn, brief_date=date, limit=1)
data = {"brief_date": meta["brief_date"], "title": "Close to home", "created_at": meta.get("created_at")}
pool = queries.home_brief(conn, home_country, home_state, limit=limit + 12)
pool = queries.home_brief(conn, home_country, home_state, scope=scope, limit=limit + 12)
else:
data = queries.brief(conn, brief_date=date, limit=limit)
pool = data["items"]