feat(news): index news packages and research persistent events

Extract reusable literal keywords once per source revision, assign complete news packages to long-lived events, and research all event members with immutable evidence and references.

Add additive research storage, vocabulary snapshots, the two-stage workspace, isolated acceptance coverage, and a paused rollout with an initial fixed 50-news production trial.
This commit is contained in:
eezd committed 2026-11-04 12:09:58 +08:00
1 parent 07252fea0f
commit 4929a32a0a
69 files changed
+8215 -2092

No files matched your search

@@ -40,3 +40,6 @@ __all__ = [
"TradingOrder",
"TradingSymbol",
]
# Register additive news research tables with Alembic metadata.
from alphapulse.news_research import models as news_research_models # noqa: F401,E402
+20
View File
@@ -156,6 +156,10 @@ class NewsEvent(Base):
published_revision: Mapped[int] = mapped_column(Integer, default=0)
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
title: Mapped[str] = mapped_column(Text)
fact: Mapped[str] = mapped_column(Text, default='', server_default='')
category: Mapped[str] = mapped_column(String(64), default='其他', server_default='其他')
tags: Mapped[list] = mapped_column(JSONB, default=list, server_default='[]')
dirty_since: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
state: Mapped[str] = mapped_column(String(16), default='pending')
revision: Mapped[int] = mapped_column(Integer, default=1)
result: Mapped[dict | None] = mapped_column(JSONB)
@@ -186,6 +190,22 @@ class EventVersion(Base):
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
class EventEvidence(Base):
__tablename__ = 'news_ai_event_evidence'
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
version_id: Mapped[int] = mapped_column(ForeignKey('news_ai_event_versions.id'), index=True)
data: Mapped[dict] = mapped_column(JSONB)
fetched_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
class EventCorrectionRecord(Base):
__tablename__ = 'news_ai_event_corrections'
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
fingerprint: Mapped[str] = mapped_column(String(64), unique=True)
input: Mapped[dict] = mapped_column(JSONB)
result: Mapped[dict] = mapped_column(JSONB)
class GroupingVersion(Base):
__tablename__ = 'news_ai_grouping_versions'
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)