feat(stage8): evidence scoring — transparent multidimensional scores (independence, proximity, support, contradiction, directness, date)

This commit is contained in:
NSCT Agent
2026-08-24 07:47:00 +00:00
parent cc9d4f2ba5
commit 719e218d9a
6 changed files with 2092 additions and 3 deletions

View File

@@ -316,8 +316,6 @@ class ClaimClusterModel(Base):
# Association table: claims ↔ clusters (many-to-many)
_claim_cluster_mapping = Base() # noqa: F811 -- dummy for type resolution
claim_cluster_mapping = Base()
claim_cluster_mapping.__tablename__ = "claim_cluster_mapping"
claim_cluster_mapping.id = Column(String(36), primary_key=True, default=lambda: str(uuid4()))
@@ -379,4 +377,98 @@ class ClaimNLUModel(Base):
__table_args__ = (
Index("ix_claim_nlu_numeric_claim_id", "claim_id"),
)
# ---------------------------------------------------------------------------
# Stage 8 — Evidence Scoring (multidimensional, transparent scores)
# ---------------------------------------------------------------------------
class EvidenceType(str, enum.Enum):
"""Klassifizierung der Evidenz-Qualität pro Claim."""
DIRECT_OBSERVATION = "direct_observation"
SECONDARY_REPORT = "secondary_report"
ANALYSIS = "analysis"
OPINION = "opinion"
SPECULATION = "speculation"
class EvidenceRelationTypeV2(str, enum.Enum):
"""Relation zwischen einem Scored-Claim und einem anderen Claim (Stage 8)."""
SUPPORTS = "supports"
CONTRADICTS = "contradicts"
NEUTRAL = "neutral"
class EvidenceScoreModel(Base):
"""Transparente multidimensionale Scores für jeden Claim (Stage 8)."""
__tablename__ = "evidence_scores"
id = Column(String(36), primary_key=True, default=lambda: str(uuid4()))
claim_id = Column(String(36), ForeignKey("claims.id"), nullable=False, unique=True)
research_run_id = Column(String(36), nullable=False)
# Dimension 1: source independence
source_independence_score = Column(Float, nullable=False, default=0.5)
# Dimension 2: proximity to primary source
primary_source_proximity = Column(Float, nullable=False, default=0.0)
# Dimension 3: cross-source support
cross_source_support = Column(Float, nullable=False, default=0.0)
# Dimension 4: contradiction level (1.0 = no contradictions)
contradiction_level = Column(Float, nullable=False, default=1.0)
# Dimension 5: directness of evidence
evidence_directness = Column(Float, nullable=False, default=0.5)
# Dimension 6: date relevance
date_relevance_score = Column(Float, nullable=False, default=0.5)
# Evidence classification
evidence_type = Column(Enum(EvidenceType), nullable=False, default=EvidenceType.SECONDARY_REPORT)
# Raw scores for full auditability
raw_scores_json = Column(JSON, nullable=False, default=dict)
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow)
# Relationships
relations = relationship(
"EvidenceScoreRelationModel",
back_populates="score",
cascade="all, delete-orphan",
foreign_keys="EvidenceScoreRelationModel.score_id",
)
__table_args__ = (
Index("ix_evidence_scores_claim_id", "claim_id"),
Index("ix_evidence_scores_research_run_id", "research_run_id"),
)
class EvidenceScoreRelationModel(Base):
"""Relation zwischen einem Evidence-Scored Claim und anderen Claims (Stage 8)."""
__tablename__ = "evidence_score_relations"
id = Column(String(36), primary_key=True, default=lambda: str(uuid4()))
score_id = Column(
String(36),
ForeignKey("evidence_scores.id"),
nullable=False,
)
related_claim_id = Column(String(36), ForeignKey("claims.id"), nullable=False)
relation_type = Column(Enum(EvidenceRelationTypeV2), nullable=False)
weight = Column(Float, nullable=False, default=1.0)
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
# Relationships
score = relationship("EvidenceScoreModel", back_populates="relations", foreign_keys=[score_id])
related_claim = relationship("ClaimModel", foreign_keys=[related_claim_id])
__table_args__ = (
Index("ix_evidence_score_relations_score_id", "score_id"),
Index("ix_evidence_score_relations_related_claim_id", "related_claim_id"),
)