/*
RFC-0221: Zod schemas for the internal site handoff bundle — the version-stamped
lock that makes ingest version-aware, and the authored/derived manifest partition.
- Do not perform file IO, hashing, or version comparison — pure shape only.
- Do not define migrator logic — that lives in @warpgogol/site-kernel-handoff.
- RFC-0221: initial schemas for the site handoff bundle.
- RFC-0479: migratorCursor changed from SemVer string to string[] (migrator-id list).
*/
import { z } from "zod";
const semverRe = /^\d+\.\d+\.\d+$/;
const sha256Re = /^sha256:[0-9a-f]{64}$/;
/** A single consumed capability, snapshotted from uni.registry.yaml at pack time. */
export const handoffCapabilitySchema = z.object({
/** Unique uni.registry entry id (e.g. "breadcrumbs-component") — the diff key. */
id: z.string().min(1),
/** Role/semanticId — NOT unique across layers; used for intent grouping and display. */
semanticId: z.string().min(1),
/** Capability version consumed (uni.registry entry version). */
version: z.string().min(1),
/** Carried so red-tier removals can be remapped by intent rather than by name. */
intent: z.array(z.string()).default([]),
});
/** Ecosystem stamp: which studio monorepo state the bundle was packed against. */
export const handoffEcosystemSchema = z.object({
/** Root package.json version at pack time, e.g. "4.5.0". */
version: z.string().regex(semverRe, "ecosystem.version must be x.y.z"),
/** git SHA of the studio monorepo at pack time. */
commit: z.string().min(7),
/** Highest `implemented` RFC id at pack time, e.g. "RFC-0220". */
rfcHead: z.string().regex(/^RFC-\d{4}$/),
/** Semantic fingerprint of the packages/ tree at pack time (RFC-0364). */
platformSemanticHash: z.string().regex(sha256Re),
/** Legacy byte hash of packages/ — read-only during migration, removed in RFC-0364 step 7. */
packagesHash: z.string().regex(sha256Re).optional(),
});
/** Passport-derived build provenance carried with the bundle. */
export const handoffBuildSchema = z.object({
/** sha256 of system.yaml at last build. */
systemHash: z.string().regex(sha256Re),
commitSha: z.string().min(7),
});
/** handoff-lock.json — the artifact that makes ingest version-aware (RFC-0221 §2). */
export const handoffLockSchema = z.object({
/** Lock format version, independent of the ecosystem version. */
schemaVersion: z.string().regex(semverRe),
app: z.string().min(1),
packedAt: z.string().datetime(),
ecosystem: handoffEcosystemSchema,
/** Ecosystem version this site is "synced to" — equals ecosystem.version at pack. */
migratorCursor: z.array(z.string()),
/** The CONSUMED subset of uni.registry.yaml (not the whole registry). */
capabilities: z.array(handoffCapabilitySchema).default([]),
build: handoffBuildSchema,
});
/** One path entry in the bundle manifest: is it source of truth, or regenerated? */
export const handoffManifestEntrySchema = z.object({
/** Bundle-relative POSIX path. */
path: z.string().min(1),
/** authored = round-trips, source of truth. derived = disposable, regenerated. */
kind: z.enum(["authored", "derived"]),
/** sha256 of the file contents at pack time (integrity + derived-edit detection). */
hash: z.string().regex(sha256Re),
});
/** handoff-manifest.json — authored/derived partition + integrity (RFC-0221 §5). */
export const handoffManifestSchema = z.object({
schemaVersion: z.string().regex(semverRe),
app: z.string().min(1),
entries: z.array(handoffManifestEntrySchema).default([]),
});
export type HandoffCapability = z.infer;
export type HandoffEcosystem = z.infer;
export type HandoffBuild = z.infer;
export type HandoffLock = z.infer;
export type HandoffManifestEntry = z.infer;
export type HandoffManifest = z.infer;