/* onboarding.intake.schema.export (RFC-1281): render the werkstatt:intake/v1 JSON Schema from the Zod source-of-truth model (renderIntakeSchemaExport) and write the vendored artifact packages/werkstatt-shared/src/onboarding/intake.schema.generated.yaml under an RFC-0336 advisory header naming this command as owner. Producers vendor the file byte-exact and record its sha256 in provenance.contractSnapshot — the value INTAKE-10 compares against. Do not hand-edit the artifact — the Zod model is the source of truth (spec D2). Do not emit JSON — the contract's persisted form is YAML (AMD-001 §1, RFC-0376). RFC-1328 review (F-1): inject statementByLocale/localeNeutral into every $def — the export validates envelope items, not bare canonical entities. RFC-1281: created — onboarding.intake.schema.export command. RFC-1281: intake contract and onboarding.intake.validate RFC-1301: export PBP entity JSON Schemas in werkstatt:intake/v1 (RFC-1301) */ import { join } from "node:path"; import { z } from "zod"; import { pbpSchemaById } from "@warpgogol/pbp/entities"; import { INTAKE_PBP_SCHEMA_ALLOWLIST, intakePbpEntitySchema, renderIntakeSchemaExport, type IntakePbpEntityJsonSchemas, } from "@warpgogol/werkstatt-shared/onboarding/intake"; import type { KernelCommandInput, KernelCommandResult, KernelRuntimeContext, } from "@warpgogol/werkstatt-shared/kernel"; import { buildGeneratedHeader } from "../kernel/generated-marker.ts"; /** Repo-relative path of the vendored schema export (INTAKE-10 input). */ export const INTAKE_SCHEMA_EXPORT_PATH = "packages/werkstatt-shared/src/onboarding/intake.schema.generated.yaml"; /** * RFC-1301: JSON Schema (draft 2020-12, input side) for every v1 allow-listed * PBP entity type, derived from the canonical Zod schemas (DNA-103) — never * hand-maintained. Zod refinements are not representable and are dropped, so * the export is a structural pre-check; INTAKE-03 (pbpSchemaById) stays * authoritative. */ export function renderIntakePbpEntityJsonSchemas(): IntakePbpEntityJsonSchemas { // AMD-005/RFC-1328: the $defs describe pbp[] items *as they appear in the // envelope* — producers validate the whole intake.json against this export. // The canonical strict fragment alone would reject the envelope-only fields // (additionalProperties: false), so each $def gains the envelope field // declarations, rendered from the same Zod source (DNA-103). const envelopeFields = z.toJSONSchema( intakePbpEntitySchema.pick({ statementByLocale: true, localeNeutral: true }), { target: "draft-2020-12", unrepresentable: "any", io: "input" }, ) as { properties?: Record }; const out: IntakePbpEntityJsonSchemas = {}; for (const id of INTAKE_PBP_SCHEMA_ALLOWLIST) { const canonical = pbpSchemaById[id]; if (canonical === undefined) { throw new Error(`onboarding.intake.schema.export: ${id} missing from pbpSchemaById`); } const { $schema: _drop, ...fragment } = z.toJSONSchema(canonical, { target: "draft-2020-12", unrepresentable: "any", io: "input", }) as Record; fragment.properties = { ...(fragment.properties as Record | undefined), ...envelopeFields.properties, }; out[id] = fragment; } return out; } export interface IntakeSchemaExportResult { command: "onboarding.intake.schema.export"; status: "pass"; path: string; bytes: number; dryRun: boolean; /** Rendered content map consumed by generated.drift.validate dryRun re-render. */ renderedFiles?: Record; } export async function runIntakeSchemaExport( input: KernelCommandInput, context: KernelRuntimeContext, ): Promise> { const content = buildGeneratedHeader({ filePath: INTAKE_SCHEMA_EXPORT_PATH, ownerCommand: "onboarding.intake.schema.export", }) + renderIntakeSchemaExport({ pbpEntitySchemas: renderIntakePbpEntityJsonSchemas() }); const dryRun = context.dryRun === true || input.flags["dry-run"] === true; if (!dryRun) { await context.io.writeFile(join(context.workspaceRoot, INTAKE_SCHEMA_EXPORT_PATH), content); } const bytes = new TextEncoder().encode(content).length; return { data: { command: "onboarding.intake.schema.export", status: "pass", path: INTAKE_SCHEMA_EXPORT_PATH, bytes, dryRun, renderedFiles: { [INTAKE_SCHEMA_EXPORT_PATH]: content }, }, exitCode: 0, summary: dryRun ? `[intake.schema.export] dry-run rendered ${bytes} bytes -> ${INTAKE_SCHEMA_EXPORT_PATH}` : `[intake.schema.export] wrote ${bytes} bytes -> ${INTAKE_SCHEMA_EXPORT_PATH}`, }; }