diff --git a/backend/app/models/memory/fact.py b/backend/app/models/memory/fact.py index 59aeb55..c7875a7 100644 --- a/backend/app/models/memory/fact.py +++ b/backend/app/models/memory/fact.py @@ -18,9 +18,8 @@ from sqlalchemy import ( Text, text, ) -from sqlalchemy.dialects.postgresql import UUID as PGUUID +from sqlalchemy.dialects.postgresql import JSONB, UUID as PGUUID from sqlalchemy.orm import relationship -from sqlalchemy.types import JSON from app.models.base import Base, TimestampMixin, UUIDMixin @@ -61,8 +60,8 @@ class Fact(Base, UUIDMixin, TimestampMixin): # Confidence score (0.0 to 1.0) confidence = Column(Float, nullable=False, default=0.8, index=True) - # Source tracking: which episodes contributed to this fact (stored as JSON array of UUID strings) - source_episode_ids: Column[list] = Column(JSON, default=list, nullable=False) + # Source tracking: which episodes contributed to this fact (stored as JSONB array of UUID strings) + source_episode_ids: Column[list] = Column(JSONB, default=list, nullable=False) # Learning history first_learned = Column(DateTime(timezone=True), nullable=False) @@ -86,6 +85,15 @@ class Fact(Base, UUIDMixin, TimestampMixin): unique=True, postgresql_where=text("project_id IS NOT NULL"), ), + # Unique constraint on triple for global facts (project_id IS NULL) + Index( + "ix_facts_unique_triple_global", + "subject", + "predicate", + "object", + unique=True, + postgresql_where=text("project_id IS NULL"), + ), # Query patterns Index("ix_facts_subject_predicate", "subject", "predicate"), Index("ix_facts_project_subject", "project_id", "subject"), @@ -96,6 +104,10 @@ class Fact(Base, UUIDMixin, TimestampMixin): "confidence >= 0.0 AND confidence <= 1.0", name="ck_facts_confidence_range", ), + CheckConstraint( + "reinforcement_count >= 1", + name="ck_facts_reinforcement_positive", + ), ) def __repr__(self) -> str: