Files
suaveplan/openspec/archive/2026-04-19-enterprise-validation/proposal.md
2026-05-27 23:29:53 +01:00

5.7 KiB

OpenSpec Change: enterprise-validation

  • Change ID: enterprise-validation
  • Package: @suaveplan/validation
  • Category: universal
  • Target path: packages/universal/validation
  • Status: IN PROGRESS
  • Date: 2026-04-18
  • Reference spec: /mnt/s/web/suaveplan/enterprise/validation.md

Summary

Greenfield implementation of @suaveplan/validation for the genesis branch. The existing main-branch validation package provides the baseline public-API surface to preserve; this change delivers a runtime schema-validation library with a Zod-compatible API surface, exhaustive schema types (string, number, boolean, date, array, object, union, intersection, literal, enum, nullable, optional, record, tuple, coerce), async refinements, hooks, structured errors, property-based tests, and benchmarks. The library is entirely self-contained — it does NOT depend on Zod; it is its own parser, used alongside Zod at the monorepo level for other packages.

Current-state audit (genesis)

The package does not exist on genesis yet — this is a fresh build.

Available workspace deps on genesis

Package Available
@suaveplan/error ✅
@suaveplan/types ✅
@suaveplan/events ✅
@suaveplan/opentelemetry ❌ not yet built — use @opentelemetry/api directly
@suaveplan/feature-flags ❌ not yet built — skip
@suaveplan/schema-registry ❌ not yet built — skip

External deps (via catalog):

  • @opentelemetry/api → catalog:observability
  • tslib → catalog:build

Dev deps (via catalog):

  • vitest, @vitest/coverage-istanbul → catalog:testing
  • fast-check → catalog:testing
  • mitata → catalog:testing

Preserved public API surface (from main branch)

Core

  • BaseSchema<TInput, TOutput> — abstract base class with .parse(input), .safeParse(input), .parseAsync(input), .safeParseAsync(input), .refine(fn, msg?), .transform(fn), .optional(), .nullable(), .describe(description)

Types

  • AnySchema, SchemaInput<S>, SchemaOutput<S> — utility type extractors
  • Infer<S>, InferInput<S> — schema type inference helpers
  • ParseResult<T> — ParseSuccess<T> | ParseFailure
  • ParseSuccess<T> — { success: true; data: T }
  • ParseFailure — { success: false; error: ValidationError }
  • ParseContext — internal traversal context
  • ValidationIssue — { code: ValidationCode; path: (string | number)[]; message: string; input?: unknown }
  • ValidationCode — string union of all built-in issue codes
  • FlattenedErrors — { formErrors: string[]; fieldErrors: Record<string, string[]> }
  • RefineFn<T>, AsyncRefineFn<T>, TransformFn<T, U>, CustomRule<T>
  • StringRuleOptions, NumberRuleOptions, ObjectShape

Errors

  • ValidationError extends SuaveplanError — .flatten(), .issues getter, .format()
  • ValidationErrorOptions — constructor options
  • FlattenedErrors — return type of .flatten()

Schema factories

  • string() → StringSchema — .min(n), .max(n), .length(n), .regex(r), .email(), .url(), .uuid(), .startsWith(s), .endsWith(s), .includes(s), .trim(), .toLowerCase(), .toUpperCase()
  • number() → NumberSchema — .min(n), .max(n), .int(), .positive(), .negative(), .multipleOf(n), .finite()
  • boolean() → BooleanSchema
  • date() → DateSchema — .min(d), .max(d)
  • array(schema) → ArraySchema — .min(n), .max(n), .length(n), .nonempty()
  • object(shape) → ObjectSchema — .strict(), .passthrough(), .strip(), .pick(keys), .omit(keys), .partial(), .required(), .extend(shape), .merge(other)
  • union(schemas) → UnionSchema
  • intersection(a, b) → IntersectionSchema
  • literal(value) → LiteralSchema
  • enumeration(values) → EnumSchema
  • nullable(schema) → NullableSchema
  • optional(schema) → OptionalSchema
  • record(schema) → RecordSchema
  • tuple(schemas) → TupleSchema

Coerce utilities

  • coerce(schema) → CoercedSchema — wraps any schema with string→type coercion
  • coerceString(input) → string
  • coerceNumber(input) → number
  • coerceBoolean(input) → boolean
  • coerceDate(input) → Date
  • CoercedSchema<T> (type)

Compose utilities

  • mergeResults(results) — merges multiple ParseResult arrays into one
  • pipe(schema, ...transforms) — sequential schema pipeline

Hook types

  • ValidationHookMap — lifecycle hooks: beforeValidate, afterValidate, onError
  • ValidationHookData<T> — data passed to each hook
  • ValidationValidatingHandler — handler signature

New additions for genesis

Structured errors

  • ValidationError extends SuaveplanError with codes under VALIDATION.* namespace
  • Codes: VALIDATION.STRING.*, VALIDATION.NUMBER.*, VALIDATION.ARRAY.*, VALIDATION.OBJECT.*, VALIDATION.UNION.NO_MATCH, VALIDATION.CUSTOM.REFINEMENT

OTel instrumentation

  • Counters: validation.parse.success, validation.parse.failure
  • Histogram: validation.parse.duration_ms (per schema type label)

Property-based tests (fast-check)

  • Round-trip: schema.parse(schema.parse(x)) === schema.parse(x) (idempotency)
  • Error propagation: any invalid input to .parse() always returns ParseFailure (never throws)
  • Union exhaustiveness: input matching none of the union arms always fails

Benchmarks (mitata)

  • object(shape).parse(data) for 10-field object — 100k iterations
  • array(string()).parse(arr) for 1 000-element array
  • union with 10 arms — best-case and worst-case branch

Impact

  • Adds one new package: packages/universal/validation
  • Adds one new spec capability: validation
  • No existing package consumers on genesis yet