/*
inspection — certification status inspection command returning the current gate result.
- Do not mutate certification state — inspection is read-only.
- 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 { ReleaseCandidateV1 } from "../contracts/candidate.ts";
import type { GateDecisionV1 } from "../contracts/decisions.ts";
import type { CoverageReportV1 } from "../contracts/decisions.ts";
import type { Sha256Digest } from "@warpgogol/werkstatt-shared/fingerprint";
import type { GateChannel } from "../contracts/identifiers.ts";
import type { DossierRepositoryV1 } from "../storage/repository.ts";
import { verifyDossierIntegrity, buildRootReference } from "../storage/repository.ts";
import { buildReleaseCandidateIdentityV1 } from "../identity.ts";
export interface CertificationStatusResultV1 {
ok: true;
status: {
candidateId: string;
candidateIdentityHash: Sha256Digest;
latestDecisions: Partial>;
coverage: CoverageReportV1 | null;
dossierRootHash: Sha256Digest | null;
eventCount: number;
durableReplicaStatus: "verified" | "not-verified" | "mismatch";
activeIncidents: string[];
nextRequiredAction: string | null;
actionPackLocators: string[];
};
}
export interface CertificationStatusFailureV1 {
ok: false;
ruleId: "CERT-ORCHESTRATOR-08" | "CERT-ORCHESTRATOR-09";
message: string;
}
export type CertificationStatusOutcomeV1 =
CertificationStatusResultV1 | CertificationStatusFailureV1;
export function getCertificationStatus(
candidate: ReleaseCandidateV1,
repository: DossierRepositoryV1,
decisions: Partial>,
coverage: CoverageReportV1 | null,
durableReplicaStatus: "verified" | "not-verified" | "mismatch",
activeIncidents: string[],
actionPackLocators: string[],
): CertificationStatusOutcomeV1 {
const identityResult = buildReleaseCandidateIdentityV1(candidate);
if (!identityResult.ok) {
return {
ok: false,
ruleId: "CERT-ORCHESTRATOR-08",
message: `failed to compute candidate identity: ${identityResult.diagnostic.message}`,
};
}
const rootRef = buildRootReference(repository);
const latestDecisions: Partial> = {};
for (const [gate, decision] of Object.entries(decisions)) {
if (decision) {
latestDecisions[gate as GateChannel] = decision;
}
}
const nextRequiredAction = computeNextRequiredAction(latestDecisions, durableReplicaStatus);
return {
ok: true,
status: {
candidateId: candidate.candidateId,
candidateIdentityHash: identityResult.digest,
latestDecisions,
coverage,
dossierRootHash: rootRef.rootHash,
eventCount: rootRef.eventCount,
durableReplicaStatus,
activeIncidents,
nextRequiredAction,
actionPackLocators,
},
};
}
function computeNextRequiredAction(
decisions: Partial>,
durableReplicaStatus: "verified" | "not-verified" | "mismatch",
): string | null {
for (const [gate, decision] of Object.entries(decisions)) {
if (decision && decision.status !== "pass") {
return `Fix requirements for gate "${gate}" — current status: ${decision.status}`;
}
}
if (durableReplicaStatus === "mismatch") {
return "Durable replica root hash mismatch — sync required";
}
if (durableReplicaStatus === "not-verified") {
return "Durable replica not verified — sync required for Alt/Main gates";
}
return null;
}
export interface CertificationVerifyResultV1 {
ok: true;
verified: boolean;
recomputedCandidateId: string;
recomputedDossierRoot: Sha256Digest;
eventCount: number;
decisionReferences: string[];
issues: string[];
}
export interface CertificationVerifyFailureV1 {
ok: false;
ruleId: "CERT-ORCHESTRATOR-09" | "CERT-ORCHESTRATOR-10";
message: string;
issues: string[];
}
export type CertificationVerifyOutcomeV1 =
CertificationVerifyResultV1 | CertificationVerifyFailureV1;
export function verifyCertification(
candidate: ReleaseCandidateV1,
repository: DossierRepositoryV1,
decisions: Partial>,
expectedDossierRoot?: Sha256Digest,
): CertificationVerifyOutcomeV1 {
const issues: string[] = [];
const identityResult = buildReleaseCandidateIdentityV1(candidate);
if (!identityResult.ok) {
return {
ok: false,
ruleId: "CERT-ORCHESTRATOR-09",
message: `failed to compute candidate identity: ${identityResult.diagnostic.message}`,
issues,
};
}
const integrityResult = verifyDossierIntegrity(repository);
if (!integrityResult.ok) {
issues.push(`dossier integrity: ${integrityResult.message}`);
return {
ok: false,
ruleId: "CERT-ORCHESTRATOR-10",
message: `dossier integrity verification failed: ${integrityResult.message}`,
issues,
};
}
if (!integrityResult.valid) {
issues.push("dossier root hash does not match recomputed root");
}
if (expectedDossierRoot && expectedDossierRoot !== integrityResult.recomputedRootHash) {
issues.push(
`expected dossier root ${expectedDossierRoot} does not match recomputed ${integrityResult.recomputedRootHash}`,
);
}
const decisionReferences: string[] = [];
for (const [gate, decision] of Object.entries(decisions)) {
if (decision) {
decisionReferences.push(`${gate}:${decision.decisionId}`);
}
}
const verified = issues.length === 0;
return {
ok: true,
verified,
recomputedCandidateId: candidate.candidateId,
recomputedDossierRoot: integrityResult.recomputedRootHash,
eventCount: repository.events.length,
decisionReferences,
issues,
};
}