/* RFC-1259: Content-authority model (CAM) schema — the optional `authority:` block on system.md that unifies clientEditable[], pseo autonomy scopes, and approval gates as projections of one authorization model. Do not evaluate authority verdicts — resolution lives in werkstatt-site/src/domain/authority/resolve.ts. Do not declare validator rules — CAM-01..05 are emitted by authority.model.validate, not this schema. RFC-1259: step 1 — camAuthoritySchema: closed fieldClass vocabulary, subjects, grants (incl. allowOverlap escape for documented narrowing), gates. version: 1 literal — unknown versions fail closed (CAM-01). */ import { z } from "zod"; /** * RFC-1259: closed field-class vocabulary (v1). A superset of the pseo * fieldClassSchema (structural, narrative, claims, product) — every pseo * scope is representable as a CAM grant on this axis. */ export const camFieldClassSchema = z.enum([ "structural", "narrative", "claims", "product", "legal", "media", "navigation", "shell", ]); /** RFC-1259: mutation-scope level scale (adapted from RFC-0278's L0–L4 vocabulary). */ export const camLevelSchema = z.enum(["L0", "L1", "L2", "L3", "L4"]); export const camSubjectSchema = z .object({ id: z.string().min(1), description: z.string().optional(), /** Baseline level when no grant covers the query. */ defaultLevel: camLevelSchema, }) .strict(); export const camGateSchema = z .object({ id: z.string().min(1), whenFieldClass: z.union([camFieldClassSchema, z.array(camFieldClassSchema).min(1)]), require: z.enum(["human-approval", "mission-digest-signoff", "provenance"]), /** Optional level ceiling this gate imposes on matched operations. */ ceiling: camLevelSchema.optional(), }) .strict(); export const camGrantSchema = z .object({ subject: z.string().min(1), fieldClasses: z.array(camFieldClassSchema).min(1), /** Workspace-relative glob paths; absent = unrestricted within fieldClasses. */ paths: z.array(z.string().min(1)).optional(), /** Grant ceiling; falls back to subject.defaultLevel when absent. */ maxLevel: camLevelSchema.optional(), /** Gate id references resolved against the block's gates[]. */ gates: z.array(z.string().min(1)).optional(), /** * Q-2 escape hatch: documented shadowing. Without it, CAM-03 flags any * glob-intersecting grant pair for the same subject×fieldClass carrying * different maxLevel. */ allowOverlap: z.boolean().optional(), }) .strict(); export const camAuthoritySchema = z .object({ /** Unknown versions fail closed: the resolver refuses the block. */ version: z.literal(1), /** * Informational restatement of the closed vocabulary — optional; the enum * is the enforcement, the list documents which classes the site uses. */ fieldClasses: z.array(camFieldClassSchema).min(1).optional(), subjects: z.array(camSubjectSchema).min(1), grants: z.array(camGrantSchema).default([]), gates: z.array(camGateSchema).default([]), }) .strict(); export type CamFieldClass = z.infer; export type CamLevel = z.infer; export type CamSubject = z.infer; export type CamGate = z.infer; export type CamGrant = z.infer; export type CamAuthority = z.infer;