Paginate C-25 owner-return reply collection (STATE-WP-0094-T03)

GET /messages/ accepts offset with stable created_at,id ordering; C-25 pages
every reply per counterpart, dedups by message id and warns explicitly when
collection is incomplete instead of capping at 200.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 671493@bnt-lap001
Assistant-Session: 60d7b11f-78f9-4731-9367-918511b2762d
This commit is contained in:
tegwick 2026-10-04 12:54:57 +02:00
parent fceb5f27f0
commit 3b9a5c58f5
3 changed files with 154 additions and 7 deletions

View file

@ -1,6 +1,6 @@
from datetime import datetime, timezone
from fastapi import APIRouter, Body, Depends, HTTPException, Request, Response, status
from fastapi import APIRouter, Body, Depends, HTTPException, Query, Request, Response, status
from sqlalchemy import and_, or_, select
from sqlalchemy.ext.asyncio import AsyncSession
@ -137,6 +137,7 @@ async def list_messages(
from_agent: str | None = None,
unread_only: bool = False,
limit: int = 50,
offset: int = Query(0, ge=0),
session: AsyncSession = Depends(get_session),
) -> list[MessageRead]:
now = utcnow()
@ -170,7 +171,10 @@ async def list_messages(
values = resolution.slug_values if resolution else (from_agent,)
query = query.where(AgentMessage.from_agent.in_(values))
result = await session.execute(
query.order_by(AgentMessage.created_at.desc()).limit(limit)
# ``id`` breaks created_at ties so offset pages are stable (STATE-WP-0094-T03).
query.order_by(AgentMessage.created_at.desc(), AgentMessage.id.desc())
.offset(offset)
.limit(limit)
)
messages = list(result.scalars().all())
if reader_values is None or reader is None: