Add per-paper summary verification and cap safeguards

- Per-paper summary batches are fact-checked against abstracts (verify ->
  revise once on major issues -> re-verify), controlled by SEBRIEF_VERIFY_ENABLED
- The paper cap never drops papers already published in this week's digest
  (--force re-runs could otherwise erase them from every digest)
- SEBRIEF_MAX_PAPERS default 40 -> 60 (observed weekly volume ~47)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jsahn
2026-09-02 17:21:41 +09:00
co-authored by Claude Fable 5
parent c0b140d27f
commit d9dda79282
13 changed files with 249 additions and 23 deletions
+22
View File
@@ -138,6 +138,7 @@ class FakeStore:
def __init__(self, *, pending: list[Paper] | None = None) -> None:
self.upserted: list[list[Paper]] = []
self.saved_summaries: list[dict] = []
self.published_dois: set[str] = set()
self.pending = pending if pending is not None else []
self.digests: dict[str, object] = {}
self.digested: list[tuple[list[str], str]] = []
@@ -157,6 +158,9 @@ class FakeStore:
def mark_digested(self, dois: list[str], week: str) -> None:
self.digested.append((list(dois), week))
def digested_dois(self, week: str) -> set[str]:
return set(self.published_dois)
def has_digest(self, week: str) -> bool:
return week in self.digests
@@ -198,6 +202,8 @@ class FakeProvider:
fail_summarize: bool = False,
fail_revise: bool = False,
fail_paper_summaries: bool = False,
paper_verifications: list | None = None,
revised_papers: list | None = None,
) -> None:
self.digest = digest or make_digest()
self.verifications = list(verifications or [])
@@ -205,6 +211,8 @@ class FakeProvider:
self.fail_summarize = fail_summarize
self.fail_revise = fail_revise
self.fail_paper_summaries = fail_paper_summaries
self.paper_verifications = list(paper_verifications or [])
self.revised_papers = revised_papers
self.calls: list[str] = []
def summarize(self, payload):
@@ -227,6 +235,20 @@ class FakeProvider:
]
return items, "fake-model"
def verify_paper_summaries(self, papers, items):
self.calls.append("verify_papers")
if not self.paper_verifications:
from sebrief.models import Verification
return Verification(ok=True, issues=[]), "fake-model"
return self.paper_verifications.pop(0), "fake-model"
def revise_paper_summaries(self, papers, items, issues):
self.calls.append("revise_papers")
if self.revised_papers is not None:
return list(self.revised_papers), "fake-model"
return list(items), "fake-model"
def verify(self, payload, digest):
self.calls.append("verify")
if not self.verifications: