722bcf6317
Readers can now choose which quick-access lanes sit above the feed; "Today" stays pinned. The pool (goodnews/lanes.py, served at /api/lanes) is one source of truth over three lane kinds the feed already renders: moods, primary topics, and high-volume Discovery tags. Selection lives in the existing prefs blob (localStorage + /api/prefs sync); the filter parser ignores the new `lanes` field, so it rides along harmlessly. Default = today's moods, unchanged. Food/Space stay grouping tags rather than primary topics (per review): `space` already existed; added `food` to the Mind & Craft family so the classifier assigns it, and seeded the Food lane by re-tagging the two food sources. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
36 lines
1.8 KiB
Python
36 lines
1.8 KiB
Python
from goodnews.lanes import build_lane_pool, known_lane_keys, DEFAULT_LANES
|
|
|
|
|
|
def test_pool_shape_and_pinned():
|
|
pool = build_lane_pool({"science": 100}, {"space": 200, "food": 0, "innovation": 99})
|
|
assert pool["pinned"]["key"] == "today"
|
|
assert pool["default"] == DEFAULT_LANES
|
|
names = [g["name"] for g in pool["groups"]]
|
|
assert names == ["Moods", "Topics", "Discovery"]
|
|
# 'today' is pinned, never part of the selectable pool.
|
|
assert "today" not in known_lane_keys(pool)
|
|
|
|
|
|
def test_topics_are_bare_keys_tags_are_prefixed():
|
|
pool = build_lane_pool({"science": 5}, {})
|
|
topics = next(g for g in pool["groups"] if g["name"] == "Topics")["lanes"]
|
|
assert any(l["key"] == "science" for l in topics) # bare topic key
|
|
disc = next(g for g in pool["groups"] if g["name"] == "Discovery")["lanes"]
|
|
assert all(l["key"].startswith("tag:") for l in disc)
|
|
|
|
|
|
def test_volume_gate_and_always_offer():
|
|
# space/food are always offered; a low-volume non-curated tag is dropped.
|
|
pool = build_lane_pool({}, {"space": 1, "food": 0, "resilience": 3, "innovation": 999})
|
|
disc_keys = {l["key"] for l in next(g for g in pool["groups"] if g["name"] == "Discovery")["lanes"]}
|
|
assert "tag:space" in disc_keys and "tag:food" in disc_keys
|
|
assert "tag:innovation" in disc_keys # over threshold
|
|
assert "tag:resilience" not in disc_keys # under threshold, not curated
|
|
|
|
|
|
def test_topic_named_tags_excluded_from_discovery():
|
|
# a tag that duplicates a primary topic must not appear as a Discovery lane
|
|
pool = build_lane_pool({}, {"science": 999, "technology": 999})
|
|
disc_keys = {l["key"] for l in next(g for g in pool["groups"] if g["name"] == "Discovery")["lanes"]}
|
|
assert "tag:science" not in disc_keys and "tag:technology" not in disc_keys
|