Make paywalls systemic + fix ArticleCard reactivity
- ArticleCard: derive safeHref from article.url and reset image-failure state when the article changes, so in-place replacements re-evaluate correctly (clears the Svelte capture warning; build is warning-free again). - Downweight paywalled stories below readable ones (stable sort) when composing the daily five and in feed results — the brief now leads readable and rarely hands over a locked door. - review_sources gains a 'paywall-heavy' advisory flag (Nature, New Scientist flag at 100%); never auto-deactivates. - New Scientist/Nature kept active but no longer reach the daily five; they remain browsable with the label + Replace. - Tests: brief readability preference + paywall-heavy flag (79 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
from datetime import date
|
||||
|
||||
from goodnews.db import connect, init_db
|
||||
from goodnews.briefs import build_daily_brief, show_brief
|
||||
from goodnews.paywall import is_paywalled
|
||||
|
||||
|
||||
def test_brief_prefers_readable_over_higher_scored_paywalled():
|
||||
c = connect(":memory:"); init_db(c)
|
||||
today = date.today().isoformat()
|
||||
for sid in range(1, 8):
|
||||
c.execute("INSERT INTO sources (id,name,feed_url,trust_score) VALUES (?,?,?,5)",
|
||||
(sid, f"S{sid}", f"http://s{sid}/f"))
|
||||
|
||||
def add(aid, sid, url, score):
|
||||
c.execute("INSERT INTO articles (id,source_id,canonical_url,title,published_at,url_hash) "
|
||||
"VALUES (?,?,?,?,?,?)", (aid, sid, url, f"t{aid}", today + "T12:00:00+00:00", f"h{aid}"))
|
||||
c.execute("INSERT INTO article_scores (article_id,constructive_score,agency_score,human_benefit_score,"
|
||||
"cortisol_score,ragebait_score,pr_risk_score,accepted,topic,flavor) "
|
||||
"VALUES (?,?,?,?,0,0,2,1,'science','discovery')", (aid, score, score, score))
|
||||
|
||||
# Paywalled ones are scored HIGHER — readability must still win for the five.
|
||||
add(1, 1, "https://www.newscientist.com/a", 9)
|
||||
add(2, 2, "https://www.nature.com/b", 9)
|
||||
add(3, 3, "https://phys.org/c", 4)
|
||||
add(4, 4, "https://www.goodnewsnetwork.org/d", 4)
|
||||
add(5, 5, "https://e360.yale.edu/e", 4)
|
||||
add(6, 6, "https://news.mongabay.com/f", 4)
|
||||
add(7, 7, "https://theconversation.com/g", 4)
|
||||
c.commit()
|
||||
|
||||
build_daily_brief(c, brief_date=today, limit=5, replace=True)
|
||||
urls = [r["canonical_url"] for r in show_brief(c, brief_date=today, limit=10)]
|
||||
c.close()
|
||||
assert len(urls) == 5
|
||||
assert not any(is_paywalled(u) for u in urls) # five readable chosen over paywalled
|
||||
@@ -0,0 +1,25 @@
|
||||
import pytest
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from goodnews.db import connect, init_db
|
||||
from goodnews.sources import review_sources
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def conn():
|
||||
c = connect(":memory:"); init_db(c)
|
||||
c.execute("INSERT INTO sources (id,name,feed_url,trust_score) VALUES (1,'Pay','http://p/f',5)")
|
||||
yield c; c.close()
|
||||
|
||||
|
||||
def test_paywall_heavy_flagged(conn):
|
||||
now = datetime.now(timezone.utc).isoformat()
|
||||
for i in range(20):
|
||||
url = f"https://www.newscientist.com/{i}" if i < 15 else f"https://phys.org/{i}"
|
||||
conn.execute("INSERT INTO articles (id,source_id,canonical_url,title,published_at,url_hash) "
|
||||
"VALUES (?,1,?,?,?,?)", (i, url, f"t{i}", now, f"h{i}"))
|
||||
conn.execute("INSERT INTO article_scores (article_id,cortisol_score,ragebait_score,accepted) "
|
||||
"VALUES (?,1,0,1)", (i,))
|
||||
conn.commit()
|
||||
flagged = review_sources(conn)
|
||||
assert flagged and "paywall-heavy" in flagged[0]["reason"]
|
||||
Reference in New Issue
Block a user