Summary briefing layer: Today pre-summarized, /a is the canonical read

Make summaries the core reading experience (summary-first, source-forward):
- Cycle pre-warms summaries for Today's 7 (idempotent → only new ones hit the LLM).
- /api/brief items carry their cached summary; Today cards (hero + tiles) show it
  inline, so Today reads as a calm briefing.
- Card title/image now open the /a summary page (the canonical artifact), with a
  visible "Full story" link straight to the source on every card (the escape hatch).
- /a gains related-grouping chips + a Copy-link/share control.
- Tighten the summary prompt: original, factual, no quotations / no close paraphrase.
Long tail stays lazy+cached. No article bodies stored. 129 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jay
2026-06-04 19:48:32 +00:00
parent 3924d927aa
commit cfde4e22db
6 changed files with 80 additions and 14 deletions
+19
View File
@@ -10,6 +10,7 @@ from .briefs import build_daily_brief, show_brief
from .db import connect, init_db
from .dedup import DEFAULT_THRESHOLD, DEFAULT_WINDOW_DAYS, dedup as run_dedup
from .enrich import enrich_brief_images
from .summarize import generate_summary, get_summary
from .feeds import (
fetch_feed,
parse_feed,
@@ -452,6 +453,24 @@ def _run_cycle_locked(conn: sqlite3.Connection, args: argparse.Namespace) -> Non
except Exception as exc:
print(f"brief: skipped ({exc})")
# Pre-warm summaries for today's brief so Today reads as a calm briefing.
# Idempotent: cached items are skipped, so this only hits the LLM for new ones.
try:
client = llm_client_from_args(args)
ids = [r[0] for r in conn.execute(
"SELECT bi.article_id FROM daily_briefs b JOIN daily_brief_items bi "
"ON bi.brief_id = b.id WHERE b.brief_date = ?", (today,)
)]
made = 0
for aid in ids:
had = get_summary(conn, aid)
generate_summary(conn, aid, client=client)
if not had and get_summary(conn, aid):
made += 1
print(f"summaries: {made} new (of {len(ids)} brief items)")
except Exception as exc:
print(f"summaries: skipped ({exc})")
if not args.no_review:
try:
flagged = review_sources(conn)