Brief emotional-mix guardrails + source on its own line

Composition (Codex's priority — content mix was the louder problem):
- _select_diverse now guards the daily five's emotional tone: at most 1 health,
  at most 2 science+health combined, at most 2 of any topic, distinct sources —
  so at least three of the five are community/culture/animals/environment when
  available. Caps relax (mix, then source) only to fill on thin days.
- Verified live: today's five went to environment x2, health, animals, science.

UI:
- Source moved to its own line below the tags, left-justified, for uniform
  rhythm across hero and tiles (was sometimes trailing the tags, right-aligned).
- Watermark kept as-is (intentionally subtle; liked).

Tests updated for the emotional-mix contract (80 total).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jay
2026-05-31 12:29:02 +00:00
parent 541f59ed6e
commit 3858380ffe
3 changed files with 64 additions and 38 deletions
+24 -15
View File
@@ -2,7 +2,6 @@ from goodnews.briefs import _select_diverse
def row(id, source, topic):
# _select_diverse reads id, source_name, topic; plain dicts support [] access.
return {"id": id, "source_name": source, "topic": topic}
@@ -10,29 +9,39 @@ def test_prefers_distinct_sources_best_first():
rows = [
row(1, "A", "science"),
row(2, "A", "science"), # same source as #1 — skipped while others remain
row(3, "B", "health"),
row(3, "B", "community"),
row(4, "C", "environment"),
]
assert [r["id"] for r in _select_diverse(rows, limit=3)] == [1, 3, 4]
def test_caps_a_topic_when_alternatives_exist():
def test_at_most_one_health_when_alternatives_exist():
rows = [
row(1, "A", "science"), row(2, "B", "science"),
row(3, "C", "science"), row(4, "D", "science"),
row(5, "E", "community"), row(6, "F", "animals"), row(7, "G", "culture"),
row(1, "A", "health"), row(2, "B", "health"),
row(3, "C", "science"), row(4, "D", "community"),
row(5, "E", "animals"), row(6, "F", "environment"),
]
selected = _select_diverse(rows, limit=5, max_per_topic=2)
topics = [r["topic"] for r in selected]
assert len(selected) == 5
assert topics.count("science") == 2 # capped, even though 4 were available
assert {"community", "animals", "culture"} <= set(topics)
topics = [r["topic"] for r in _select_diverse(rows, limit=5)]
assert len(topics) == 5
assert topics.count("health") == 1
def test_relaxes_cap_when_only_one_topic_available():
rows = [row(i, f"S{i}", "science") for i in range(1, 6)]
selected = _select_diverse(rows, limit=5)
assert len(selected) == 5 # all science: cap relaxed because nothing else exists
def test_science_plus_health_capped_at_two():
rows = [
row(1, "A", "science"), row(2, "B", "science"), row(3, "C", "science"),
row(4, "D", "health"), row(5, "E", "community"),
row(6, "F", "animals"), row(7, "G", "culture"),
]
topics = [r["topic"] for r in _select_diverse(rows, limit=5)]
assert len(topics) == 5
assert topics.count("science") + topics.count("health") <= 2
# …which means the rest are the gentler lanes
assert sum(t in {"community", "animals", "culture", "environment"} for t in topics) >= 3
def test_relaxes_caps_to_fill_on_thin_days():
rows = [row(i, f"S{i}", "science") for i in range(1, 6)] # only science available
assert len(_select_diverse(rows, limit=5)) == 5
def test_backfills_repeating_source_when_needed():