feat(p9): propagate trace id into emitted events + structured relay/gateway logs

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>
This commit is contained in:
2026-07-03 01:04:24 +05:30
parent 0f923303d3
commit 1d3e18f417
8 changed files with 78 additions and 5 deletions
@@ -1,6 +1,7 @@
import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { OutboxBus } from './outbox.bus';
import { logJson } from '../observability/logger';
/**
* Transactional-outbox relay (Bottom-Up §12). At-least-once by design; the
@@ -60,6 +61,8 @@ export class OutboxRelay implements OnModuleInit, OnModuleDestroy {
try {
const fresh = await this.consumeOnce(eventId);
if (fresh) this.bus.publish(evt.eventType, evt.cloudEvent);
const ce = evt.cloudEvent as { insignia?: { correlationId?: string } } | null;
logJson('info', 'relay.publish', { eventType: evt.eventType, aggregateId: evt.aggregateId, correlationId: ce?.insignia?.correlationId });
await this.prisma.iiosOutboxEvent.update({
where: { eventId },
data: { status: 'PUBLISHED', publishedAt: new Date() },