Sparse-day-proof briefs, feed health check, and 16 new sources
- Briefs now fill from a rolling window (prefer today, backfill up to window_days) and exclude anything featured in the last 7 days of briefs, so slow days still produce five items without stories lingering day to day. - New 'check-feeds' command fetches and parses every feed to catch dead ones. - Added 16 validated sources (science, environment, animals, culture), expanding coverage from 12 to 28 feeds to reduce staleness. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+28
-5
@@ -9,6 +9,7 @@ def build_daily_brief(
|
||||
brief_date: str | None = None,
|
||||
limit: int = 5,
|
||||
replace: bool = False,
|
||||
window_days: int = 3,
|
||||
) -> int:
|
||||
target_date = brief_date or date.today().isoformat()
|
||||
existing = conn.execute("SELECT id FROM daily_briefs WHERE brief_date = ?", (target_date,)).fetchone()
|
||||
@@ -22,7 +23,7 @@ def build_daily_brief(
|
||||
(target_date, f"Five Good Things Today - {target_date}"),
|
||||
).lastrowid
|
||||
|
||||
rows = _candidate_articles(conn, target_date)
|
||||
rows = _candidate_articles(conn, target_date, window_days)
|
||||
selected = _select_diverse(rows, limit)
|
||||
for index, row in enumerate(selected, start=1):
|
||||
conn.execute(
|
||||
@@ -78,7 +79,17 @@ def show_brief(conn: sqlite3.Connection, brief_date: str | None = None, limit: i
|
||||
).fetchall()
|
||||
|
||||
|
||||
def _candidate_articles(conn: sqlite3.Connection, target_date: str) -> list[sqlite3.Row]:
|
||||
def _candidate_articles(
|
||||
conn: sqlite3.Connection, target_date: str, window_days: int = 3
|
||||
) -> list[sqlite3.Row]:
|
||||
"""Brief candidates, sparse-day-proof.
|
||||
|
||||
Prefers articles dated on target_date, but widens to the preceding
|
||||
`window_days` so the brief still fills on slow news days. Anything already
|
||||
featured in a brief within the last 7 days (other than this same date, which
|
||||
is being rebuilt) is excluded so backfilled stories cannot linger across
|
||||
consecutive days.
|
||||
"""
|
||||
return conn.execute(
|
||||
"""
|
||||
SELECT
|
||||
@@ -100,19 +111,31 @@ def _candidate_articles(conn: sqlite3.Connection, target_date: str) -> list[sqli
|
||||
s.pr_risk_score,
|
||||
s.reason_code,
|
||||
s.reason_text,
|
||||
s.model_name
|
||||
s.model_name,
|
||||
CASE WHEN date(COALESCE(a.published_at, a.discovered_at)) = date(?)
|
||||
THEN 1 ELSE 0 END AS is_today
|
||||
FROM articles a
|
||||
JOIN sources src ON src.id = a.source_id
|
||||
JOIN article_scores s ON s.article_id = a.id
|
||||
WHERE s.accepted = 1
|
||||
AND date(COALESCE(a.published_at, a.discovered_at)) = date(?)
|
||||
AND date(COALESCE(a.published_at, a.discovered_at)) <= date(?)
|
||||
AND date(COALESCE(a.published_at, a.discovered_at)) > date(?, '-' || ? || ' days')
|
||||
AND a.id NOT IN (
|
||||
SELECT bi.article_id
|
||||
FROM daily_brief_items bi
|
||||
JOIN daily_briefs b ON b.id = bi.brief_id
|
||||
WHERE b.brief_date <> ?
|
||||
AND b.brief_date <= date(?)
|
||||
AND b.brief_date > date(?, '-7 days')
|
||||
)
|
||||
ORDER BY
|
||||
is_today DESC,
|
||||
(s.constructive_score + s.agency_score + s.human_benefit_score + src.trust_score
|
||||
- s.cortisol_score - s.ragebait_score - s.pr_risk_score) DESC,
|
||||
COALESCE(a.published_at, a.discovered_at) DESC
|
||||
LIMIT 50
|
||||
""",
|
||||
(target_date,),
|
||||
(target_date, target_date, target_date, window_days, target_date, target_date, target_date),
|
||||
).fetchall()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user