Task O.2: ai/calendar/route/ingest emit sites now stamp traceparent + insignia.
correlationId from interaction.traceId ?? currentTraceId() ?? generated (mirroring
message.send; inbox/inbound already carried correlationId). toTraceparent is hex-safe
(UUID used as-is, other ids hashed). OutboxRelay logs a structured relay.publish per
event (eventType/aggregateId/correlationId); MessageGateway logs ws.deliver. Tests:
an event's correlationId equals the active request trace, with a generated fallback.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Task T3.2: AiJobService.getArtifact/accept/reject assertOwns on artifact.job.scopeId;
listArtifacts scoped to caller. CalendarService.getMeeting/setConsent/generateTranscript/
summarize/listActionItems assertOwns on meeting.scopeId (optional principal → asserts
when supplied by a controller, skipped for internal calls). MessageService.getMessageById
gains the same optional fence. Controllers thread the principal through. All 46
ai/calendar/routing/messaging tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
InboxService.list (fail-closed) + transition (OPEN/SNOOZED/DONE/STALE/ARCHIVED
state machine, owner-only, state-history). GET /v1/inbox/items + PATCH
/v1/inbox/items/:id. Moved SessionVerifier to global IdentityModule (shared by
message + inbox, no circular imports). 35 tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Event-driven projector creates/collapses NEEDS_REPLY items from message.sent
(traceId propagated; inbox.item.created emitted) and resolves them to DONE on
message.read; idempotent via processed-event ledger. markRead now emits a
message.read outbox event (atomic). OutboxRelay runs on a 500ms timer in the
app (off in tests). Shared resetDb (TRUNCATE CASCADE) fixes cross-spec FK
isolation. 32 tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>