/*
RFC-1299: capabilityGapSchema — the Zod mirror of
docs/specs/werkstatt-onboarding/schemas/capability-gap.schema.yaml. A
capability gap is a typed proof that the platform catalog cannot express a
client need (D4): raised by the composer or by family.detect (kind
new-family), carried as a decision-window entry, and validated by
capability.gap.validate (CAPGAP-01…03).
- Do not score or detect gaps here — detection lives in werkstatt-site (family.detect); this file is the data contract only.
- Do not add fields beyond the spec schema — strict objects mirror additionalProperties:false (DNA-19).
- Field-for-field mirror of capability-gap.schema.yaml — the spec file is normative; any divergence is a bug.
- systemId has no pattern in the spec schema, so none is enforced here (CAPGAP-02's token check supplies the semantic constraint).
- RFC-1299: created — capabilityGapSchema + CapabilityGap type.
- RFC-1299: capability.brief + family.detect + capability.gap.validate
*/
import { z } from "zod";
const capgapIdSchema = z.string().regex(/^CAPGAP-[0-9]{3,}$/);
const catalogEvidenceCandidateSchema = z
.object({
/** Catalog id (archetype, family, biome, …). */
ref: z.string(),
whyInsufficient: z.string(),
})
.strict();
const capabilityGapNeedSchema = z
.object({
statement: z.string(),
evidenceRefs: z.array(z.string()).min(1),
})
.strict();
const capabilityGapCatalogEvidenceSchema = z
.object({
capabilityBriefSha256: z.string().regex(/^sha256:[0-9a-f]{64}$/),
/** family.detect best score (for new-family). */
familyScore: z.number().min(0).max(1).optional(),
candidates: z.array(catalogEvidenceCandidateSchema).min(1),
})
.strict();
const capabilityGapProposalSchema = z
.object({
/**
* Generic name by function (never a client name), e.g. `partner-locator`
* rather than `dp7-partners`.
*/
functionalName: z.string().regex(/^[a-z][a-z0-9-]{2,48}$/),
/**
* `data` = built in this onboarding with provenance.client;
* `platform-rfc` = separate platform track (code).
*/
track: z.enum(["data", "platform-rfc"]),
sketch: z.string().optional(),
})
.strict();
export const capabilityGapSchema = z
.object({
id: capgapIdSchema,
systemId: z.string(),
kind: z.enum([
"new-section-archetype",
"section-props-extension",
"new-family",
"new-biome",
"new-constellation",
"new-pbp-entity-type",
"new-component",
]),
need: capabilityGapNeedSchema,
catalogEvidence: capabilityGapCatalogEvidenceSchema,
proposal: capabilityGapProposalSchema,
/**
* What the site uses until the extension exists (an existing archetype
* or an omission). Code extensions never block birth.
*/
interim: z.string(),
})
.strict();
export type CapabilityGap = z.infer;