/*
decisions contract — Zod schemas for certification coverage reports and gate decisions.
- Do not make gate decisions — this module defines the contract 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.
- RFC-1207: candidate-preview certify — wrangler dev on releases//dist/server measures the candidate artifact
*/
import { z } from "zod";
import {
digestSchema,
decisionIdSchema,
humanReadableIdSchema,
utcTimestampSchema,
authoritySequenceSchema,
certificationStatusSchema,
} from "./identifiers.ts";
export const coverageReportV1Schema = z
.object({
schema: z.literal("werkstatt/coverage-report@1"),
totalRequirements: z.number().int().nonnegative().max(1000),
coveredRequirements: z.number().int().nonnegative().max(1000),
uncoveredRequirements: z.array(humanReadableIdSchema).max(1000),
})
.strict();
export type CoverageReportV1 = z.infer;
export const selectedEvidenceV1Schema = z
.object({
evidenceId: humanReadableIdSchema,
evidenceHash: digestSchema,
selectedAt: utcTimestampSchema,
})
.strict();
export type SelectedEvidenceV1 = z.infer;
export const gateDecisionV1Schema = z
.object({
schema: z.literal("werkstatt/gate-decision@1"),
decisionId: decisionIdSchema,
candidateId: humanReadableIdSchema,
policyBundleRoot: digestSchema,
gate: z.enum(["dev", "alt", "main"]),
evaluationCut: authoritySequenceSchema,
selectedEvidence: z.array(selectedEvidenceV1Schema).max(10000),
status: certificationStatusSchema,
coverage: coverageReportV1Schema,
reasons: z.array(z.string().min(1).max(4096)).max(100),
actionPackRef: digestSchema.nullable(),
decidedAt: utcTimestampSchema,
// RFC-1207: candidate measurement provenance — optional so pre-RFC-1207
// persisted decisions still validate (strict() permits declared optionals).
measurementTarget: z.enum(["candidate-preview", "channel", "explicit"]).optional(),
measuredReleaseId: humanReadableIdSchema.optional(),
})
.strict();
export type GateDecisionV1 = z.infer;
export const mainVerificationDecisionV1Schema = z
.object({
schema: z.literal("werkstatt/main-verification-decision@1"),
decisionId: decisionIdSchema,
candidateId: humanReadableIdSchema,
policyBundleRoot: digestSchema,
gate: z.literal("main"),
evaluationCut: authoritySequenceSchema,
selectedEvidence: z.array(selectedEvidenceV1Schema).max(10000),
status: certificationStatusSchema,
coverage: coverageReportV1Schema,
reasons: z.array(z.string().min(1).max(4096)).max(100),
actionPackRef: digestSchema.nullable(),
rootDossierRef: digestSchema,
priorOperationRef: digestSchema.nullable(),
decidedAt: utcTimestampSchema,
})
.strict();
export type MainVerificationDecisionV1 = z.infer;
export const certificationHealthDecisionV1Schema = z
.object({
schema: z.literal("werkstatt/certification-health-decision@1"),
candidateId: humanReadableIdSchema,
currentStatus: certificationStatusSchema,
lastDecisionId: decisionIdSchema.nullable(),
lastDecisionAt: utcTimestampSchema.nullable(),
staleEvidenceCount: z.number().int().nonnegative().max(10000),
incompleteCount: z.number().int().nonnegative().max(1000),
assessedAt: utcTimestampSchema,
})
.strict();
export type CertificationHealthDecisionV1 = z.infer;