// SPEC: PJ2026-01040111 long-running Workbench observation.
// Responsibility: Analyzer recent-window, page provenance, and Navigation Timing API performance source fragment.

export function nodeWebObserveAnalyzerWindowPageSource(): string {
  return String.raw`async function buildRecentAnalysisWindow({ samples, control, network, consoleEvents, errors, artifacts, browserProcessRows, performanceRows, manifest }) {
  const latestSampleMs = latestTimestampMs(samples);
  const windowMs = 5 * 60 * 1000;
  const fromMs = Number.isFinite(latestSampleMs) ? latestSampleMs - windowMs : Number.NEGATIVE_INFINITY;
  const toMs = Number.isFinite(latestSampleMs) ? latestSampleMs : Number.POSITIVE_INFINITY;
  const inWindow = (item) => {
    const tsMs = Date.parse(item?.ts);
    return Number.isFinite(tsMs) && tsMs >= fromMs && tsMs <= toMs;
  };
  const windowSamples = samples.filter(inWindow);
  const windowControl = control.filter(inWindow);
  const windowNetwork = network.filter(inWindow);
  const windowConsole = consoleEvents.filter(inWindow);
  const windowErrors = errors.filter(inWindow);
  const windowArtifacts = (artifacts || []).filter(inWindow);
  const windowBrowserProcessRows = (browserProcessRows || []).filter(inWindow);
  const windowPerformanceRows = (performanceRows || []).filter(inWindow);
  const sampleMetrics = buildSampleMetrics(windowSamples, control);
  const pageProvenance = buildPageProvenanceReport(windowSamples, windowControl, manifest);
  const pagePerformance = buildPagePerformanceReport(windowSamples, manifest);
  const requestRate = buildRequestRateReport(windowNetwork);
  const promptNetwork = buildPromptNetworkReport(windowControl, windowNetwork);
  const runtimeAlerts = buildRuntimeAlerts(windowSamples, control, windowNetwork, windowConsole, windowErrors);
  const apiDomLag = buildApiDomLagReport(windowSamples, windowNetwork);
  const browserProcess = buildBrowserProcessReport(windowBrowserProcessRows);
  const frontendPerformance = await buildFrontendPerformanceReport(windowPerformanceRows, windowArtifacts, windowSamples, windowNetwork);
  const findings = buildFindings(windowSamples, control, windowNetwork, windowErrors, sampleMetrics, promptNetwork, runtimeAlerts, pagePerformance, requestRate, pageProvenance, [], {}, apiDomLag, browserProcess, frontendPerformance);
  return {
    summary: {
      name: "recent-5m",
      windowMs,
      fromAt: Number.isFinite(fromMs) ? new Date(fromMs).toISOString() : null,
      toAt: Number.isFinite(toMs) ? new Date(toMs).toISOString() : null,
      samples: windowSamples.length,
      control: windowControl.length,
      network: windowNetwork.length,
      console: windowConsole.length,
      errors: windowErrors.length,
      artifacts: windowArtifacts.length,
      browserProcess: windowBrowserProcessRows.length,
      performance: windowPerformanceRows.length,
      valuesRedacted: true
    },
    sampleMetrics,
    pageProvenance,
    pagePerformance,
    requestRate,
    promptNetwork,
    runtimeAlerts,
    apiDomLag,
    browserProcess,
    frontendPerformance,
    findings,
    valuesRedacted: true
  };
}

function latestTimestampMs(items) {
  let latest = Number.NEGATIVE_INFINITY;
  for (const item of items || []) {
    const tsMs = Date.parse(item?.ts);
    if (Number.isFinite(tsMs) && tsMs > latest) latest = tsMs;
  }
  return latest;
}

function buildPageProvenanceReport(samples, control, manifest) {
  const groups = new Map();
  for (const sample of samples) {
    const provenance = sample?.pageProvenance;
    if (!provenance) continue;
    const key = provenance.assetFingerprint || "unknown";
    const group = groups.get(key) || {
      assetFingerprint: provenance.assetFingerprint || null,
      pageLoadSeqs: [],
      sampleCount: 0,
      firstSeq: sample.seq ?? null,
      lastSeq: sample.seq ?? null,
      firstAt: sample.ts ?? null,
      lastAt: sample.ts ?? null,
      urlPaths: [],
      scriptCount: provenance.scriptCount ?? null,
      stylesheetCount: provenance.stylesheetCount ?? null,
      metaCount: provenance.metaCount ?? null,
      scripts: Array.isArray(provenance.scripts) ? provenance.scripts.slice(0, 12) : [],
      stylesheets: Array.isArray(provenance.stylesheets) ? provenance.stylesheets.slice(0, 12) : [],
      valuesRedacted: true
    };
    group.sampleCount += 1;
    group.lastSeq = sample.seq ?? null;
    group.lastAt = sample.ts ?? null;
    if (provenance.pageLoadSeq !== null && provenance.pageLoadSeq !== undefined && !group.pageLoadSeqs.includes(provenance.pageLoadSeq)) group.pageLoadSeqs.push(provenance.pageLoadSeq);
    if (provenance.urlPath && !group.urlPaths.includes(provenance.urlPath)) group.urlPaths.push(provenance.urlPath);
    groups.set(key, group);
  }
  const segments = Array.from(groups.values()).sort((a, b) => Number(a.firstSeq ?? 0) - Number(b.firstSeq ?? 0));
  const controlSegments = control
    .filter((item) => item.type === "page-provenance" || item?.pageProvenance)
    .map((item) => ({
      ts: item.ts ?? null,
      reason: item.reason ?? item.detail?.reason ?? null,
      httpStatus: item.httpStatus ?? item.detail?.httpStatus ?? null,
      pageProvenance: item.pageProvenance ?? item.detail?.pageProvenance ?? null,
    }))
    .slice(0, 80);
  return {
    summary: {
      segmentCount: segments.length,
      sampleCount: segments.reduce((sum, item) => sum + item.sampleCount, 0),
      manifestFingerprint: manifest?.pageProvenance?.assetFingerprint ?? null,
      controlSegmentCount: controlSegments.length
    },
    segments,
    controlSegments,
    valuesRedacted: true
  };
}

function buildPagePerformanceReport(samples, manifest) {
  const base = manifest?.baseUrl || "http://invalid.local";
  const seen = new Set();
  const groups = new Map();
  const sampleTimes = samples.map((sample) => Date.parse(sample?.ts || "")).filter(Number.isFinite);
  const windowStartMs = sampleTimes.length > 0 ? Math.min(...sampleTimes) : null;
  const windowEndMs = sampleTimes.length > 0 ? Math.max(...sampleTimes) : null;
  for (const sample of samples) {
    const entries = Array.isArray(sample?.performance) ? sample.performance : [];
    for (const entry of entries) {
      const durationMs = Number(entry?.duration);
      if (!Number.isFinite(durationMs) || durationMs < 0) continue;
      const entryCompletedMs = performanceEntryCompletedEpochMs(sample, entry);
      if (windowStartMs !== null && entryCompletedMs !== null && entryCompletedMs < windowStartMs) continue;
      if (windowEndMs !== null && entryCompletedMs !== null && entryCompletedMs > windowEndMs + 1000) continue;
      const entryTs = entryCompletedMs === null ? (sample.ts ?? null) : new Date(entryCompletedMs).toISOString();
      const parsed = parsePerformanceUrl(entry?.name, base);
      if (!parsed.sameOrigin || !isApiLikePath(parsed.path)) continue;
      const normalizedPath = normalizeApiPath(parsed.path);
      const routeKind = classifyApiPerformanceRoute(normalizedPath, entry);
      const isLongLivedStream = routeKind === "same-origin-api-stream";
      const streamOpenMs = streamOpenLatencyMs(entry);
      const timingStatus = resourceTimingPhaseStatus(entry);
      const dedupeKey = [parsed.path, entry.initiatorType || "", sample?.pageProvenance?.pageLoadSeq ?? "", sample?.pageProvenance?.timeOrigin ?? "", entry.startTime ?? "", Math.round(durationMs)].join("|");
      if (seen.has(dedupeKey)) continue;
      seen.add(dedupeKey);
      const group = groups.get(normalizedPath) || {
        routeKind,
        path: normalizedPath,
        isLongLivedStream,
        budgetMetric: isLongLivedStream ? "streamOpenMs" : "durationMs",
        rawPathSamples: [],
        sampleCount: 0,
        completeTimingSampleCount: 0,
        partialTimingSampleCount: 0,
        durationsMs: [],
        streamOpenDurationsMs: [],
        overFiveSecondCount: 0,
        overBudgetCount: 0,
        partialOverFiveSecondCount: 0,
        partialOverBudgetCount: 0,
        streamLifetimeOverFiveSecondCount: 0,
        streamOpenOverFiveSecondCount: 0,
        streamOpenOverBudgetCount: 0,
        firstAt: entryTs,
        lastAt: entryTs,
        firstSeq: sample.seq ?? null,
        lastSeq: sample.seq ?? null,
        initiatorTypes: [],
        pageAssetFingerprints: [],
        slowSamples: [],
        partialSamples: [],
        valuesRedacted: true
      };
      group.sampleCount += 1;
      const partialOrdinaryTiming = !isLongLivedStream && timingStatus.status !== "complete";
      let overBudget = false;
      if (partialOrdinaryTiming) {
        group.partialTimingSampleCount += 1;
        if (durationMs > 5000) group.partialOverFiveSecondCount += 1;
        if (durationMs > alertThresholds.partialApiSlowMs) {
          group.partialOverBudgetCount += 1;
          if (group.partialSamples.length < 80) group.partialSamples.push(compactPagePerformanceSlowSample({ sample, entry, entryTs, normalizedPath, rawPath: parsed.path, durationMs, streamOpenMs }));
        }
      } else {
        group.completeTimingSampleCount += 1;
        group.durationsMs.push(durationMs);
        if (isLongLivedStream) {
          if (durationMs > 5000) group.streamLifetimeOverFiveSecondCount += 1;
          if (streamOpenMs !== null) {
            group.streamOpenDurationsMs.push(streamOpenMs);
            if (streamOpenMs > 5000) {
              group.streamOpenOverFiveSecondCount += 1;
              group.overFiveSecondCount += 1;
            }
            if (streamOpenMs > alertThresholds.longLivedStreamOpenSlowMs) {
              group.streamOpenOverBudgetCount += 1;
              group.overBudgetCount += 1;
              overBudget = true;
            }
          }
        } else {
          if (durationMs > 5000) group.overFiveSecondCount += 1;
          if (durationMs > alertThresholds.sameOriginApiSlowMs) {
            group.overBudgetCount += 1;
            overBudget = true;
          }
        }
      }
      if (overBudget && group.slowSamples.length < 80) group.slowSamples.push(compactPagePerformanceSlowSample({ sample, entry, entryTs, normalizedPath, rawPath: parsed.path, durationMs, streamOpenMs }));
      group.lastAt = entryTs;
      group.lastSeq = sample.seq ?? null;
      if (parsed.path && !group.rawPathSamples.includes(parsed.path)) group.rawPathSamples.push(parsed.path);
      if (entry.initiatorType && !group.initiatorTypes.includes(entry.initiatorType)) group.initiatorTypes.push(entry.initiatorType);
      const assetFingerprint = sample?.pageProvenance?.assetFingerprint;
      if (assetFingerprint && !group.pageAssetFingerprints.includes(assetFingerprint)) group.pageAssetFingerprints.push(assetFingerprint);
      groups.set(normalizedPath, group);
    }
  }
  const sameOriginApiByPath = Array.from(groups.values()).map((group) => {
    const durations = group.durationsMs.slice().sort((a, b) => a - b);
    const streamOpenDurations = group.streamOpenDurationsMs.slice().sort((a, b) => a - b);
    return {
      routeKind: group.routeKind,
      path: group.path,
      isLongLivedStream: group.isLongLivedStream === true,
      budgetMetric: group.budgetMetric,
      sampleCount: group.sampleCount,
      budgetMs: group.isLongLivedStream === true ? alertThresholds.longLivedStreamOpenSlowMs : alertThresholds.sameOriginApiSlowMs,
      partialBudgetMs: alertThresholds.partialApiSlowMs,
      streamOpenBudgetMs: alertThresholds.longLivedStreamOpenSlowMs,
      completeTimingSampleCount: group.completeTimingSampleCount,
      partialTimingSampleCount: group.partialTimingSampleCount,
      p50Ms: percentile(durations, 50),
      p75Ms: percentile(durations, 75),
      p95Ms: percentile(durations, 95),
      maxMs: durations.length > 0 ? durations[durations.length - 1] : null,
      streamOpenSampleCount: streamOpenDurations.length,
      streamOpenP50Ms: percentile(streamOpenDurations, 50),
      streamOpenP75Ms: percentile(streamOpenDurations, 75),
      streamOpenP95Ms: percentile(streamOpenDurations, 95),
      streamOpenMaxMs: streamOpenDurations.length > 0 ? streamOpenDurations[streamOpenDurations.length - 1] : null,
      streamOpenOverFiveSecondCount: group.streamOpenOverFiveSecondCount,
      streamOpenOverBudgetCount: group.streamOpenOverBudgetCount,
      streamLifetimeOverFiveSecondCount: group.streamLifetimeOverFiveSecondCount,
      overFiveSecondCount: group.overFiveSecondCount,
      overBudgetCount: group.overBudgetCount,
      partialOverFiveSecondCount: group.partialOverFiveSecondCount,
      partialOverBudgetCount: group.partialOverBudgetCount,
      overFiveSecondRatio: group.sampleCount > 0 ? Number((group.overFiveSecondCount / group.sampleCount).toFixed(3)) : 0,
      overBudgetRatio: group.sampleCount > 0 ? Number((group.overBudgetCount / group.sampleCount).toFixed(3)) : 0,
      firstAt: group.firstAt,
      lastAt: group.lastAt,
      firstSeq: group.firstSeq,
      lastSeq: group.lastSeq,
      initiatorTypes: group.initiatorTypes,
      rawPathSamples: group.rawPathSamples.slice(0, 8),
      pageAssetFingerprints: group.pageAssetFingerprints.slice(0, 8),
      slowSamples: group.slowSamples
        .slice()
        .sort((a, b) => Number(b.durationMs ?? 0) - Number(a.durationMs ?? 0))
        .slice(0, 12),
      partialSamples: group.partialSamples
        .slice()
        .sort((a, b) => Number(b.durationMs ?? 0) - Number(a.durationMs ?? 0))
        .slice(0, 12),
      valuesRedacted: true
    };
  }).sort((a, b) => (Number(b.overBudgetCount ?? b.overFiveSecondCount ?? 0) - Number(a.overBudgetCount ?? a.overFiveSecondCount ?? 0)) || (Number(b.p95Ms ?? 0) - Number(a.p95Ms ?? 0)) || a.path.localeCompare(b.path));
  const longLivedStreams = sameOriginApiByPath.filter((item) => item.isLongLivedStream);
  const ordinaryApi = sameOriginApiByPath.filter((item) => item.isLongLivedStream !== true);
  const slow = ordinaryApi.filter((item) => Number(item.overBudgetCount ?? item.overFiveSecondCount ?? 0) > 0);
  const slowFiveSecond = ordinaryApi.filter((item) => Number(item.overFiveSecondCount ?? 0) > 0);
  const partialSlow = ordinaryApi.filter((item) => Number(item.partialOverBudgetCount ?? item.partialOverFiveSecondCount ?? 0) > 0);
  const partialFiveSecond = ordinaryApi.filter((item) => Number(item.partialOverFiveSecondCount ?? 0) > 0);
  const slowStreamOpen = longLivedStreams.filter((item) => Number(item.streamOpenOverBudgetCount ?? item.streamOpenOverFiveSecondCount ?? 0) > 0);
  const slowStreamOpenFiveSecond = longLivedStreams.filter((item) => Number(item.streamOpenOverFiveSecondCount ?? 0) > 0);
  const budgetP95Values = sameOriginApiByPath
    .map((item) => Number(item.isLongLivedStream ? (item.streamOpenP95Ms ?? 0) : (item.p95Ms ?? 0)))
    .filter((value) => Number.isFinite(value));
  return {
    summary: {
      budgetMs: alertThresholds.sameOriginApiSlowMs,
      alertThresholds,
      sameOriginApiPathCount: sameOriginApiByPath.length,
      sameOriginApiSampleCount: sameOriginApiByPath.reduce((sum, item) => sum + item.sampleCount, 0),
      longLivedStreamPathCount: longLivedStreams.length,
      longLivedStreamSampleCount: longLivedStreams.reduce((sum, item) => sum + item.sampleCount, 0),
      longLivedStreamOpenOverFiveSecondPathCount: slowStreamOpenFiveSecond.length,
      longLivedStreamOpenOverFiveSecondSampleCount: slowStreamOpenFiveSecond.reduce((sum, item) => sum + Number(item.streamOpenOverFiveSecondCount ?? 0), 0),
      longLivedStreamOpenOverBudgetPathCount: slowStreamOpen.length,
      longLivedStreamOpenOverBudgetSampleCount: slowStreamOpen.reduce((sum, item) => sum + Number(item.streamOpenOverBudgetCount ?? item.streamOpenOverFiveSecondCount ?? 0), 0),
      longLivedStreamLifetimeOverFiveSecondSampleCount: longLivedStreams.reduce((sum, item) => sum + Number(item.streamLifetimeOverFiveSecondCount ?? 0), 0),
      slowPathCount: slow.length,
      slowSampleCount: slow.reduce((sum, item) => sum + Number(item.overBudgetCount ?? item.overFiveSecondCount ?? 0), 0),
      overFiveSecondPathCount: slowFiveSecond.length,
      overFiveSecondSampleCount: slowFiveSecond.reduce((sum, item) => sum + Number(item.overFiveSecondCount ?? 0), 0),
      partialTimingSampleCount: ordinaryApi.reduce((sum, item) => sum + Number(item.partialTimingSampleCount ?? 0), 0),
      partialOverFiveSecondPathCount: partialFiveSecond.length,
      partialOverFiveSecondSampleCount: partialFiveSecond.reduce((sum, item) => sum + Number(item.partialOverFiveSecondCount ?? 0), 0),
      partialOverBudgetPathCount: partialSlow.length,
      partialOverBudgetSampleCount: partialSlow.reduce((sum, item) => sum + Number(item.partialOverBudgetCount ?? item.partialOverFiveSecondCount ?? 0), 0),
      worstP95Ms: budgetP95Values.length > 0 ? Math.max(...budgetP95Values) : null,
      valuesRedacted: true
    },
    sameOriginApiByPath,
    valuesRedacted: true
  };
}

function performanceEntryCompletedEpochMs(sample, entry) {
  const origin = Number(sample?.pageProvenance?.timeOrigin);
  const responseEnd = Number(entry?.responseEnd);
  const startTime = Number(entry?.startTime);
  const offset = Number.isFinite(responseEnd) && responseEnd > 0 ? responseEnd : startTime;
  if (Number.isFinite(origin) && origin > 0 && Number.isFinite(offset) && offset >= 0) return Math.round(origin + offset);
  const sampleTs = Date.parse(sample?.ts || "");
  return Number.isFinite(sampleTs) ? sampleTs : null;
}

function compactPagePerformanceSlowSample({ sample, entry, entryTs, normalizedPath, rawPath, durationMs, streamOpenMs }) {
  const timingStatus = resourceTimingPhaseStatus(entry);
  const serverTiming = compactServerTiming(entry?.serverTiming);
  return {
    ts: entryTs ?? sample?.ts ?? null,
    sampleTs: sample?.ts ?? null,
    seq: sample?.seq ?? null,
    path: normalizedPath ?? null,
    rawPath: rawPath ?? null,
    initiatorType: entry?.initiatorType ?? null,
    durationMs: roundFinite(durationMs),
    startTimeMs: roundFinite(entry?.startTime),
    fetchStartMs: roundFinite(entry?.fetchStart),
    requestStartMs: roundFinite(entry?.requestStart),
    responseStartMs: roundFinite(entry?.responseStart),
    responseEndMs: roundFinite(entry?.responseEnd),
    streamOpenMs: roundFinite(streamOpenMs),
    dnsMs: phaseDeltaMs(entry, "domainLookupEnd", "domainLookupStart"),
    tcpMs: phaseDeltaMs(entry, "connectEnd", "connectStart"),
    tlsStartMs: roundFinite(entry?.secureConnectionStart),
    requestToResponseStartMs: phaseDeltaMs(entry, "responseStart", "requestStart"),
    responseTransferMs: phaseDeltaMs(entry, "responseEnd", "responseStart"),
    timingStatus: timingStatus.status,
    invalidTimingPhases: timingStatus.invalidPhases,
    partialTimingPhases: timingStatus.partialPhases,
    transferSize: Number.isFinite(Number(entry?.transferSize)) ? Number(entry.transferSize) : null,
    encodedBodySize: Number.isFinite(Number(entry?.encodedBodySize)) ? Number(entry.encodedBodySize) : null,
    decodedBodySize: Number.isFinite(Number(entry?.decodedBodySize)) ? Number(entry.decodedBodySize) : null,
    nextHopProtocol: entry?.nextHopProtocol ?? null,
    serverTiming,
    serverTimingNames: serverTiming.map((item) => item.name).filter(Boolean).slice(0, 8),
    otelTraceId: extractOtelTraceIdFromServerTiming(serverTiming),
    valuesRedacted: true
  };
}

function phaseDeltaMs(entry, endKey, startKey) {
  const end = Number(entry?.[endKey]);
  const start = Number(entry?.[startKey]);
  if (!Number.isFinite(end) || !Number.isFinite(start) || end <= 0 || start <= 0 || end < start) return null;
  return Math.round(end - start);
}

function resourceTimingPhaseStatus(entry) {
  const pairs = [
    ["requestToResponseStart", "requestStart", "responseStart"],
    ["responseTransfer", "responseStart", "responseEnd"],
  ];
  const invalidPhases = [];
  const partialPhases = [];
  for (const [label, startKey, endKey] of pairs) {
    const start = Number(entry?.[startKey]);
    const end = Number(entry?.[endKey]);
    if (!Number.isFinite(start) || !Number.isFinite(end) || start <= 0 || end <= 0) {
      partialPhases.push(label);
    } else if (end < start) {
      invalidPhases.push(label);
    }
  }
  return {
    status: invalidPhases.length > 0 ? "invalid" : (partialPhases.length > 0 ? "partial" : "complete"),
    invalidPhases,
    partialPhases,
  };
}

function compactServerTiming(value) {
  const items = Array.isArray(value) ? value : [];
  return items.slice(0, 8).map((item) => ({
    name: truncate(String(item?.name || ""), 80),
    duration: Number.isFinite(Number(item?.duration)) ? Math.round(Number(item.duration)) : null,
    description: truncate(String(item?.description || ""), 120),
  })).filter((item) => item.name || item.description || item.duration !== null);
}

function extractOtelTraceIdFromServerTiming(items) {
  const text = (Array.isArray(items) ? items : []).map((item) => [item.name, item.description].filter(Boolean).join(" ")).join(" ");
  const match = text.match(/\b[0-9a-f]{32}\b/iu);
  return match ? match[0].toLowerCase() : null;
}

function roundFinite(value) {
  const numeric = Number(value);
  return Number.isFinite(numeric) ? Math.round(numeric) : null;
}

function classifyApiPerformanceRoute(normalizedPath, entry = {}) {
  if (normalizedPath === "/v1/workbench/events") return "same-origin-api-stream";
  if (String(entry?.initiatorType ?? "").toLowerCase() === "eventsource") return "same-origin-api-stream";
  return "same-origin-api";
}

function streamOpenLatencyMs(entry = {}) {
  const responseStart = Number(entry?.responseStart);
  const startTime = Number(entry?.startTime);
  if (!Number.isFinite(responseStart) || responseStart <= 0) return null;
  if (!Number.isFinite(startTime) || startTime < 0) return Math.max(0, responseStart);
  if (responseStart < startTime) return null;
  return Math.max(0, responseStart - startTime);
}

function parsePerformanceUrl(value, base) {
  try {
    const url = new URL(String(value || ""), base);
    const origin = new URL(String(base || "http://invalid.local")).origin;
    return { sameOrigin: url.origin === origin, path: url.pathname };
  } catch {
    return { sameOrigin: false, path: "-" };
  }
}

function isApiLikePath(path) {
  return /^\/(?:v1(?:\/|$)|auth(?:\/|$)|health(?:\/|$))/u.test(String(path || ""));
}

function normalizeApiPath(path) {
  return String(path || "-")
    .replace(/\/v1\/workbench\/sessions\/ses_[^/]+/gu, "/v1/workbench/sessions/:id")
    .replace(/\/v1\/workbench\/turns\/trc_[^/]+/gu, "/v1/workbench/turns/:traceId")
    .replace(/\/v1\/workbench\/traces\/trc_[^/]+/gu, "/v1/workbench/traces/:traceId")
    .replace(/\/v1\/workbench\/sessions\/[0-9a-f-]{12,}/giu, "/v1/workbench/sessions/:id")
    .replace(/\/v1\/[^/]+\/[0-9a-f-]{16,}(?=\/|$)/giu, (match) => match.replace(/\/[0-9a-f-]{16,}$/iu, "/:id"));
}

function percentile(sortedValues, percentileValue) {
  if (!Array.isArray(sortedValues) || sortedValues.length === 0) return null;
  if (sortedValues.length === 1) return Math.round(sortedValues[0]);
  const rank = (percentileValue / 100) * (sortedValues.length - 1);
  const lower = Math.floor(rank);
  const upper = Math.ceil(rank);
  if (lower === upper) return Math.round(sortedValues[lower]);
  const weight = rank - lower;
  return Math.round(sortedValues[lower] * (1 - weight) + sortedValues[upper] * weight);
}
`;
}
