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:
1 parent
07252fea0f
commit
4929a32a0a
69 files changed
+8215
-2092
No files matched your search
@@ -0,0 +1,142 @@
|
||||
"""Additive storage: original news and legacy AI tables are never written here."""
|
||||
|
||||
from datetime import datetime
|
||||
from sqlalchemy import (
|
||||
BigInteger,
|
||||
DateTime,
|
||||
ForeignKey,
|
||||
Integer,
|
||||
String,
|
||||
Text,
|
||||
UniqueConstraint,
|
||||
func,
|
||||
)
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from alphapulse.core.db import Base
|
||||
|
||||
|
||||
class VocabularyVersion(Base):
|
||||
__tablename__ = "news_research_vocabulary_versions"
|
||||
revision: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=False)
|
||||
entries: Mapped[list] = mapped_column(JSONB)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
||||
|
||||
|
||||
class ResearchSettings(Base):
|
||||
__tablename__ = "news_research_settings"
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
config: Mapped[dict] = mapped_column(JSONB)
|
||||
enabled: Mapped[bool] = mapped_column(default=False)
|
||||
control_revision: Mapped[int] = mapped_column(
|
||||
Integer, default=0, server_default="0"
|
||||
)
|
||||
start_at: Mapped[datetime] = mapped_column(DateTime(timezone=True))
|
||||
|
||||
|
||||
class Package(Base):
|
||||
__tablename__ = "news_research_packages"
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
||||
news_id: Mapped[int] = mapped_column(ForeignKey("news_items.id"), unique=True)
|
||||
content_hash: Mapped[str] = mapped_column(String(64))
|
||||
state: Mapped[str] = mapped_column(String(20), default="index_pending", index=True)
|
||||
keywords: Mapped[list] = mapped_column(JSONB, default=list)
|
||||
error: Mapped[str | None] = mapped_column(Text)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now()
|
||||
)
|
||||
|
||||
|
||||
class Attempt(Base):
|
||||
__tablename__ = "news_research_attempts"
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
||||
package_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("news_research_packages.id"), index=True
|
||||
)
|
||||
content_hash: Mapped[str] = mapped_column(String(64))
|
||||
stage: Mapped[str] = mapped_column(String(16))
|
||||
state: Mapped[str] = mapped_column(String(16))
|
||||
input: Mapped[dict] = mapped_column(JSONB)
|
||||
output: Mapped[dict | None] = mapped_column(JSONB)
|
||||
rules: Mapped[dict] = mapped_column(JSONB)
|
||||
usage: Mapped[dict | None] = mapped_column(JSONB)
|
||||
error: Mapped[str | None] = mapped_column(Text)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now()
|
||||
)
|
||||
|
||||
|
||||
class Event(Base):
|
||||
__tablename__ = "news_research_events"
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
||||
title: Mapped[str] = mapped_column(Text)
|
||||
tags: Mapped[list] = mapped_column(JSONB, default=list)
|
||||
revision: Mapped[int] = mapped_column(Integer, default=1)
|
||||
state: Mapped[str] = mapped_column(String(16), default="pending", index=True)
|
||||
result: Mapped[dict | None] = mapped_column(JSONB)
|
||||
error: Mapped[str | None] = mapped_column(Text)
|
||||
dirty_since: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
|
||||
due_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now(), index=True
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now()
|
||||
)
|
||||
|
||||
|
||||
class Membership(Base):
|
||||
__tablename__ = "news_research_memberships"
|
||||
event_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("news_research_events.id"), primary_key=True
|
||||
)
|
||||
package_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("news_research_packages.id"), primary_key=True
|
||||
)
|
||||
evidence: Mapped[str] = mapped_column(Text)
|
||||
reason: Mapped[str] = mapped_column(Text)
|
||||
change_kind: Mapped[str] = mapped_column(String(20))
|
||||
|
||||
|
||||
class Version(Base):
|
||||
__tablename__ = "news_research_versions"
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
||||
event_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("news_research_events.id"), index=True
|
||||
)
|
||||
revision: Mapped[int] = mapped_column(Integer)
|
||||
state: Mapped[str] = mapped_column(String(16))
|
||||
input: Mapped[dict] = mapped_column(JSONB)
|
||||
output: Mapped[dict | None] = mapped_column(JSONB)
|
||||
rules: Mapped[dict] = mapped_column(JSONB)
|
||||
usage: Mapped[dict | None] = mapped_column(JSONB)
|
||||
evidence: Mapped[list] = mapped_column(JSONB, default=list)
|
||||
error: Mapped[str | None] = mapped_column(Text)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
DateTime(timezone=True), server_default=func.now()
|
||||
)
|
||||
|
||||
|
||||
class Reference(Base):
|
||||
__tablename__ = "news_research_references"
|
||||
__table_args__ = (UniqueConstraint("version_id", "target_version_id"),)
|
||||
id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
|
||||
version_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("news_research_versions.id"), index=True
|
||||
)
|
||||
target_version_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("news_research_versions.id")
|
||||
)
|
||||
role: Mapped[str] = mapped_column(String(20))
|
||||
reason: Mapped[str] = mapped_column(Text)
|
||||
|
||||
|
||||
TABLES = [
|
||||
VocabularyVersion.__table__,
|
||||
ResearchSettings.__table__,
|
||||
Package.__table__,
|
||||
Attempt.__table__,
|
||||
Event.__table__,
|
||||
Membership.__table__,
|
||||
Version.__table__,
|
||||
Reference.__table__,
|
||||
]
|
||||
Reference in new issue
Block a user