Schema revision
Why every object has two version fields, what each one controls, and how schema revisions coexist.
Every opentide object carries two version-like fields, and mixing them up is the single most common authoring mistake. This page explains what each controls and why they are separate.
Two fields, two jobs
| Field | Example | Answers | Authoritative history |
|---|---|---|---|
metadata.schema | rule::1.0 | Which structure does this object follow? | The specification |
metadata.version | 1.2.0 | Which revision of this object's content? | Git |
metadata.schema— the structural schema revision. It selects the validation model and the generatedrule.1.0.schema.jsonyour editor and CLI check against. It changes only when the shape of the object changes (new required fields, renamed structures), which is rare and governed by the specifications.metadata.version— the instance content version. It is your semver-style marker for how a specific detection has evolved. Bump it when you meaningfully change the rule's logic. The real, line-by-line history lives in git.
Never use metadata.version to select a schema file. Content revisions and structural revisions are independent — a rule at content version: 4 can still be schema: rule::1.0.
Naming conventions
The schema identifier maps predictably to files and specs:
| Layer | Format | Example |
|---|---|---|
| Schema identifier | {family}::{major}.{minor} | rule::1.0 |
| Specification file | specs/objects/{family}-{major}.{minor}.md | rule-1.0.md |
| JSON Schema artifact | .opentide/schemas/{family}.{major}.{minor}.schema.json | rule.1.0.schema.json |
| Template artifact | .opentide/templates/{family}.{major}.{minor}.template.yaml | rule.1.0.template.yaml |
| IDE router | .opentide/schemas/opentide.schema.json | objects/**/*.yaml, routed by metadata.schema |
The router opentide.schema.json is the editor entry point. opentide setup vscode maps objects/**/*.yaml to it, and the router applies the revision schema named in each object's metadata.schema:
metadata.schemacompletes to the registered object identifiers (objective::1.0,rule::1.0,rule::1.1,threat::1.0). An unknown identifier is reported on that field with the valid values.- Each identifier has one
if/thenbranch, combined withallOf. Only the branch whose identifier matches applies, so arule::1.1object is checked againstrule.1.1.schema.jsonand nothing else. - Branches reference the revision schemas by relative file name, so they resolve to the files next to the router in
.opentide/schemas/.
Map the router, not a revision schema. A folder mapping such as objects/rules/**/*.yaml → rule.1.0.schema.json checks every rule against rule::1.0 and flags valid rule::1.1 objects.
How revisions coexist
Schema revisions are additive. When a new revision such as rule::1.1 ships, both revisions can exist in the same repo at once:
opentide generate schemasemits bothrule.1.0.schema.jsonandrule.1.1.schema.json.- The IDE router adds a branch and a
metadata.schemavalue for each identifier, and routes objects by their declaredmetadata.schema. - Objects opt in individually by setting
metadata.schema: rule::1.1. Objects that still declarerule::1.0keep validating against1.0until you migrate them.
This means a schema upgrade never forces a big-bang migration — you move objects over at your own pace. For CoreTide-era repos, see the migration guide.
rule::1.1 is that kind of revision. It adds optional metadata.reviewed and changes nothing else. rule::1.0 stays valid and rejects the field. opentide generate schemas writes both rule.1.0.schema.json and rule.1.1.schema.json. opentide generate templates writes both templates and leaves reviewed commented out, so a new file does not invent a review date. List stale rules with opentide rules unreviewed.
What to do when
| Situation | Action |
|---|---|
| You changed a rule's detection logic | Bump metadata.version |
| You upgraded the opentide package | Run opentide generate to refresh schema artifacts |
| A new schema revision is available | Migrate objects to the new metadata.schema when ready |
| Your editor stopped validating YAML | Regenerate: opentide generate schemas |
Implementation detail: how the registry resolves identifiers to models and runs migrations is an internal concern documented in the SDK registry and the opentide source. Authors only need the metadata.schema value.
Normative reference
- Versioning spec — the rules for how revisions are numbered and deprecated.
- Metadata spec — the full
metadatafield contract.