fix(memory): add data integrity constraints to Fact model
- Change source_episode_ids from JSON to JSONB for PostgreSQL consistency - Add unique constraint for global facts (project_id IS NULL) - Add CHECK constraint ensuring reinforcement_count >= 1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -18,9 +18,8 @@ from sqlalchemy import (
|
|||||||
Text,
|
Text,
|
||||||
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.orm import relationship
|
||||||
from sqlalchemy.types import JSON
|
|
||||||
|
|
||||||
from app.models.base import Base, TimestampMixin, UUIDMixin
|
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 score (0.0 to 1.0)
|
||||||
confidence = Column(Float, nullable=False, default=0.8, index=True)
|
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 tracking: which episodes contributed to this fact (stored as JSONB array of UUID strings)
|
||||||
source_episode_ids: Column[list] = Column(JSON, default=list, nullable=False)
|
source_episode_ids: Column[list] = Column(JSONB, default=list, nullable=False)
|
||||||
|
|
||||||
# Learning history
|
# Learning history
|
||||||
first_learned = Column(DateTime(timezone=True), nullable=False)
|
first_learned = Column(DateTime(timezone=True), nullable=False)
|
||||||
@@ -86,6 +85,15 @@ class Fact(Base, UUIDMixin, TimestampMixin):
|
|||||||
unique=True,
|
unique=True,
|
||||||
postgresql_where=text("project_id IS NOT NULL"),
|
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
|
# Query patterns
|
||||||
Index("ix_facts_subject_predicate", "subject", "predicate"),
|
Index("ix_facts_subject_predicate", "subject", "predicate"),
|
||||||
Index("ix_facts_project_subject", "project_id", "subject"),
|
Index("ix_facts_project_subject", "project_id", "subject"),
|
||||||
@@ -96,6 +104,10 @@ class Fact(Base, UUIDMixin, TimestampMixin):
|
|||||||
"confidence >= 0.0 AND confidence <= 1.0",
|
"confidence >= 0.0 AND confidence <= 1.0",
|
||||||
name="ck_facts_confidence_range",
|
name="ck_facts_confidence_range",
|
||||||
),
|
),
|
||||||
|
CheckConstraint(
|
||||||
|
"reinforcement_count >= 1",
|
||||||
|
name="ck_facts_reinforcement_positive",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user