--- name: corvus-keywords-and-validation description: > Implement and extend JSON Schema keywords in the Corvus code generation system and the runtime evaluator. Covers the IKeyword interface, behavioral marker interfaces, vocabulary registration, draft-specific keyword variations (Draft 4 through 2020-12), where assertions are implemented (SchemaCompiler/Evaluator), custom keyword extension points, and the TypeDeclaration data structure. USE FOR: adding new JSON Schema keywords, modifying validation behavior, understanding keyword evolution across drafts, extending the code generation engine, understanding vocabularies. DO NOT USE FOR: using generated types (use corvus-codegen), standalone evaluator internals (use corvus-standalone-evaluator). --- # Keywords and Validation Handlers ## Keyword Architecture Keywords are **stateless singletons** implementing `IKeyword` plus behavioral marker interfaces. ### IKeyword Interface Every keyword implements: - `Keyword` property — the JSON property name (e.g., `"type"`, `"maxLength"`) - Behavioral marker interfaces that declare how the keyword participates in schema processing ### Behavioural Marker Interface Categories (25+) 1. **Schema structure** — type shape: `ISubschemaTypeBuilderKeyword`, `ILocalSubschemaRegistrationKeyword`, `IPropertySubchemaProviderKeyword` 2. **Validation** — runtime checks: `IObjectPropertyValidationKeyword`, `IValueKindValidationKeyword`, `INumericValidationKeyword`, `IStringValidationKeyword`, `IArrayValidationKeyword` 3. **Annotation & documentation** — `IAnnotationProducingKeyword`, `IShortDocumentationProviderKeyword`, `ILongDocumentationProviderKeyword`, `IDefaultValueProviderKeyword`, `IExamplesProviderKeyword`, `INonStructuralKeyword`, `IDeprecatedKeyword` 4. **References & identity** — `IRefKeyword`, `IDynamicRefKeyword`, `IIdKeyword`, `IAnchorKeyword`, `ISchemaKeyword` ## Vocabularies Vocabularies are modular sets of keywords (introduced formally in Draft 2019-09): - **Core** — `$id`, `$schema`, `$ref`, `$defs` - **Applicator** — `allOf`, `anyOf`, `oneOf`, `if/then/else`, `properties`, `items` - **Validation** — `type`, `minimum`, `maximum`, `pattern`, `required` - **MetaData** — `title`, `description`, `default`, `examples` - **Format** — `format` keyword (annotation in 2019-09+, assertion in earlier drafts) - **Content** — `contentEncoding`, `contentMediaType`, `contentSchema` - **Unevaluated** — `unevaluatedProperties`, `unevaluatedItems` (2019-09+) ## Validation Handler Priorities Handlers execute in strict priority order (defined in `ValidationPriorities` static class in `src-v4/Corvus.Json.CodeGeneration/.../Validation/ValidationPriorities.cs`, shared by both V4 and V5): | Priority | Name | Value | Purpose | |----------|------|-------|---------| | First | `First` | 0 | Must run before everything | | CoreType | `CoreType` | 1,000 | Basic type checking (`type` keyword) | | Default | `Default` | ~2.1 billion (`uint.MaxValue / 2`) | Standard validation (min/max, pattern, etc.) | | Composition | `Composition` | Default + 1,000 | `allOf`, `anyOf`, `oneOf`, `not` | | AfterComposition | `AfterComposition` | Composition + 1,000 | Keywords that depend on composition results (arrays, objects) | | Last | `Last` | `uint.MaxValue` | Final cleanup, unevaluated properties/items | The large gap between CoreType (1,000) and Default (~2.1B) leaves room for future priorities without redefining existing values. ## Draft-Specific Keyword Variations Keywords change behavior across JSON Schema drafts: | Keyword | Draft 4 | Draft 6+ | |---------|---------|----------| | `exclusiveMaximum` | Boolean modifier on `maximum` | Standalone number | | `exclusiveMinimum` | Boolean modifier on `minimum` | Standalone number | | `items` | Single schema or array | Single schema only in 2020-12 (`prefixItems` for array) | | `additionalItems` | Used with array `items` | Removed in 2020-12 | | `$ref` | Replaces all siblings | Coexists with siblings in 2019-09+ | ## Custom Keyword Extension Points (8) The code generation engine exposes extension points at different phases: 1. **Schema discovery** — register custom schema locations 2. **Type declaration building** — modify type declarations during construction 3. **Type reduction** — control how trivial subschemas are collapsed 4. **Validation handler registration** — add custom validation code emitters 5. **Property handler** — customize how object properties are processed 6. **Array handler** — customize array item processing 7. **Format handler** — add custom format validators 8. **Composition handler** — customize allOf/anyOf/oneOf/not processing ## Where Validation Lives Validation handlers no longer exist. Keywords are declared for the type builder (so generated *types* reflect them), but every assertion is implemented once in the runtime evaluator (`src/Corvus.Text.Json/Corvus/Text/Json/RuntimeEvaluator`, namespace `Corvus.Text.Json.RuntimeEvaluator`, in the `Corvus.Text.Json` assembly), which generated types, standalone evaluators, the Validator and the CLI all use: - `Compilation/SchemaCompiler.cs` — `CompileNode` reads each keyword into a `SchemaNode` (dispatch by keyword name length, then bytes), then whole-graph passes (dynamic refs, tracking, marking, `$ref` elision, discriminators, plans, flags). - `Evaluation/Evaluator.cs` — the assertions, generic over `FastMode`/`CollectingMode` and the document access type; report results with the keyword name through the collector. - Tests: `tests/Corvus.Text.Json.RuntimeEvaluator.Tests` (unit + JSON Schema Test Suite), plus the generated suite projects, which now run the same engine through generated types. The generator emits one `CorvusJsonSchemaProgram` per compilation (`RuntimeProgramGenerator.cs`) with an entry point per type: pre-compiled as an image when the host supplies `Options.ProgramCompiler` (the CLI), else holding the schema documents for compilation on first use; see `docs/StandaloneEvaluatorInternals.md`. ## TypeDeclaration The central data structure representing a resolved JSON Schema as a C# type: - Holds the schema keywords, their values, and resolved references - Tracks the type's place in the inheritance/composition hierarchy - Type reduction collapses trivial subschemas for leaner generated code ## Common Pitfalls - **Draft awareness**: Always check which draft(s) your keyword applies to. A keyword may have different semantics or not exist in certain drafts. - **Stateless keywords**: Keywords must be stateless singletons. State lives in `TypeDeclaration`. ## Cross-References - For code generation, see `corvus-codegen` - For the evaluation program and evaluator-only generation, see `corvus-standalone-evaluator` - Full guide: `docs/AddingKeywords.md`, `docs/ValidationHandlerGuide.md`, `docs/RuntimeEvaluator.md`