# `AgentBlueprintProtocol.Schema`
[🔗](https://github.com/baselabs/agent_blueprint_protocol/blob/v0.1.1/lib/agent_blueprint_protocol/schema.ex#L1)

Bounded JSON Schema 2020-12 dialect + instance validator.

A closed 16-keyword subset — `type properties required items enum const
minimum maximum minLength maxLength minItems maxItems additionalProperties
oneOf $defs` plus document-local `$ref` — parsed from `Json`'s tagged
algebra and evaluated as pure, zero-dep instance validation. Serves port
payloads, `output_schema` assertions, and binding checks; evaluation and
execution TRUTH stays host-owned. Semantics follow the 2020-12 core and
validation specifications: assertions auto-pass instance types they do
not target (core §7.6.1), missing keywords never fail (core §7.3), `oneOf`
is exactly-one (core §10.2.1.3), boolean schemas are the substrate (core
§4.3.2), numbers compare by mathematical value across the integer/float
tags (core §4.2.2 — the tags do not survive the wire, so a non-Elixir
verifier cannot and must not distinguish them), and string lengths count
RFC 8259 characters (codepoints — not graphemes, not UTF-16 units).

Everything outside the frozen subset denies `:schema_keyword_not_allowed`
(fail-closed closed world: a regex-bearing or network-fetching schema is
a DoS/SSRF surface in a portable artifact). Keyword recognition is
POSITIONAL — only members of schema-position objects are keywords;
`enum`/`const` values and `properties`/`$defs` member names are instance
data.

Resource posture: schema complexity is metered as
`nodes + keywords + Σ(oneOf branches) + depth × 4` against the profile
ceiling 512 (`:schema_complexity_exceeded`); evaluation memoizes
(schema-node, instance-location) results — sound because assertion
results are context-free in this annotation-free dialect — which bounds
evaluation work to distinct pairs and closes the acyclic-`$ref`-DAG
blowup; references resolve only to document-local JSON Pointers landing
on schema positions, and any application-reachable reference cycle denies
`:schema_ref_cycle` (core §9.4.1 — a dead `$defs` entry is never applied
and may self-reference). `validate_instance/3` bounds no instance
itself: termination and cost rely on the caller-side parse ceilings
upstream (`Json`), the same posture as the decoder.

Both `parse/2` and `validate_instance/3` are total and never raise on any
input: malformed tagged shapes deny (`:invalid_type` instance-side,
`:schema_keyword_value_invalid` schema-side), never crash. Errors are
value-free; no wire string becomes an atom before a closed-set check.
Schema validation is a structural fact — it never authorizes content.

# `instance_reason`

```elixir
@type instance_reason() :: :invalid_type | :invalid_constraint | :invalid_cardinality
```

# `schema_reason`

```elixir
@type schema_reason() ::
  :schema_dialect_unknown
  | :schema_keyword_not_allowed
  | :schema_keyword_value_invalid
  | :schema_complexity_exceeded
  | :schema_ref_unresolvable
  | :schema_ref_cycle
  | :schema_invalid_shape
```

# `t`

```elixir
@type t() :: %AgentBlueprintProtocol.Schema{
  complexity: non_neg_integer(),
  dialect: binary(),
  pointers: pointers(),
  root: AgentBlueprintProtocol.Json.value()
}
```

# `ceiling`

```elixir
@spec ceiling() :: pos_integer()
```

The profile complexity ceiling (declared profile maximum).

# `complexity`

```elixir
@spec complexity(AgentBlueprintProtocol.Json.value()) :: non_neg_integer()
```

Meter a schema document: `nodes + keywords + Σ(oneOf branch counts) +
depth × 4`. Pure metering over the positional walk — unknown keywords
count as keywords, their values as data; no validation is performed.

# `dialect`

```elixir
@spec dialect() :: binary()
```

The single accepted dialect identifier — the 2020-12 dialect meta-schema
URI (validation §5). 2020-12 is the only published dialect; the
v1/2026 URI 404s.

# `equal?`

```elixir
@spec equal?(AgentBlueprintProtocol.Json.value(), AgentBlueprintProtocol.Json.value()) ::
  boolean()
```

Structural equality of two tagged values per core §4.2.2: numbers compare
by mathematical value across the integer/float tags, strings
codepoint-for-codepoint, booleans and null by kind, arrays pairwise
order-sensitive, objects order-blind with equal member counts. Mismatched
kinds are unequal, never an error. Public so the artifact layers consume
the one equality law rather than restating it.

# `parse`

```elixir
@spec parse(AgentBlueprintProtocol.Json.value(), binary()) ::
  {:ok, t()} | {:error, schema_reason()}
```

Parse a schema document (the tagged algebra value) under `dialect`.
Validates the closed keyword subset, keyword-value syntax, document-local
`$ref` resolution, application-edge acyclicity, and the complexity
ceiling. Accepts only the exact 2020-12 dialect URI.

# `validate_instance`

```elixir
@spec validate_instance(
  t() | AgentBlueprintProtocol.Json.value(),
  AgentBlueprintProtocol.Json.value(),
  binary()
) :: :ok | {:error, instance_reason() | schema_reason()}
```

Validate `instance` (a tagged algebra value) against `schema` under
`dialect`. `schema` is the raw tagged document or a `parse/2` struct
(structs are re-parsed, not trusted — the `Bounds.coerce` precedent).
Total and never-raising on any input: malformed tagged values deny
`:invalid_type`, malformed schemas deny a `:schema_*` reason.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
