import { createTelemetryIntegrationHub, normalizeAuditForIntegration, } from "../src/services/transcription/metrics"; const createAudit = ( overrides: Partial> = {} ) => { const nowIso = new Date(1_700_000_000_000).toISOString(); const healthGroup = { supported: true, status: "healthy", reasons: [], }; const baseAudit = { schemaVersion: 2, kind: "sofya-transcriber-debug-audit", sessionId: "session-1", label: "demo", generatedAt: nowIso, createdAt: nowIso, startedAt: nowIso, stoppedAt: nowIso, sessionDurationMs: 1200, requestedProvider: "sofya_as_service", resolvedProvider: "sofya_as_service", metadata: null, environment: { userAgent: "jest", locationHref: "http://localhost/", }, report: { schemaVersion: 2, generatedAt: nowIso, session: { sessionId: "session-1", label: "demo", requestedProvider: "sofya_as_service", resolvedProvider: "sofya_as_service", createdAt: nowIso, startedAt: nowIso, stoppedAt: nowIso, durationMs: 1200, hasStarted: true, hasStopped: true, }, summary: { outcome: "failed", sessionDurationMs: 1200, partialTranscriptCount: 3, finalTranscriptCount: 1, diarizationCount: 0, avgFirstPartialLatencyMs: 140, p95FirstPartialLatencyMs: 220, avgFinalLatencyMs: 310, p95FinalLatencyMs: 500, avgStabilizationLatencyMs: 170, p95StabilizationLatencyMs: 280, reconnectCount: 2, recoverySuccessCount: 1, terminalDisconnectCount: 1, avgRecoveryDurationMs: 330, p95RecoveryDurationMs: 450, peakBufferedAudioBytes: 1600, bufferingDurationMs: 800, drainingDurationMs: 300, bufferStallCount: 0, drainExitReason: "completed", finishDeliveryState: "sent", offlineDurationMs: 0, flapCount: 0, rttMs: 20, downlinkMbps: 5.5, clippingEventCount: 0, silenceRatio: null, speechActivityRatio: null, audioCallbackGapCount: 0, longestAudioCallbackGapMs: null, }, health: { transcriptUi: healthGroup, session: healthGroup, connection: healthGroup, recovery: healthGroup, buffering: healthGroup, browserNetwork: healthGroup, audioCapture: healthGroup, }, timeline: { phases: [{ type: "started", timestamp: 1_700_000_000_000 }], incidents: [], transcriptMilestones: [ { type: "first_final", timestamp: 1_700_000_000_500, text: "sensitive transcript text", }, ], }, findings: [ { code: "terminal_disconnect_observed", severity: "critical", message: "Terminal disconnect happened", }, ], dashboard: { heroStats: { outcome: "failed", sessionDurationMs: 1200, finalTranscriptCount: 1, reconnectCount: 2, peakBufferedAudioBytes: 1600, offlineDurationMs: 0, }, cards: { transcript: { status: "healthy", headline: "ok", metrics: {} }, connection: { status: "critical", headline: "error", metrics: {} }, recovery: { status: "degraded", headline: "retry", metrics: {} }, buffering: { status: "healthy", headline: "ok", metrics: {} }, network: { status: "healthy", headline: "ok", metrics: {} }, audio: { status: "healthy", headline: "ok", metrics: {} }, }, }, }, }; return { ...baseAudit, ...overrides, } as any; }; describe("telemetry integration hub", () => { afterEach(() => { delete (globalThis as any).dtrum; jest.restoreAllMocks(); }); it("normalizes audit payload without transcript text", () => { const payload = normalizeAuditForIntegration(createAudit()); expect(payload.report.timeline.transcriptMilestones[0]).toEqual({ type: "first_final", timestamp: 1_700_000_000_500, }); expect( (payload.report.timeline.transcriptMilestones[0] as Record).text ).toBeUndefined(); }); it("no-ops when integration is disabled", async () => { const warnings = jest.fn(); const hub = createTelemetryIntegrationHub(undefined, warnings); const dispatched = await hub.dispatchAudit(createAudit(), "stop"); expect(dispatched).toBe(false); expect(warnings).not.toHaveBeenCalled(); }); it("emits warning when dynatrace runtime is missing", async () => { const warnings = jest.fn(); const hub = createTelemetryIntegrationHub( { enabled: true, provider: "dynatrace", }, warnings ); await hub.dispatchAudit(createAudit(), "stop"); expect(warnings).toHaveBeenCalledWith( expect.objectContaining({ provider: "dynatrace", code: "runtime_missing", }) ); }); it("dispatches to dynatrace and dedupes by session+reason", async () => { const enterAction = jest.fn(() => 42); const leaveAction = jest.fn(); const sendSessionProperties = jest.fn(); const addActionProperties = jest.fn(); const reportError = jest.fn(); const reportCustomError = jest.fn(); (globalThis as any).dtrum = { enterAction, leaveAction, sendSessionProperties, addActionProperties, reportError, reportCustomError, }; const warnings = jest.fn(); const hub = createTelemetryIntegrationHub( { enabled: true, provider: "dynatrace", }, warnings ); const audit = createAudit(); await hub.dispatchAudit(audit, "stop"); await hub.dispatchAudit(audit, "stop"); await hub.dispatchAudit(audit, "error"); expect(enterAction).toHaveBeenCalledTimes(2); expect(sendSessionProperties).toHaveBeenCalledTimes(2); expect(addActionProperties).toHaveBeenCalledTimes(2); expect(leaveAction).toHaveBeenCalledTimes(2); expect(reportError).toHaveBeenCalledTimes(2); expect(reportCustomError).toHaveBeenCalled(); expect(addActionProperties).toHaveBeenCalledWith( 42, expect.any(Object), undefined, expect.any(Object), expect.any(Object) ); const [javaLong, , shortString, javaDouble] = sendSessionProperties.mock.calls[0]; expect(Object.keys(shortString)).toEqual( expect.arrayContaining([ "sofya.session_id", "sofya.requested_provider", "sofya.resolved_provider", "sofya.outcome", "sofya.dispatch_reason", ]) ); expect(Object.keys(shortString).every((key) => key === key.toLowerCase())).toBe(true); expect(javaLong["sofya.final_transcript_count"]).toBe(1); expect(javaLong["sofya.partial_transcript_count"]).toBe(3); expect(javaDouble["sofya.avg_final_latency_ms"]).toBe(310); expect(JSON.stringify({ javaLong, shortString, javaDouble })).not.toContain( "sensitive transcript text" ); expect(warnings).not.toHaveBeenCalledWith( expect.objectContaining({ code: "dispatch_failed", }) ); }); });