Back to Delivery 4 — Collaborative and Tested Quality Utilities
delivery-04-collaborative-tested-utilities/src/qualitySummary.ts
import { QualityUtilityError } from "./errors.js";
import type { CheckState, QualityObservation, QualitySummary } from "./models.js";
function validateSlowThreshold(slowThresholdMs: number): void {
if (!Number.isFinite(slowThresholdMs) || slowThresholdMs < 0) {
throw new QualityUtilityError(
"invalid-input",
"slowThresholdMs must be a non-negative finite number.",
{ operation: "summarise-quality-observations" },
);
}
}
function countState(observations: readonly QualityObservation[], state: CheckState): number {
return observations.filter((observation) => observation.state === state).length;
}
/**
* The current, reviewable implementation. It owns aggregation only; callers
* retain ownership of acquisition and presentation.
*/
export function summariseQualityObservations(
observations: readonly QualityObservation[],
slowThresholdMs: number,
): QualitySummary {
validateSlowThreshold(slowThresholdMs);
const slowEndpoints = new Set(
observations
.filter((observation) => observation.durationMs >= slowThresholdMs)
.map((observation) => observation.endpoint),
);
return {
executionCount: observations.length,
passedCount: countState(observations, "passed"),
failedCount: countState(observations, "failed"),
pendingCount: countState(observations, "pending"),
slowEndpointCount: slowEndpoints.size,
};
}
/**
* Deliberately retained as a teaching fixture. It represents the observed
* contract before a focused refactor; it is not a second preferred design.
*/
export function legacySummariseQualityObservations(
observations: readonly QualityObservation[],
slowThresholdMs: number,
): QualitySummary {
validateSlowThreshold(slowThresholdMs);
let passedCount = 0;
let failedCount = 0;
let pendingCount = 0;
const slowEndpoints = new Set<string>();
for (const observation of observations) {
if (observation.state === "passed") {
passedCount += 1;
} else if (observation.state === "failed") {
failedCount += 1;
} else {
pendingCount += 1;
}
if (observation.durationMs >= slowThresholdMs) {
slowEndpoints.add(observation.endpoint);
}
}
return {
executionCount: observations.length,
passedCount,
failedCount,
pendingCount,
slowEndpointCount: slowEndpoints.size,
};
}