c25e14ed6a
Restructure the nav around two permanent lanes, then the reader's chosen ones: "Highlights" (the curated daily brief — formerly "Today") and "Latest" (the freshest accepted stories, newest-first). Now that the gate is tight, a chronological "incoming" feed is safe to expose. * feed(): new sort="latest" (pure recency) alongside the default best-first rank; /api/feed exposes sort=ranked|latest (validated). Still accepted-only and boundary-respecting either way. * lanes.py: two pinned lanes (Highlights + Latest) instead of one. * Home: "Latest" view + "Load more" pagination for every feed view (offset- paged, de-duped). Mobile bottom bar gains a Latest tab. * LanePicker shows both pinned lanes; nav rail renders them first. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
28 lines
1.0 KiB
Python
28 lines
1.0 KiB
Python
from goodnews.db import connect, init_db
|
|
from goodnews import queries
|
|
|
|
|
|
def _article(c, aid, *, when):
|
|
c.execute(
|
|
"INSERT INTO articles (id, source_id, canonical_url, title, url_hash, published_at) "
|
|
"VALUES (?, 1, ?, ?, ?, ?)",
|
|
(aid, f"http://s/{aid}", f"T{aid}", f"h{aid}", when),
|
|
)
|
|
c.execute(
|
|
"INSERT INTO article_scores (article_id, accepted, constructive_score) VALUES (?, 1, 5)",
|
|
(aid,),
|
|
)
|
|
|
|
|
|
def test_latest_sorts_strictly_by_recency(tmp_path):
|
|
c = connect(str(tmp_path / "t.db")); init_db(c)
|
|
c.execute("INSERT INTO sources (id, name, feed_url) VALUES (1, 'S', 'http://s/f')")
|
|
# Insert out of order; the dates are what should drive 'latest'.
|
|
_article(c, 1, when="2026-03-01T00:00:00")
|
|
_article(c, 2, when="2026-06-01T00:00:00") # newest
|
|
_article(c, 3, when="2026-01-01T00:00:00") # oldest
|
|
c.commit()
|
|
|
|
latest = [a["id"] for a in queries.feed(c, sort="latest")]
|
|
assert latest == [2, 1, 3] # newest → oldest, regardless of insert order
|