import { createMetricsSnapshot, createUnsupportedMetricsSnapshot } from "./helpers/metricsFixtures"; import { createBaseAuditState, createFailedAuditState, createRecoveredAuditState, createStatus, createUnsupportedMetricsSnapshot as createAuditUnsupportedMetricsSnapshot, type AuditState, } from "./helpers/auditReportFixtures"; type BuildSessionReportInput = { auditState: AuditState; resilienceStatus: AuditState["checkpoints"][number]["resilienceStatus"] | null; metricsSnapshot: ReturnType | ReturnType | null; now: number; }; type AuditReportModule = { buildSessionReport: (input: BuildSessionReportInput) => { report: { schemaVersion: 2; generatedAt: string; session: { sessionId: string; label: string | null; requestedProvider: string; resolvedProvider: string | null; createdAt: string; startedAt: string | null; stoppedAt: string | null; durationMs: number | null; hasStarted: boolean; hasStopped: boolean; }; summary: { outcome: "healthy" | "degraded_recovered" | "degraded_unrecovered" | "failed"; partialTranscriptCount: number | null; finalTranscriptCount: number | null; avgFirstPartialLatencyMs: number | null; p95FirstPartialLatencyMs: number | null; avgFinalLatencyMs: number | null; p95FinalLatencyMs: number | null; }; health: Record; timeline: { phases: Array<{ type: string; timestamp: number }>; incidents: Array<{ type: string; timestamp: number; endedAt: number | null; detail: unknown }>; transcriptMilestones: Array<{ type: string; timestamp: number; text: string | null }>; }; findings: Array<{ code: string; severity: string; message: string }>; dashboard: { heroStats: { outcome: string; sessionDurationMs: number | null; finalTranscriptCount: number | null; reconnectCount: number | null; peakBufferedAudioBytes: number | null; offlineDurationMs: number | null; }; cards: Record }>; }; }; }; }; const loadAuditReportModule = (): AuditReportModule | null => { try { return require("../src/services/transcription/audit") as AuditReportModule; } catch { return null; } }; const auditReportModule = loadAuditReportModule(); const describeIfAvailable = auditReportModule ? describe : describe.skip; const buildReport = (input: BuildSessionReportInput) => { if (!auditReportModule) { throw new Error("audit report module is not available"); } return auditReportModule.buildSessionReport(input).report; }; const assertFindingCodes = (report: { findings: Array<{ code: string }> }, codes: string[]) => { expect(report.findings.map((finding) => finding.code)).toEqual( expect.arrayContaining(codes) ); }; describeIfAvailable("audit report helper contract", () => { it("builds a healthy session report with dashboard-friendly summary data", () => { const auditState = createBaseAuditState(); const metricsSnapshot = createMetricsSnapshot({ transcriptUi: { supported: true, currentPartialText: null, lastFinalText: "hello world", partialCount: 1, finalCount: 1, diarizationCount: 0, utteranceCount: 1, lastFirstPartialLatencyMs: 120, avgFirstPartialLatencyMs: 120, p95FirstPartialLatencyMs: 120, lastFinalLatencyMs: 280, avgFinalLatencyMs: 280, p95FinalLatencyMs: 280, lastStabilizationLatencyMs: 160, avgStabilizationLatencyMs: 160, p95StabilizationLatencyMs: 160, }, buffering: { supported: true, isBufferingAudio: false, isDrainingAudio: false, pendingBufferedAudioBytes: 0, persistedBufferedAudioBytes: 0, persistedBufferedAudioSegments: 0, totalBufferedAudioBytes: 0, peakBufferedAudioBytes: 0, bufferingDurationMs: null, drainingDurationMs: null, lastDrainProgressAt: null, drainCycles: 0, drainExitReason: null, finishDeliveryState: "sent", avgBufferGrowthRateBytesPerSecond: null, avgBufferDrainRateBytesPerSecond: null, bufferStallCount: 0, }, }); const report = buildReport({ auditState, resilienceStatus: auditState.checkpoints[auditState.checkpoints.length - 1]?.resilienceStatus ?? null, metricsSnapshot, now: 1_700_000_002_800, }); expect(report).toMatchObject({ schemaVersion: 2, summary: expect.objectContaining({ outcome: "healthy", }), dashboard: expect.objectContaining({ heroStats: expect.objectContaining({ outcome: "healthy", finalTranscriptCount: 1, }), }), }); expect(report.health.transcriptUi.supported).toBe(true); expect(report.health.connection.supported).toBe(true); expect(report.health.connection.status).toBe("healthy"); expect(report.timeline.phases.map((phase) => phase.type)).toEqual( expect.arrayContaining(["created", "ready", "connected", "stopped"]) ); expect(report.timeline.transcriptMilestones.map((milestone) => milestone.type)).toEqual( expect.arrayContaining(["first_partial", "first_final", "last_final"]) ); expect(report.findings).toEqual([]); }); it("marks a recovered degraded session and records recovery and buffering findings", () => { const auditState = createRecoveredAuditState(); const metricsSnapshot = createMetricsSnapshot({ browserNetwork: { supported: true, onlineTransitionCount: 2, offlineTransitionCount: 2, offlineDurationMs: 900, flapCount: 2, effectiveType: "4g", downlinkMbps: 25, rttMs: 180, }, buffering: { supported: true, isBufferingAudio: false, isDrainingAudio: false, pendingBufferedAudioBytes: 0, persistedBufferedAudioBytes: 0, persistedBufferedAudioSegments: 0, totalBufferedAudioBytes: 0, peakBufferedAudioBytes: 262_144, bufferingDurationMs: 900, drainingDurationMs: 500, lastDrainProgressAt: 1_700_000_001_500, drainCycles: 1, drainExitReason: "completed", finishDeliveryState: "sent", avgBufferGrowthRateBytesPerSecond: 256, avgBufferDrainRateBytesPerSecond: 512, bufferStallCount: 0, }, recovery: { supported: true, reconnectCount: 1, recoverySuccessCount: 1, terminalDisconnectCount: 0, currentReconnectAttempt: null, nextReconnectDelayMs: null, remainingReconnectAttempts: 3, lastRecoveryDurationMs: 600, avgRecoveryDurationMs: 600, p95RecoveryDurationMs: 600, }, }); const report = buildReport({ auditState, resilienceStatus: auditState.checkpoints[auditState.checkpoints.length - 1]?.resilienceStatus ?? null, metricsSnapshot, now: 1_700_000_002_900, }); expect(report.summary.outcome).toBe("degraded_recovered"); assertFindingCodes(report, ["offline_flaps_detected", "high_peak_buffer"]); expect(report.health.recovery.status).toBe("degraded"); expect(report.health.buffering.status).toBe("degraded"); expect(report.dashboard.heroStats.outcome).toBe("degraded_recovered"); expect(report.dashboard.cards.buffering.metrics).toEqual( expect.objectContaining({ peakBufferedAudioBytes: 262_144, }) ); }); it("marks a failed session when the session ends unrecovered after a terminal disconnect", () => { const auditState = createFailedAuditState(); const metricsSnapshot = createMetricsSnapshot({ connection: { supported: true, connectionState: "disconnected", websocketState: "closed", browserOnline: true, connectionOpenCount: 1, connectionCloseCount: 1, connectedDurationMs: 1_200, reconnectingDurationMs: 0, disconnectedDurationMs: 200, transportBufferedAmountBytes: 0, lastDisconnectCode: 1006, lastDisconnectReason: "abnormal", }, recovery: { supported: true, reconnectCount: 1, recoverySuccessCount: 0, terminalDisconnectCount: 1, currentReconnectAttempt: 1, nextReconnectDelayMs: 250, remainingReconnectAttempts: 0, lastRecoveryDurationMs: null, avgRecoveryDurationMs: null, p95RecoveryDurationMs: null, }, }); const report = buildReport({ auditState, resilienceStatus: auditState.checkpoints[auditState.checkpoints.length - 1]?.resilienceStatus ?? null, metricsSnapshot, now: 1_700_000_001_500, }); expect(report.summary.outcome).toBe("failed"); assertFindingCodes(report, ["terminal_disconnect_observed"]); expect(report.health.connection.status).toBe("critical"); expect(report.health.recovery.status).toBe("critical"); expect(report.dashboard.heroStats.finalTranscriptCount).toBe(0); }); it("keeps unsupported groups explicit and avoids inventing metrics-derived health", () => { const auditState = createBaseAuditState({ finalDigests: [], transcriptMilestones: [], phases: [{ type: "ready", timestamp: 1_700_000_000_100 }], checkpoints: [ { timestamp: 1_700_000_000_100, resilienceStatus: createStatus({ timestamp: 1_700_000_000_100, connectionState: "connecting", websocketState: "connecting", }), metricsSnapshot: null, }, ], stoppedAt: null, }); const report = buildReport({ auditState, resilienceStatus: auditState.checkpoints[0]?.resilienceStatus ?? null, metricsSnapshot: createAuditUnsupportedMetricsSnapshot(), now: 1_700_000_000_200, }); expect(report.health.transcriptUi.supported).toBe(false); expect(report.health.connection.supported).toBe(false); expect(report.health.buffering.supported).toBe(false); expect(report.summary.partialTranscriptCount).toBe(0); expect(report.summary.finalTranscriptCount).toBe(0); expect(report.findings).toEqual([]); }); const findingCases = [ { name: "duplicate finals", mutate: () => ({ auditState: createBaseAuditState({ finalDigests: [ { digest: "dup", timestamp: 1_700_000_001_200 }, { digest: "dup", timestamp: 1_700_000_001_500 }, ], }), metricsSnapshot: createMetricsSnapshot(), expected: ["duplicate_final_transcripts"], }), }, { name: "drain stall", mutate: () => ({ auditState: createBaseAuditState({ checkpoints: [ { timestamp: 1_700_000_000_100, resilienceStatus: createStatus({ timestamp: 1_700_000_000_100, connectionState: "connected", websocketState: "open", isBufferingAudio: true, isDrainingAudio: true, bufferingStartedAt: 1_700_000_000_100, drainStartedAt: 1_700_000_000_200, drainExitReason: "stalled", totalBufferedAudioBytes: 4_096, pendingBufferedAudioBytes: 4_096, persistedBufferedAudioBytes: 0, persistedBufferedAudioSegments: 1, drainCycles: 1, lastDrainProgressAt: 1_700_000_000_300, }), metricsSnapshot: null, }, ], incidents: [ { type: "drain_stalled", timestamp: 1_700_000_000_100, endedAt: null, detail: { drainExitReason: "stalled", finishDeliveryState: "timed_out", }, }, ], finalDigests: [], transcriptMilestones: [], }), metricsSnapshot: createMetricsSnapshot({ buffering: { supported: true, isBufferingAudio: true, isDrainingAudio: true, pendingBufferedAudioBytes: 4_096, persistedBufferedAudioBytes: 0, persistedBufferedAudioSegments: 1, totalBufferedAudioBytes: 4_096, peakBufferedAudioBytes: 4_096, bufferingDurationMs: 1_000, drainingDurationMs: 900, lastDrainProgressAt: 1_700_000_000_300, drainCycles: 1, drainExitReason: "stalled", finishDeliveryState: "timed_out", avgBufferGrowthRateBytesPerSecond: 128, avgBufferDrainRateBytesPerSecond: null, bufferStallCount: 1, }, }), expected: ["drain_stalled"], }), }, { name: "offline flaps", mutate: () => ({ auditState: createRecoveredAuditState(), metricsSnapshot: createMetricsSnapshot({ browserNetwork: { supported: true, onlineTransitionCount: 3, offlineTransitionCount: 2, offlineDurationMs: 1_100, flapCount: 2, effectiveType: "4g", downlinkMbps: 20, rttMs: 140, }, }), expected: ["offline_flaps_detected"], }), }, { name: "clipping", mutate: () => ({ auditState: createBaseAuditState(), metricsSnapshot: createMetricsSnapshot({ audioCapture: { supported: true, inputSampleRate: 44_100, targetSampleRate: 16_000, channelCount: 1, currentRms: 0.2, peakRms: 0.95, currentPeakAmplitude: 0.995, clippingEventCount: 2, silenceRatio: 0.1, speechActivityRatio: 0.9, audioCallbackGapCount: 0, longestAudioCallbackGapMs: null, }, }), expected: ["audio_clipping_detected"], }), }, { name: "callback gaps", mutate: () => ({ auditState: createBaseAuditState(), metricsSnapshot: createMetricsSnapshot({ audioCapture: { supported: true, inputSampleRate: 44_100, targetSampleRate: 16_000, channelCount: 1, currentRms: 0.05, peakRms: 0.2, currentPeakAmplitude: 0.4, clippingEventCount: 0, silenceRatio: 0.2, speechActivityRatio: 0.8, audioCallbackGapCount: 3, longestAudioCallbackGapMs: 220, }, }), expected: ["audio_callback_gaps_detected"], }), }, ] as const; it.each(findingCases)("$name", ({ mutate }) => { const { auditState, metricsSnapshot, expected } = mutate(); const report = buildReport({ auditState, resilienceStatus: auditState.checkpoints[auditState.checkpoints.length - 1]?.resilienceStatus ?? null, metricsSnapshot, now: 1_700_000_002_000, }); assertFindingCodes(report, expected); }); });