Files
core-api/src
jpmschweitzerandClaude Sonnet 5 3026b9214f feat(scribe): mailbox takes since_message_id, answers newest_message_id (T-16)
The Office's one polling call, glance, answers "has anything changed
since I last looked?" with counts; live core-api ignored the
parameters it needed, so glance could not ship.

GET /scribe/mailbox now takes since_message_id=N: only entries whose
message number is above N (strictly — not >=), combined with
view/unread/tag the same way they combine with each other today.
message_id, which already bypasses those filters, keeps bypassing
since_message_id too.

The response gains newest_message_id: the caller's newest message
number across its whole mailbox, every view, regardless of any filter
the call applied; null when the mailbox is empty. It exists because
the unread-first sort can return an older unread entry on a limit=1
page while a newer message is already read — the exact shape glance
hits. Computed from a scoped MAX(message_id) query (tenant and
address), never from the page itself, so it cannot read stale or leak
across the tenant/address boundary (D-73).

total's meaning is unchanged: it already counted every filter match
independent of limit (the count query runs against the pre-limit
subquery), so since_message_id just becomes one more filter it counts
against.

Three mutations run and reverted to confirm the new tests actually
cover the behavior: message_id > vs >= broke the boundary test;
computing newest_message_id from the sorted page instead of the whole
mailbox broke the older-unread test; dropping the address filter from
the MAX query broke the address-boundary test.

583 -> 592 tests passing; test database left at head (010).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-20 00:55:31 +02:00
..