/*
RFC-0358/RFC-0379/RFC-0666: Zod schemas for deployment config, channel model, and propagation results. secretsFile field kept as z.string().optional() for detection (sternsystem.validate rejects any value); secretRefSchema removed as dead code.
- Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.
- RFC-0926: add optional workerVersionId to propagationResultSchema and lastPropagatedChannelSchema for release-aware rollback.
- RFC-1091: add github-pages to deploymentAdapterNameSchema enum.
- RFC-1097: step 6 — compass.migrate codemod run
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.
- 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-1297: lastPropagatedChannelSchema gains states rolled-back + reconciled; healthy becomes nullable (unknown until re-verified).
RFC-0358, RFC-0379, RFC-0595, RFC-0624, RFC-0627, RFC-0666, RFC-0790
*/
import { z } from "zod";
export const deploymentAdapterNameSchema = z.enum([
"cloudflare-workers",
"github-pages",
"netlify",
"null",
]);
export const deploymentChannelSchema = z.object({
workerName: z.string(),
url: z.string().url(),
// RFC-0666: secretsFile kept as z.string().optional() for detection — sternsystem.validate rejects any value.
// secretRefSchema removed (dead code — env vars were never set).
secretsFile: z.string().optional(),
});
export const purgeResultSchema = z.object({
success: z.boolean(),
purgedUrls: z.number(),
error: z.string().optional(),
});
export const lastPropagatedChannelSchema = z.object({
releaseId: z.string(),
at: z.string().datetime(),
// RFC-1297: nullable — rollback/reconcile record the release but not its
// health; health is re-established by the next leitstand.verify run.
healthy: z.boolean().nullable(),
state: z.enum([
"succeeded",
"failed",
"failed-stale",
"in-progress",
"rolled-back",
"reconciled",
]),
operationId: z.string(),
leaseExpiresAt: z.string().datetime().nullable(),
purgeResult: purgeResultSchema.optional(),
workerVersionId: z.string().optional(),
});
export const healthCheckSchema = z.object({
name: z.string(),
url: z.string(),
status: z.number().int(),
passed: z.boolean(),
detail: z.string(),
expectedHash: z.string().optional(),
actualHash: z.string().optional(),
});
export const propagationResultSchema = z.object({
systemId: z.string(),
releaseId: z.string(),
state: z.enum(["succeeded", "failed", "failed-stale", "in-progress"]),
deploymentUrl: z.string(),
workerVersionId: z.string().optional(),
startedAt: z.string().datetime(),
completedAt: z.string().datetime().nullable(),
healthChecks: z.array(healthCheckSchema),
});
export const routeFactSchema = z.object({
path: z.string(),
contentHash: z.string().nullable(),
redirectTarget: z.string().optional(),
});
export type DeploymentAdapterName = z.infer;
export type DeploymentChannel = z.infer;
export type LastPropagatedChannel = z.infer;
export type PurgeResult = z.infer;
export const deploymentStaticConfigSchema = z.object({
adapter: deploymentAdapterNameSchema,
channels: z.object({
dev: deploymentChannelSchema,
alt: deploymentChannelSchema,
main: deploymentChannelSchema,
}),
});
export type DeploymentStaticConfig = z.infer;
export type HealthCheck = z.infer;
export type PropagationResult = z.infer;
export type RouteFact = z.infer;