|
| 1 | +# Meta-schema |
| 2 | + |
| 3 | +The OpenDecree meta-schema is a [JSON Schema 2020-12](https://json-schema.org/draft/2020-12/schema) document that describes the [decree schema-format](schema-format.md) itself — what keys are valid, what types are allowed, what constraints belong with which field type. Tooling that consumes the meta-schema can validate `*.decree.schema.yaml` files offline without shelling out to the Go reference parser. |
| 4 | + |
| 5 | +> **Alpha Software** — OpenDecree is under active development. The schema format and meta-schema may change without notice between versions. Not recommended for production use yet. |
| 6 | +
|
| 7 | +## What's covered |
| 8 | + |
| 9 | +The meta-schema enforces the **layer-1 structural shape** of a schema YAML: |
| 10 | + |
| 11 | +- Required keys (`spec_version`, `name`, `fields`). |
| 12 | +- Slug regex on `name` and field-path regex on `fields` map keys. |
| 13 | +- The 8 valid field types and the per-type constraint compatibility matrix (numeric / string / json / other). |
| 14 | +- Top-level reserved keys (`dependentRequired`, `validations`). |
| 15 | +- `unevaluatedProperties: false` at every object level — unknown keys are rejected. |
| 16 | +- `x-*` vendor extensions accepted at every object level. |
| 17 | + |
| 18 | +## What's not covered |
| 19 | + |
| 20 | +Layer-2 semantic rules that JSON Schema cannot express stay in the Go parser at [`internal/schema/validate_constraints.go`](https://github.com/opendecree/decree/blob/main/internal/schema/validate_constraints.go): |
| 21 | + |
| 22 | +- Referential integrity between `redirect_to` and existing field paths. |
| 23 | +- `dependentRequired` keys/values referring to defined fields (not just regex-valid paths). |
| 24 | +- `validations` entries referring to defined fields (the meta-schema only checks `rule`/`message` are non-empty; expression compilation and field-resolution come from the CEL engine). |
| 25 | +- Range sanity: `minimum > maximum`, `minLength > maxLength`, etc. |
| 26 | +- Prefix-overlap rejection between sibling field paths (e.g. `payments` and `payments.fee` cannot coexist). |
| 27 | + |
| 28 | +Runtime validation of config values against the schema is also out of scope — that is a separate concern handled in [`internal/validation/`](https://github.com/opendecree/decree/tree/main/internal/validation), driven by the per-field type and constraints. |
| 29 | + |
| 30 | +## Files |
| 31 | + |
| 32 | +The repository ships two single-file meta-schemas under [`schemas/v0.1.0/`](https://github.com/opendecree/decree/tree/main/schemas/v0.1.0): |
| 33 | + |
| 34 | +| File | Validates | Purpose | |
| 35 | +|------|-----------|---------| |
| 36 | +| `decree-schema.yaml` / `decree-schema.json` | `*.decree.schema.yaml` | Schema-definition format — fields, constraints, validations, dependentRequired. | |
| 37 | +| `decree-config.yaml` / `decree-config.json` | `*.decree.config.yaml` | Tenant-side config format — the values applied against a published schema. | |
| 38 | + |
| 39 | +YAML is the human-edited source of truth. JSON copies are generated by [`scripts/yaml-to-json.py`](https://github.com/opendecree/decree/blob/main/scripts/yaml-to-json.py) and committed alongside their YAML sources so consumers (schemastore.org, IDE language servers, CI validators) can `$ref` the JSON directly without a build step. |
| 40 | + |
| 41 | +## Using the meta-schema |
| 42 | + |
| 43 | +### Editor IntelliSense (yaml-language-server) |
| 44 | + |
| 45 | +Add the modeline on line 1 of your schema or config file. VS Code, Neovim, IntelliJ, Helix, and Zed via [yaml-language-server](https://github.com/redhat-developer/yaml-language-server) auto-apply the schema for autocompletion and inline error highlighting: |
| 46 | + |
| 47 | +```yaml |
| 48 | +# yaml-language-server: $schema=https://schemas.opendecree.io/schema/v0.1.0/decree-schema.json |
| 49 | +spec_version: v1 |
| 50 | +name: payments |
| 51 | +fields: |
| 52 | + payments.fee: |
| 53 | + type: number |
| 54 | +``` |
| 55 | +
|
| 56 | +For config files: |
| 57 | +
|
| 58 | +```yaml |
| 59 | +# yaml-language-server: $schema=https://schemas.opendecree.io/schema/v0.1.0/decree-config.json |
| 60 | +spec_version: v1 |
| 61 | +values: |
| 62 | + payments.fee: |
| 63 | + value: 0.025 |
| 64 | +``` |
| 65 | +
|
| 66 | +### CI validation |
| 67 | +
|
| 68 | +Run [`check-jsonschema`](https://github.com/python-jsonschema/check-jsonschema) over your repo's schema files in CI: |
| 69 | + |
| 70 | +```bash |
| 71 | +pip install check-jsonschema |
| 72 | +check-jsonschema \ |
| 73 | + --schemafile https://schemas.opendecree.io/schema/v0.1.0/decree-schema.json \ |
| 74 | + '**/*.decree.schema.yaml' |
| 75 | +
|
| 76 | +check-jsonschema \ |
| 77 | + --schemafile https://schemas.opendecree.io/schema/v0.1.0/decree-config.json \ |
| 78 | + '**/*.decree.config.yaml' |
| 79 | +``` |
| 80 | + |
| 81 | +The decree project itself uses this approach via `make validate-meta-schemas` — see [`scripts/validate-meta-schemas.py`](https://github.com/opendecree/decree/blob/main/scripts/validate-meta-schemas.py). |
| 82 | + |
| 83 | +### Programmatic validation |
| 84 | + |
| 85 | +Any [JSON Schema 2020-12 validator](https://json-schema.org/implementations) can consume the meta-schema. Examples: |
| 86 | + |
| 87 | +- **Python** — [`jsonschema`](https://python-jsonschema.readthedocs.io/) (vanilla, what `validate-meta-schemas.py` uses) |
| 88 | +- **Node.js** — [`ajv`](https://ajv.js.org/) with the `ajv-formats` and `ajv-draft-2020` extensions |
| 89 | +- **Go** — [`santhosh-tekuri/jsonschema/v6`](https://github.com/santhosh-tekuri/jsonschema) |
| 90 | +- **Rust** — [`jsonschema`](https://crates.io/crates/jsonschema) |
| 91 | + |
| 92 | +## URL scheme + versioning |
| 93 | + |
| 94 | +``` |
| 95 | +https://schemas.opendecree.io/schema/v{MAJOR}.{MINOR}.{PATCH}/decree-{schema|config}.json |
| 96 | +``` |
| 97 | +
|
| 98 | +**Pre-stable (current):** full SemVer in the path — `https://schemas.opendecree.io/schema/v0.1.0/...`. Each release of the meta-schema is published at its exact version path forever; older versions stay reachable for tools that pin a specific version. |
| 99 | +
|
| 100 | +**Post-1.0.0 (future):** switch to major-only paths (`/v1/`) with permanent redirects from historical full-SemVer URLs. Matches the OpenAPI 3.x dated-URL practice. |
| 101 | +
|
| 102 | +## Stability policy |
| 103 | +
|
| 104 | +The meta-schema follows SemVer. Versions are bumped in a separate cadence from the decree server release; the meta-schema version is always present in the URL. |
| 105 | +
|
| 106 | +| Change | Bump | |
| 107 | +|--------|------| |
| 108 | +| New optional property | Minor | |
| 109 | +| New `enum` value | Minor | |
| 110 | +| Loosening a constraint (higher `maxLength`, wider `pattern`) | Minor | |
| 111 | +| Removing a property | Major | |
| 112 | +| Removing an `enum` value | Major | |
| 113 | +| Tightening a constraint | Major | |
| 114 | +| Changing a property's type | Major | |
| 115 | +| Making an optional property required | Major | |
| 116 | +
|
| 117 | +Per [project policy](https://github.com/opendecree/decree/blob/main/docs/development/checklists.md), the project is currently in alpha — both the schema format and the meta-schema may break without a major bump until v1.0.0. Until then, the version path makes it possible to pin against a known shape. |
| 118 | +
|
| 119 | +## Local development |
| 120 | +
|
| 121 | +The repository's `make validate-meta-schemas` target validates every checked-in `*.decree.schema.yaml` and `*.decree.config.yaml` against the matching meta-schema, plus a set of known-invalid fixtures under [`schemas/v0.1.0/testdata/invalid/`](https://github.com/opendecree/decree/tree/main/schemas/v0.1.0/testdata/invalid) that must fail validation. CI runs the same script on every PR. |
| 122 | +
|
| 123 | +## Related |
| 124 | +
|
| 125 | +- [Schema Format](schema-format.md) — the format reference the meta-schema describes. |
| 126 | +- [`.agents/context/schema-spec.md`](https://github.com/opendecree/decree/blob/main/.agents/context/schema-spec.md) — internal design brief for the v0.1.0 spec. |
| 127 | +- [JSON Schema 2020-12 spec](https://json-schema.org/draft/2020-12/schema) |
| 128 | +- [yaml-language-server modeline format](https://github.com/redhat-developer/yaml-language-server#using-inlined-schema) |
0 commit comments