Files
resolutionflow/backend/app/models/session_resolution_output.py
chihlasm e130976803 fix: add back_populates to SessionHandoff and SessionResolutionOutput relationships
SQLAlchemy SAWarning about overlapping relationships was promoted to
an error by pytest filterwarnings=error, crashing mapper initialization
and causing 500s on every request — cascading to 423+ test failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 17:46:07 +00:00

40 lines
2.5 KiB
Python

"""Session resolution output model — three deliverables generated on resolve."""
import uuid
from datetime import datetime, timezone
from typing import Optional, Any
from sqlalchemy import String, Text, DateTime, ForeignKey, CheckConstraint, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.dialects.postgresql import UUID, JSONB
from app.core.database import Base
class SessionResolutionOutput(Base):
"""One of three resolution deliverables: PSA ticket notes, KB article, client summary.
UNIQUE(session_id, output_type) + upsert so outputs can be regenerated.
"""
__tablename__ = "session_resolution_outputs"
__table_args__ = (
CheckConstraint("output_type IN ('psa_ticket_notes', 'knowledge_base', 'client_summary')", name="ck_session_resolution_outputs_output_type"),
CheckConstraint("status IN ('draft', 'approved', 'pushed', 'rejected')", name="ck_session_resolution_outputs_status"),
UniqueConstraint("session_id", "output_type", name="uq_session_resolution_session_type"),
)
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
session_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("ai_sessions.id", ondelete="CASCADE"), nullable=False, index=True)
output_type: Mapped[str] = mapped_column(String(30), nullable=False)
generated_content: Mapped[str] = mapped_column(Text, nullable=False)
structured_data: Mapped[Optional[dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="For KB: {symptoms, root_cause, steps, tags}")
edited_content: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
status: Mapped[str] = mapped_column(String(20), nullable=False, default="draft")
pushed_to: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
pushed_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
pushed_reference: Mapped[Optional[str]] = mapped_column(String(200), nullable=True)
generated_by_model: Mapped[str] = mapped_column(String(50), nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
# Relationships
session = relationship("AISession", foreign_keys="SessionResolutionOutput.session_id", back_populates="resolution_outputs")