Back to Delivery 2 Reusable Quality Utilities

delivery-02-reusable-quality-utilities/src/summary.ts

import type { QualityEvidenceSummary, QualityExecutionResult } from "./models.js";

function isFailedExecution(result: QualityExecutionResult): boolean {
  return !result.validationPassed || result.statusCode >= 400;
}

function isSlowExecution(result: QualityExecutionResult, thresholdMs: number): boolean {
  return result.responseTimeMs > thresholdMs;
}

/**
 * Produces a summary from already trusted input. The selected threshold is an
 * explicit policy input, not a universal definition of acceptable latency.
 */
export function summariseQualityExecutionResults(
  results: readonly QualityExecutionResult[],
  slowResponseThresholdMs: number,
): QualityEvidenceSummary {
  if (!Number.isFinite(slowResponseThresholdMs) || slowResponseThresholdMs < 0) {
    throw new Error("slowResponseThresholdMs must be a non-negative finite number.");
  }

  const failureCountByEndpoint = new Map<string, number>();
  const slowEndpoints = new Set<string>();
  let failedExecutionCount = 0;
  let slowExecutionCount = 0;

  for (const result of results) {
    if (isFailedExecution(result)) {
      failedExecutionCount += 1;
      failureCountByEndpoint.set(
        result.endpoint,
        (failureCountByEndpoint.get(result.endpoint) ?? 0) + 1,
      );
    }

    if (isSlowExecution(result, slowResponseThresholdMs)) {
      slowExecutionCount += 1;
      slowEndpoints.add(result.endpoint);
    }
  }

  return {
    executionCount: results.length,
    failedExecutionCount,
    slowExecutionCount,
    failureCountByEndpoint: Object.fromEntries(failureCountByEndpoint),
    slowEndpoints: [...slowEndpoints].sort(),
  };
}