Back to Quality Engineering Toolkit

capstone-quality-engineering-toolkit/src/normalisation.ts

import { ToolkitError } from "./errors.js";
import type { ExecutionRecord, NormalisedExecutions } from "./models.js";

function normaliseText(value: string): string {
  return value.trim().replaceAll(/\s+/g, " ");
}

function normaliseRecord(record: ExecutionRecord): ExecutionRecord {
  return {
    ...record,
    executionId: normaliseText(record.executionId),
    operation: normaliseText(record.operation),
    environment: normaliseText(record.environment).toLowerCase(),
    ...(record.diagnosticCode === undefined ? {} : { diagnosticCode: normaliseText(record.diagnosticCode) }),
  };
}

function isSameLogicalExecution(left: ExecutionRecord, right: ExecutionRecord): boolean {
  return (
    left.executionId === right.executionId &&
    left.operation === right.operation &&
    left.environment === right.environment &&
    left.outcome === right.outcome &&
    left.durationMs === right.durationMs &&
    left.timestamp === right.timestamp &&
    left.diagnosticCode === right.diagnosticCode
  );
}

/**
 * Normalises presentation-level values and removes exact replayed records.
 * A duplicate identifier with conflicting evidence is rejected rather than
 * silently choosing a record and distorting the resulting quality evidence.
 */
export function normaliseAndDeduplicate(
  records: readonly ExecutionRecord[],
): NormalisedExecutions {
  const logicalExecutions = new Map<string, ExecutionRecord>();
  let duplicateExecutionCount = 0;

  for (const rawRecord of records) {
    const record = normaliseRecord(rawRecord);
    const existing = logicalExecutions.get(record.executionId);
    if (existing === undefined) {
      logicalExecutions.set(record.executionId, record);
      continue;
    }

    if (!isSameLogicalExecution(existing, record)) {
      throw new ToolkitError(
        "invalid-input",
        "A duplicate executionId contains conflicting evidence.",
        {
          operation: "deduplicate-executions",
          executionId: record.executionId,
          expected: "identical replayed execution evidence",
        },
      );
    }

    duplicateExecutionCount += 1;
  }

  return {
    receivedRecordCount: records.length,
    executions: [...logicalExecutions.values()],
    duplicateExecutionCount,
  };
}