Internal compiler for the bounded capability JSON Schema profile.
The accepted profile is a strict subset of JSON Schema 2020-12 containing
type, title, description, default, properties, required,
additionalProperties, items, enum, const, minimum, maximum,
minLength, maxLength, minItems, maxItems, and the single bounded
sha256 string format. Types are scalar rather than unions, roots are
objects, and a missing additionalProperties on an object is normalized to
false.
$schema selects the schema dialect; absence means the MCP default
(2020-12). Because the accepted profile is a common subset of the
allowlisted dialects, a supported root $schema URI (2020-12, or draft-07
as a deliberate compatibility translation) is accepted and removed, while
unknown, malformed, and nested dialect markers are rejected. Vendor x-…
extension keys and the standard non-validating default annotation are
discarded from every level as a deliberate client policy — mainstream MCP
SDKs emit them by default. They do not reach normalized output, encodings,
hashes, or runtime argument construction. All other unknown keywords remain
rejected.
Each normalized schema is at most 64 KiB with maximum depth 16, 128 properties per object, and 256 enum members. Schemas are compiled once with JSV. Runtime validation delegates to the compiled JSV root. Input rejection may retain a small explanation containing only schema-declared paths, keywords, and bounds; submitted values and undeclared property names never enter that explanation. Validation and explanation projection run together in one time- and heap-bounded worker. Proven schema invalidity is distinct from validator timeout, heap exhaustion, crashes, and malformed validator results.
Rejection reports the first proven fault as a closed rule atom plus the
segments locating it inside the submitted schema document. Every segment is
a key or index the submitted document actually carries, so the location
always resolves in the file the author opens. The profile is deliberately
closed, and its edges are not guessable from a bare refusal: an unsupported
keyword, a misspelled type, and an unsatisfiable bound are three different
authoring mistakes and must not report identically.
Summary
Functions
Returns every rule a rejection can carry, most specific first.
Validates a value and returns only bounded, schema-authored rejection facts.
Types
@type compiled() :: JSV.Root.t()
@type segment() :: {:property, binary()} | {:index, non_neg_integer()}
Functions
@spec rules() :: [atom()]
Returns every rule a rejection can carry, most specific first.
The set is closed so a diagnostic boundary can render each rule from a fixed literal instead of forwarding compiler prose.
@spec validate(compiled(), map(), term(), pos_integer(), pos_integer()) :: :ok | {:invalid, [violation()]} | {:unavailable, atom()}
Validates a value and returns only bounded, schema-authored rejection facts.