Scope dial polish (Codex): hero stays closest-first + visible Clear
- Hero constraint: _pick_lead now runs only within the CLOSEST non-empty section of a personalized Brief, so a "gentler" wider-region/world story can never be floated into the hero slot above a local one. Only widens if the closest section is empty. - Dial gains a visible Clear (alongside Change) so a reader never feels locked into personalization; "World" stays the keep-home-but-go-global option. 366 tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -738,7 +738,10 @@
|
|||||||
<button class="sd-btn" class:on={homeScope === s} onclick={() => setScope(s)}>{label}</button>
|
<button class="sd-btn" class:on={homeScope === s} onclick={() => setScope(s)}>{label}</button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<button class="linkish sd-change" onclick={openHomeEditor}>Change home</button>
|
<span class="sd-actions">
|
||||||
|
<button class="linkish" onclick={openHomeEditor}>Change</button>
|
||||||
|
<button class="linkish" onclick={clearHome}>Clear</button>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<section class="rise">
|
<section class="rise">
|
||||||
@@ -1047,7 +1050,7 @@
|
|||||||
background: var(--bg); color: var(--ink); cursor: pointer; border-right: 1px solid var(--line); }
|
background: var(--bg); color: var(--ink); cursor: pointer; border-right: 1px solid var(--line); }
|
||||||
.sd-stops .sd-btn:last-child { border-right: none; }
|
.sd-stops .sd-btn:last-child { border-right: none; }
|
||||||
.sd-btn.on { background: var(--accent-soft); color: var(--accent-deep); }
|
.sd-btn.on { background: var(--accent-soft); color: var(--accent-deep); }
|
||||||
.sd-change { margin-left: auto; }
|
.sd-actions { margin-left: auto; display: inline-flex; gap: 12px; }
|
||||||
.feed-section { grid-column: 1 / -1; margin: 8px 0 2px; font-family: var(--label); font-size: 0.78rem;
|
.feed-section { grid-column: 1 / -1; margin: 8px 0 2px; font-family: var(--label); font-size: 0.78rem;
|
||||||
text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
|
text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
|
||||||
.grid > .feed-section:first-child { margin-top: 0; }
|
.grid > .feed-section:first-child { margin-top: 0; }
|
||||||
|
|||||||
+10
-1
@@ -2236,7 +2236,16 @@ def create_app() -> FastAPI:
|
|||||||
have.add(a["id"])
|
have.add(a["id"])
|
||||||
# Lead with a gentle, readable story (charged or paywalled stories stay
|
# Lead with a gentle, readable story (charged or paywalled stories stay
|
||||||
# in the set, just not as the first thing seen).
|
# in the set, just not as the first thing seen).
|
||||||
items = _pick_lead(items)
|
if home_country and scope != "world" and items:
|
||||||
|
# Keep "closest first": pick the gentlest hero from ONLY the closest non-empty
|
||||||
|
# section, so _pick_lead can never float a wider-region/world story above a
|
||||||
|
# local one. Wider tiers stay in their order behind it.
|
||||||
|
lead = items[0].get("__section")
|
||||||
|
head = [a for a in items if a.get("__section") == lead]
|
||||||
|
tail = [a for a in items if a.get("__section") != lead]
|
||||||
|
items = _pick_lead(head) + tail
|
||||||
|
else:
|
||||||
|
items = _pick_lead(items)
|
||||||
return BriefResponse(
|
return BriefResponse(
|
||||||
brief_date=data["brief_date"],
|
brief_date=data["brief_date"],
|
||||||
title=data["title"],
|
title=data["title"],
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ def test_home_brief_leads_with_local(app_db):
|
|||||||
# NY story (#5). CA stories (a different census region) fall to 'country'.
|
# NY story (#5). CA stories (a different census region) fall to 'country'.
|
||||||
r = TestClient(app_db).get("/api/brief?home=US-NY&limit=10").json()
|
r = TestClient(app_db).get("/api/brief?home=US-NY&limit=10").json()
|
||||||
assert r["title"] == "Close to home"
|
assert r["title"] == "Close to home"
|
||||||
|
assert r["items"][0]["section"] == "state" # hero comes from the closest section
|
||||||
state_ids = {it["id"] for it in r["items"] if it["section"] == "state"}
|
state_ids = {it["id"] for it in r["items"] if it["section"] == "state"}
|
||||||
assert state_ids == {1, 2, 3, 4} # high-conf NY only
|
assert state_ids == {1, 2, 3, 4} # high-conf NY only
|
||||||
a5 = next(it for it in r["items"] if it["id"] == 5)
|
a5 = next(it for it in r["items"] if it["id"] == 5)
|
||||||
|
|||||||
Reference in New Issue
Block a user