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 { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { Prisma, IiosRouteBinding, IiosRouteDecision, IiosRouteMode, IiosOutputFormat } from '@prisma/client';
import { CloudEvent, IIOS_EVENTS } from '@insignia/iios-contracts';
import { currentTraceId, newTraceId, toTraceparent } from '../observability/trace-context';
import { PrismaService } from '../prisma/prisma.service';
import { RouteSimulator, type OriginRef } from './route-simulator';
import { OutboundService } from '../adapters/outbound.service';
@@ -118,6 +119,7 @@ export class RouteService {
}
private async emitApproved(scopeId: string, decisionId: string): Promise<void> {
const tid = currentTraceId() ?? newTraceId();
const event: CloudEvent = {
specversion: '1.0',
id: `evt_routeapproved_${decisionId}`,
@@ -126,7 +128,8 @@ export class RouteService {
subject: `route_decision/${decisionId}`,
time: new Date().toISOString(),
datacontenttype: 'application/json',
insignia: { scopeSnapshotId: scopeId, idempotencyKey: `routeapproved:${decisionId}`, dataClass: 'internal' },
traceparent: toTraceparent(tid),
insignia: { scopeSnapshotId: scopeId, correlationId: tid, idempotencyKey: `routeapproved:${decisionId}`, dataClass: 'internal' },
data: { decisionId },
};
await this.prisma.iiosOutboxEvent.create({