/*
aggregation — combine certification evaluation inputs into the aggregate verdict.
- Do not evaluate individual checks — aggregation consumes their results.
- RFC-1097: sweep — werkstatt-engine clean
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.
*/
import type {
CertificationPolicyBundleV1,
CoverageReportV1,
SelectedEvidenceV1,
} from "./contracts/index.ts";
import type { Sha256Digest } from "@warpgogol/werkstatt-shared/fingerprint";
import {
buildEvidenceIndex,
selectRequirementEvidence,
type RequirementStatus,
} from "./evidence-selection.ts";
export type CertificationEvaluationInputV1 = {
readonly candidateId: string;
readonly policyBundle: CertificationPolicyBundleV1;
readonly evidence: readonly import("./contracts/index.ts").EvidenceEnvelopeV1[];
readonly evaluationCutSequence: number;
readonly authorityTime: string;
readonly gate: "dev" | "alt" | "main";
readonly decidedAt: string;
};
export type RequirementEvaluationV1 = {
readonly requirementId: string;
readonly status: RequirementStatus;
readonly selectedEvidenceId: string | null;
readonly selectedEvidenceHash: Sha256Digest | null;
readonly reasonCode: string;
readonly reasonMessage: string;
};
export type CertificationEvaluationResultV1 =
| {
readonly ok: true;
readonly candidateId: string;
readonly gate: "dev" | "alt" | "main";
readonly evaluationCut: number;
readonly status: "pass" | "fail" | "stale" | "incomplete";
readonly requirements: readonly RequirementEvaluationV1[];
readonly selectedEvidence: readonly SelectedEvidenceV1[];
readonly coverage: CoverageReportV1;
readonly reasons: readonly string[];
}
| {
readonly ok: false;
readonly code: "CERT-LIMIT-01" | "CERT-LIMIT-02" | "CERT-GATE-02";
readonly message: string;
};
const STATUS_PRECEDENCE: Record = {
fail: 4,
stale: 3,
incomplete: 2,
pass: 1,
"not-applicable": 0,
};
function aggregateStatus(
statuses: readonly RequirementStatus[],
): "pass" | "fail" | "stale" | "incomplete" {
if (statuses.length === 0) return "incomplete";
let worst: RequirementStatus = "pass";
for (const s of statuses) {
if (s === "not-applicable") continue;
if (STATUS_PRECEDENCE[s] > STATUS_PRECEDENCE[worst]) {
worst = s;
}
}
return worst as "pass" | "fail" | "stale" | "incomplete";
}
export function evaluateCertificationDecision(
input: CertificationEvaluationInputV1,
): CertificationEvaluationResultV1 {
if (input.policyBundle.resolvedRequirements.length > 1000) {
return {
ok: false,
code: "CERT-LIMIT-01",
message: `requirements count ${input.policyBundle.resolvedRequirements.length} exceeds hard limit 1000`,
};
}
if (input.evidence.length > 10000) {
return {
ok: false,
code: "CERT-LIMIT-02",
message: `evidence count ${input.evidence.length} exceeds hard limit 10000`,
};
}
const indexResult = buildEvidenceIndex({
candidateId: input.candidateId,
evidence: input.evidence,
evaluationCutSequence: input.evaluationCutSequence,
});
if ("code" in indexResult) {
return {
ok: false,
code: indexResult.code as "CERT-LIMIT-01" | "CERT-LIMIT-02",
message: indexResult.message,
};
}
const index = indexResult;
const requirementResults: RequirementEvaluationV1[] = [];
const selectedEvidence: SelectedEvidenceV1[] = [];
const uncovered: string[] = [];
const seenEvidenceIds = new Set();
const reasons: string[] = [];
for (const req of input.policyBundle.resolvedRequirements) {
const sel = selectRequirementEvidence(
{
requirement: req,
policyBundle: input.policyBundle,
authorityTime: input.authorityTime,
},
index,
);
requirementResults.push({
requirementId: sel.requirementId,
status: sel.status,
selectedEvidenceId: sel.selectedEvidenceId,
selectedEvidenceHash: sel.selectedEvidenceHash,
reasonCode: sel.reasonCode,
reasonMessage: sel.reasonMessage,
});
if (sel.selectedEvidenceId && !seenEvidenceIds.has(sel.selectedEvidenceId)) {
seenEvidenceIds.add(sel.selectedEvidenceId);
if (sel.selectedEvidenceHash) {
selectedEvidence.push({
evidenceId: sel.selectedEvidenceId,
evidenceHash: sel.selectedEvidenceHash,
selectedAt: input.authorityTime,
});
}
}
if (req.mandatory && sel.status !== "pass" && sel.status !== "not-applicable") {
uncovered.push(req.requirementId);
reasons.push(`${req.requirementId}: ${sel.reasonMessage}`);
}
}
selectedEvidence.sort((a, b) =>
a.evidenceId < b.evidenceId ? -1 : a.evidenceId > b.evidenceId ? 1 : 0,
);
const mandatoryStatuses = requirementResults
.filter((r) => {
const req = input.policyBundle.resolvedRequirements.find(
(rr) => rr.requirementId === r.requirementId,
);
return req?.mandatory;
})
.map((r) => r.status);
const hasMandatory = input.policyBundle.resolvedRequirements.some((r) => r.mandatory);
if (!hasMandatory) {
return {
ok: true,
candidateId: input.candidateId,
gate: input.gate,
evaluationCut: input.evaluationCutSequence,
status: "incomplete",
requirements: requirementResults,
selectedEvidence,
coverage: {
schema: "werkstatt/coverage-report@1",
totalRequirements: input.policyBundle.resolvedRequirements.length,
coveredRequirements: input.policyBundle.resolvedRequirements.length - uncovered.length,
uncoveredRequirements: uncovered,
},
reasons: ["no mandatory requirements — cannot infer pass from empty profile"],
};
}
const status = aggregateStatus(mandatoryStatuses);
return {
ok: true,
candidateId: input.candidateId,
gate: input.gate,
evaluationCut: input.evaluationCutSequence,
status,
requirements: requirementResults,
selectedEvidence,
coverage: {
schema: "werkstatt/coverage-report@1",
totalRequirements: input.policyBundle.resolvedRequirements.length,
coveredRequirements: input.policyBundle.resolvedRequirements.length - uncovered.length,
uncoveredRequirements: uncovered,
},
reasons,
};
}