From bb6f37e777d75e71b26029aa23a2b6cf8ca2b3ad Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 25 May 2026 15:54:29 +0100 Subject: [PATCH] test(qa): annotate live transport RTT measurements --- .../discord/discord-live.runtime.ts | 28 +++++++++++++++++-- .../slack/slack-live.runtime.ts | 18 ++++++++++++ .../telegram/telegram-live.runtime.ts | 18 ++++++++++++ .../whatsapp/whatsapp-live.runtime.ts | 12 ++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts b/extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts index 8e3f87022d9..8930774c49c 100644 --- a/extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts +++ b/extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts @@ -181,7 +181,15 @@ type DiscordQaScenarioResult = { title: string; status: "pass" | "fail"; details: string; + requestStartedAt?: string; + responseObservedAt?: string; rttMs?: number; + rttMeasurement?: { + finalMatchedReplyRttMs: number; + requestStartedAt: string; + responseObservedAt: string; + source: "request-to-observed-message"; + }; }; type DiscordQaRunResult = { @@ -1779,7 +1787,9 @@ export async function runDiscordQaLive(params: { expectedTextIncludes: scenarioRun.expectedTextIncludes, message: matched.message, }); - const rttMs = computeDiscordRttMs(sent.timestamp, matched.message.timestamp); + const requestStartedAt = sent.timestamp; + const responseObservedAt = matched.message.timestamp; + const rttMs = computeDiscordRttMs(requestStartedAt, responseObservedAt); scenarioResults.push({ id: scenario.id, title: scenario.title, @@ -1787,7 +1797,21 @@ export async function runDiscordQaLive(params: { details: redactPublicMetadata ? "reply matched" : `reply message ${matched.message.messageId} matched`, - ...(rttMs === undefined ? {} : { rttMs }), + ...(requestStartedAt === undefined ? {} : { requestStartedAt }), + ...(responseObservedAt === undefined ? {} : { responseObservedAt }), + ...(rttMs === undefined || + requestStartedAt === undefined || + responseObservedAt === undefined + ? {} + : { + rttMs, + rttMeasurement: { + finalMatchedReplyRttMs: rttMs, + requestStartedAt, + responseObservedAt, + source: "request-to-observed-message", + }, + }), }); } catch (error) { if (scenarioRun.kind === "channel-message" && !scenarioRun.expectReply) { diff --git a/extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts b/extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts index 16ca7616ce7..a8c95f2f64d 100644 --- a/extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts +++ b/extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts @@ -200,6 +200,12 @@ type SlackQaScenarioResult = { requestStartedAt?: string; responseObservedAt?: string; rttMs?: number; + rttMeasurement?: { + finalMatchedReplyRttMs: number; + requestStartedAt: string; + responseObservedAt: string; + source: "approval-request-to-resolution" | "request-to-observed-message"; + }; status: "fail" | "pass"; title: string; }; @@ -1859,6 +1865,12 @@ export async function runSlackQaLive(params: { rttMs: approval.rttMs, requestStartedAt: approval.requestStartedAt.toISOString(), responseObservedAt: approval.responseObservedAt.toISOString(), + rttMeasurement: { + finalMatchedReplyRttMs: approval.rttMs, + requestStartedAt: approval.requestStartedAt.toISOString(), + responseObservedAt: approval.responseObservedAt.toISOString(), + source: "approval-request-to-resolution", + }, }); break; } @@ -1911,6 +1923,12 @@ export async function runSlackQaLive(params: { rttMs, requestStartedAt: requestStartedAt.toISOString(), responseObservedAt: responseObservedAt.toISOString(), + rttMeasurement: { + finalMatchedReplyRttMs: rttMs, + requestStartedAt: requestStartedAt.toISOString(), + responseObservedAt: responseObservedAt.toISOString(), + source: "request-to-observed-message", + }, }); } else { await waitForSlackNoReply({ diff --git a/extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts b/extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts index 782a03ba172..e07f86db181 100644 --- a/extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts +++ b/extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts @@ -133,6 +133,12 @@ type TelegramQaScenarioResult = { rttMs?: number; requestStartedAt?: string; responseObservedAt?: string; + rttMeasurement?: { + finalMatchedReplyRttMs: number; + requestStartedAt: string; + responseObservedAt: string; + source: "request-to-observed-message"; + }; sentMessageId?: number; responseMessageId?: number; }; @@ -1743,6 +1749,12 @@ export async function runTelegramQaLive(params: { rttMs: canaryTiming.rttMs, requestStartedAt: canaryTiming.requestStartedAt, responseObservedAt: canaryTiming.responseObservedAt, + rttMeasurement: { + finalMatchedReplyRttMs: canaryTiming.rttMs, + requestStartedAt: canaryTiming.requestStartedAt, + responseObservedAt: canaryTiming.responseObservedAt, + source: "request-to-observed-message", + }, sentMessageId: redactPublicMetadata ? undefined : canaryTiming.sentMessageId, responseMessageId: redactPublicMetadata ? undefined : canaryTiming.responseMessageId, }); @@ -1885,6 +1897,12 @@ export async function runTelegramQaLive(params: { rttMs, requestStartedAt: firstRequestStartedAt, responseObservedAt: new Date(lastMatched.observedAtMs).toISOString(), + rttMeasurement: { + finalMatchedReplyRttMs: rttMs, + requestStartedAt: new Date(lastRequestStartedAtMs).toISOString(), + responseObservedAt: new Date(lastMatched.observedAtMs).toISOString(), + source: "request-to-observed-message", + }, sentMessageId: redactPublicMetadata ? undefined : lastSentMessageId, responseMessageId: redactPublicMetadata ? undefined : lastMatched.message.messageId, } satisfies TelegramQaScenarioResult; diff --git a/extensions/qa-lab/src/live-transports/whatsapp/whatsapp-live.runtime.ts b/extensions/qa-lab/src/live-transports/whatsapp/whatsapp-live.runtime.ts index fa4167a4b69..adf63c5a723 100644 --- a/extensions/qa-lab/src/live-transports/whatsapp/whatsapp-live.runtime.ts +++ b/extensions/qa-lab/src/live-transports/whatsapp/whatsapp-live.runtime.ts @@ -100,6 +100,12 @@ type WhatsAppQaScenarioResult = { requestStartedAt?: string; responseObservedAt?: string; rttMs?: number; + rttMeasurement?: { + finalMatchedReplyRttMs: number; + requestStartedAt: string; + responseObservedAt: string; + source: "request-to-observed-message"; + }; status: "fail" | "pass" | "skip"; title: string; }; @@ -647,6 +653,12 @@ async function runWhatsAppScenario(params: { rttMs, requestStartedAt: requestStartedAt.toISOString(), responseObservedAt: responseObservedAt.toISOString(), + rttMeasurement: { + finalMatchedReplyRttMs: rttMs, + requestStartedAt: requestStartedAt.toISOString(), + responseObservedAt: responseObservedAt.toISOString(), + source: "request-to-observed-message", + }, }; } catch (error) { preservedGatewayDebug = true;