# Validate

> Check documents with loopmath ocp validate, upgrade old ones with migrate, and validate in CI.

The reference checker is part of loopmath. It checks a document against the JSON Schema of its version and against every [numbered rule](https://orchestrationcontextprotocol.io/specification/0.3/conformance). A clean result does not prove a document meets every requirement in the field descriptions: see [what the checker does not test](https://orchestrationcontextprotocol.io/specification/0.3/conformance#checker-limits).

```bash
pipx install loopmath    # Python 3.11 or newer; or: uv tool install loopmath
```

## validate

```bash
loopmath ocp validate FILE [FILE ...] [--json]
```

```text Output
PASS  run.ocp.json  (ocp 0.3; 0 errors, 0 warnings)
FAIL  broken.ocp.json  (ocp 0.3; 1 error, 0 warnings)
  error E112 $['attempts'][0]['node']: attempt 'implement.a1' names unknown node 'implemnt'
```

- Each finding has a level, a [rule code](https://orchestrationcontextprotocol.io/specification/0.3/conformance), a JSON path and a message. The terminal shows the first eight per file; `--json` carries all of them.
- Given several files, it also runs the cross-file part of [E194](https://orchestrationcontextprotocol.io/specification/0.3/conformance#e194): documents in one slate share a task and a base commit.
- Warnings never fail a file.

| Exit code | Meaning |
|---|---|
| `0` | No file has an error. |
| `1` | At least one file has an error. |
| `2` | A file was not found. |

### JSON output

```json
{
  "schema": "loopmath.ocp.validate/1",
  "ok": false,
  "files": [
    {
      "path": "broken.ocp.json",
      "ocp": "0.3",
      "ok": false,
      "errors": 1,
      "warnings": 0,
      "findings": [
        {
          "level": "error",
          "code": "E112",
          "path": "$['attempts'][0]['node']",
          "message": "attempt 'implement.a1' names unknown node 'implemnt'"
        }
      ]
    }
  ]
}
```

## migrate

```bash
loopmath ocp migrate FILE [FILE ...] [--out DIR] [--json]
```

Upgrades 0.1 and 0.2 documents to 0.3. See [Versions in practice](https://orchestrationcontextprotocol.io/docs/learn/versioning).

- With `--out DIR`, each result is written to `DIR` as `NAME.ocp.json`. It refuses to write over an input.
- Without `--out`, a single result goes to standard output. Several files need `--out`, or `--json` to get every migrated document in one object.
- A result with a conformance error is reported and never written.

## In CI

```yaml .github/workflows/ocp.yml
name: ocp
on: [push, pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pipx install loopmath
      - run: loopmath ocp validate runs/*.ocp.json
```

## Schema only

The JSON Schemas (draft 2020-12) are in the [specification repository](https://github.com/loopmath/loopmath/tree/main/spec), one per version. Any validator can check a document against them:

```python
import json
import jsonschema

schema = json.load(open("ocp-v0.3.schema.json"))
jsonschema.Draft202012Validator(schema).validate(json.load(open("run.ocp.json")))
```

A schema check alone misses the numbered rules: references between entities, cycles, sums and the configuration id. A document that passes the schema can still fail `loopmath ocp validate`.
