> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qwedai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Schema verifier

> The QWED Schema Verifier combines Pydantic validation with embedded math constraints to enforce structural and numerical correctness in LLM output payloads.

<Info>
  **Updated in v7.0.0 (breaking).** `SchemaVerifier.verify()` and `verify_ucp_transaction()` now return a [`DiagnosticResult`](/advanced/diagnostics) instead of an ad-hoc dict. A payload that violates its schema is `VERIFIED` (the check completed and proved the violation) with `developer_fields.is_valid: false` — `BLOCKED` is reserved for schemas the verifier cannot parse or validate. See the [changelog](/changelog#v7-0-0-—-full-diagnosticresult-engine-conformance) for migration details.
</Info>

The **Schema Verifier** goes beyond standard JSON validation. It combines **Pydantic** structure enforcement with **Symbolic Math** checks deeply embedded within the schema.

## How it works

It validates that:

1. **Structure:** The output matches the required JSON keys and types.
2. **Logic:** The numeric values *inside* the JSON are mathematically consistent (e.g., `total == sum(items)`).

## The `DiagnosticResult` contract

`verify()` returns a `DiagnosticResult` with a status, an agent-safe `agent_message`, structured `developer_fields`, and a deterministic `proof_ref`:

| Outcome                        | `status`                | `developer_fields`                                                               | `proof_ref` |
| ------------------------------ | ----------------------- | -------------------------------------------------------------------------------- | ----------- |
| Payload conforms to the schema | `VERIFIED`              | `is_valid: true`, `constraint_id: "schema_verifier.schema_valid"`                | Present     |
| Payload violates the schema    | `VERIFIED` (as-invalid) | `is_valid: false`, `constraint_id: "schema_verifier.schema_violation"`, `issues` | Present     |
| Schema cannot be parsed        | `BLOCKED`               | `constraint_id: "schema_verifier.parse_error"`                                   | `null`      |
| Unexpected validation error    | `BLOCKED`               | `constraint_id: "schema_verifier.validation_error"`                              | `null`      |

A schema violation is a completed, proven verdict, so it is `VERIFIED` — read `developer_fields.is_valid` for the pass/fail outcome and `developer_fields.issues` for per-path detail. `proof_ref` is computed deterministically from a canonical JSON encoding of the schema plus the instance evidence. Unsupported values (non-finite floats such as `NaN` or `±inf`, hostile objects) and cyclic structures fail closed to `BLOCKED` instead of emitting a proof.

Malformed schemas also fail closed: non-dict `properties`, invalid `required` entries, invalid numeric constraints, non-finite bounds, and negative size constraints return `BLOCKED` (`schema_verifier.parse_error`) instead of being silently treated as empty.

`agent_message` is sanitized — rule IDs, issue types, and schema internals never leak into agent-facing output.

## Usage

```python theme={null}
schema = {
    "type": "object",
    "properties": {
        "items": {"type": "array", "items": {"type": "number"}},
        "total": {"type": "number"}
    },
    # QWED Extension: Math Logic
    "qwed:constraints": [
        "total == sum(items)"
    ]
}

response = client.verify_schema(
    obj={"items": [10, 20], "total": 30},
    schema=schema
)
# -> status: "VERIFIED", developer_fields.is_valid: true

response = client.verify_schema(
    obj={"items": [10, 20], "total": 300}, # LLM hallucinations
    schema=schema
)
# -> status: "VERIFIED", developer_fields.is_valid: false
# -> issue: total (300) != sum(items) (30)
```

Money arithmetic uses `Decimal`, not float tolerance — computed-total and tax checks quantize operands to the currency precision and compare exactly, so boundary transactions deterministically pass or fail.

## Object validation

The Schema Verifier supports standard JSON Schema object keywords including `properties`, `required`, and `additionalProperties`.

### `additionalProperties: false` — strict fail-closed validation

When a schema sets `"additionalProperties": false` and the verifier runs with `strict=True` (the default), any property that is not declared in `properties` causes the payload to fail validation. The verifier records each undeclared property as an `ERROR`-severity `additional_property` issue, so `developer_fields.is_valid` is `false`.

In non-strict mode (`strict=False`), `additionalProperties: false` is treated as advisory and undeclared properties do not block validation.

**Issue types returned for `additionalProperties`:**

| Issue type            | Severity         | Meaning                                                                  |
| --------------------- | ---------------- | ------------------------------------------------------------------------ |
| `additional_property` | `ERROR` (strict) | An undeclared property was present and `additionalProperties` is `false` |

**Example — strict mode rejects extra fields:**

```python theme={null}
schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"}
    },
    "required": ["name"],
    "additionalProperties": False
}

result = client.verify_schema(
    obj={"name": "rahul", "role": "admin"},
    schema=schema,
    strict=True
)
# -> status: "VERIFIED", developer_fields.is_valid: false
# -> issue type: "additional_property", severity: "ERROR"
# -> message: "Additional property 'role' not allowed"
```

**Example — declared-only payloads pass:**

```python theme={null}
result = client.verify_schema(
    obj={"name": "rahul"},
    schema=schema,
    strict=True
)
# -> status: "VERIFIED", developer_fields.is_valid: true
```

**Example — nested objects also fail closed:**

```python theme={null}
schema = {
    "type": "object",
    "properties": {
        "user": {
            "type": "object",
            "properties": {"name": {"type": "string"}},
            "required": ["name"],
            "additionalProperties": False
        }
    },
    "required": ["user"]
}

result = client.verify_schema(
    obj={"user": {"name": "rahul", "role": "admin"}},
    schema=schema,
    strict=True
)
# -> status: "VERIFIED", developer_fields.is_valid: false
# -> issue path: "$.user.role", type: "additional_property", severity: "ERROR"
```

**Behavior matrix:**

| Mode           | `additionalProperties` | Extra field present | Result                                    |
| -------------- | ---------------------- | ------------------- | ----------------------------------------- |
| `strict=True`  | `false`                | yes                 | `is_valid: false`, issue severity `ERROR` |
| `strict=True`  | `false`                | no                  | `is_valid: true`                          |
| `strict=False` | `false`                | yes                 | `is_valid: true` (permissive)             |

<Info>
  This fail-closed behavior for strict `additionalProperties: false` was hardened in the v5.1.x line. See the [changelog](/changelog-archive#qwed-verification-—-strict-additionalproperties-fail-closed) for the release notes.
</Info>

## Array validation

The Schema Verifier supports standard JSON Schema array keywords including `uniqueItems`.

### `uniqueItems` — fail-closed validation

When a schema sets `uniqueItems: true`, the verifier checks that every element in the array is distinct. If an element is unhashable or otherwise cannot be compared deterministically (for example, an object containing a Python `set`), the verifier **fails closed** — it reports a `uniqueness_validation_error` issue instead of silently passing.

This ensures that unverifiable arrays are never treated as valid.

**Issue types returned for `uniqueItems`:**

| Issue type                    | Meaning                                                          |
| ----------------------------- | ---------------------------------------------------------------- |
| `uniqueness_violation`        | Duplicate items were found in the array                          |
| `uniqueness_validation_error` | Uniqueness could not be verified deterministically (fail-closed) |

**Example — duplicate items:**

```python theme={null}
schema = {"type": "array", "uniqueItems": True}

result = client.verify_schema(obj=[1, 2, 2, 3], schema=schema)
# -> developer_fields.is_valid: false, issue type: "uniqueness_violation"
```

**Example — uncheckable items fail closed:**

```python theme={null}
schema = {"type": "array", "uniqueItems": True}

# Items containing unhashable types cannot be compared deterministically
result = client.verify_schema(obj=[{"bad": {1, 2}}, {"bad": {3, 4}}], schema=schema)
# -> developer_fields.is_valid: false
# -> issue type: "uniqueness_validation_error"
# -> message: "uniqueItems could not be verified deterministically: ..."
```

<Info>
  This fail-closed behavior shipped in v5.1.0. See the [changelog](/changelog-archive#v5-1-0-—-agent-state-governance-and-fail-closed-hardening) for the full release notes.
</Info>

## UCP transaction verification

`verify_ucp_transaction()` shares the same `DiagnosticResult` contract and was hardened in v7.0.0:

* **Complete verdict fields on every path** — the result always carries `transaction_type`, `currency`, and `schema_verifier.ucp_*` constraint ids in `developer_fields`, for both valid and violated verdicts.
* **Type safety** — string or `None` amount fields and non-dict transactions produce deterministic verdicts instead of raising `TypeError` or `AttributeError`.
* **Exact money arithmetic** — computed-total and tax checks use `Decimal` quantized to the currency precision, removing the previous `0.01` float tolerance.
* **`tax` is selected by key presence, not truthiness** — a declared `tax: 0` is used instead of silently falling back to `tax_amount`.

## When to use

* **Invoice Processing:** Ensure line items sum to the total.
* **Financial Reports:** Ensure balance sheets balance.
* **Tax Forms:** Ensure calculated fields match underlying data.
* **Strict API contracts:** Reject payloads with undeclared fields when `strict=True` and `additionalProperties: false` are combined.
