state-hub/api/services/memo_notification.py

68 lines
2.4 KiB
Python
Raw Normal View History

"""Deduplicated informed-decision notification receipts.
The signed-in overview is the review entry point. A receipt stores and
announces only memo id, question, class, and submitter. Replays of the same
delivery id return the retained receipt; a different body conflicts and leaves
the original readable.
"""
from __future__ import annotations
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from api.models.agent_message import AgentMessage
from api.models.memo_notification import MemoNotificationReceipt
from api.services.informed_decision_contract import Notification
from api.services.repository_aliases import canonicalize_repository_slug
NOTIFICATION_SENDER = "informed-decision"
NOTIFICATION_RECIPIENT = "bernd"
class NotificationConflict(Exception):
def __init__(self, receipt: MemoNotificationReceipt) -> None:
self.receipt = receipt
async def accept_notification(
session: AsyncSession, delivery_id: str, notice: Notification
) -> tuple[MemoNotificationReceipt, bool]:
existing = await session.get(MemoNotificationReceipt, delivery_id)
if existing is not None:
if existing.body_digest != notice.body_digest:
raise NotificationConflict(existing)
return existing, True
message = AgentMessage(
from_agent=await canonicalize_repository_slug(session, NOTIFICATION_SENDER),
to_agent=await canonicalize_repository_slug(session, NOTIFICATION_RECIPIENT),
subject=notice.message_subject(),
body=notice.message_text(),
kind="message",
)
session.add(message)
await session.flush()
receipt = MemoNotificationReceipt(
delivery_id=delivery_id,
body_digest=notice.body_digest,
memo_id=notice.memo_id,
question=notice.question,
memo_class=notice.memo_class,
submitter=notice.submitter,
message_id=message.id,
authoritative_review="signed-in-overview",
)
session.add(receipt)
try:
await session.commit()
except IntegrityError:
await session.rollback()
existing = await session.get(MemoNotificationReceipt, delivery_id)
if existing is None:
raise
if existing.body_digest != notice.body_digest:
raise NotificationConflict(existing)
return existing, True
await session.refresh(receipt)
return receipt, False