# schemas — Canonical OT Equipment Definitions > **Status**: DRAFT — initial seed contributed by the OtOpcUa team (`lmxopcua/docs/v2/acl-design.md`, `lmxopcua/docs/v2/plan.md` decisions #112, #115, corrections doc D1+D2). **Ownership of this content is TBD** — should be assigned to a cross-team authority since it's consumed by OT and IT systems alike. The future owner team should treat this seed as a starting point, not a finished spec. > > **Temporary location**: this seed lives at `3yearplan/schemas/` as a sub-tree of the 3-year-plan repo because Gitea's push-to-create is disabled and creating the dedicated `schemas` repo requires a manual UI step. Once the dedicated repo is created (proposed: `gitea.dohertylan.com/dohertj2/schemas`) and an owner team is named, this content should migrate over and references update accordingly. Until then, treat this directory as the canonical location for the seed. ## Purpose Single source of truth for the org's canonical OT equipment definitions: 1. **UNS hierarchy** — the per-site Unified Namespace subtree (Enterprise / Site / Area / Line / Equipment) per the 3-year-plan handoff §UNS Naming Hierarchy 2. **Equipment-class templates** — per-class declarations of which raw signals each equipment type exposes (FANUC CNCs surface these; Modbus PLCs surface those; etc.) 3. **Type vocabulary** — the canonical machine-state values (`Running` / `Idle` / `Faulted` / `Starved` / `Blocked`) and any other shared enumerations consumers need ## Who consumes this Three surfaces per the 3-year-plan handoff §"Canonical Model Integration": | Consumer | How | |----------|-----| | **OtOpcUa equipment namespace** | At deploy/config time, OtOpcUa nodes fetch the equipment-class template referenced by `Equipment.EquipmentClassRef` and use it to validate the operator-configured tag set. Drift = config validation error | | **Redpanda topics + Protobuf schemas** | Equipment-class templates derive Protobuf message definitions for canonical events (`equipment.state.transitioned`, etc.) | | **dbt curated layer in Snowflake** | Same templates derive column definitions and dimension tables for the curated analytics model | OtOpcUa is one consumer of three. Decisions about format, structure, and naming live with the schemas-repo owner team (TBD), not with any one consumer. ## Format **JSON Schema (Draft 2020-12) authored in this repo; Protobuf code-generated for wire serialization where needed** (per OtOpcUa corrections doc D2 recommendation, blessed by the OtOpcUa team but pending schemas-repo team review). Why JSON Schema as the authoring format: - Idiomatic for .NET (System.Text.Json + JsonSchema.Net) — OtOpcUa reads templates with no extra dependencies - Idiomatic for CI tooling (every CI runner can `jq` / validate JSON Schema without extra toolchain) - Supports validation at multiple layers: operator-visible Admin UI errors in OtOpcUa, schemas-repo CI gates, downstream consumer runtime validation - Better authoring experience than Protobuf (binary format, .proto compiler, poor merge story) - Where wire-format efficiency matters (Redpanda events), code-generate Protobuf from the JSON Schema source. One-way derivation is simpler than bidirectional sync. ## Structure ``` schemas/ ├── README.md This file ├── CONTRIBUTING.md How to add a new class, validate, PR process ├── format/ JSON Schemas defining the format of everything below │ ├── equipment-class.schema.json Shape of an equipment-class template │ ├── uns-subtree.schema.json Shape of a per-site UNS subtree definition │ └── tag-definition.schema.json Shape of an individual tag declaration inside a template ├── classes/ Equipment-class templates │ └── fanuc-cnc.json Pilot class per OtOpcUa corrections D1 ├── uns/ Per-site UNS subtree definitions │ └── example-warsaw-west.json Worked example └── docs/ ├── overview.md What this repo is, who uses it, lifecycle ├── format-decisions.md Why JSON Schema, structure rationale, Protobuf derivation └── consumer-integration.md How each of the 3 consumers integrates ``` ## Lifecycle 1. **Author** — humans edit JSON files in this repo, validated against the schemas in `format/` by the CI gate 2. **Publish** — merging to `main` makes the new content the authoritative version; semver tag on each release 3. **Consume** — each consumer pulls a specific tagged version (or `main` for staging environments) and integrates per `docs/consumer-integration.md` The current state has no consumers actively reading from this repo — content is seed-only. First wiring happens in OtOpcUa Phase 1+ when `Equipment.EquipmentClassRef` validation lands (see `lmxopcua/docs/v2/plan.md` decision #112). ## Open Questions Owner-team-decisions (not for OtOpcUa or any single consumer to make alone): - **Repo ownership and review process**: who owns this repo? PR review SLA? Format changes need who to sign off? - **Versioning policy**: semver per release? Per-class versioning vs whole-repo versioning? How do consumers pin versions? - **Backward-compatibility policy**: when a class adds a new required signal, do all existing equipment in OtOpcUa's central config DB need to be updated atomically? Or graceful degradation? - **Cross-class shared types**: how does a `Position` measurement (used by both FANUC CNC and a Beckhoff axis) avoid duplicate definitions? - **Pilot class scope**: FANUC CNC chosen per OtOpcUa corrections D1 because FOCAS already has a fixed pre-defined hierarchy. Confirm with the schemas-repo team that this is the right starting class. - **Enterprise shortname** (currently `ent` placeholder) — the UNS subtree definitions reference an Enterprise segment; the canonical value comes from organizational naming authority. ## References - 3-year-plan handoff: `gitea.dohertylan.com/dohertj2/3yearplan` → `handoffs/otopcua-handoff.md` §"UNS Naming Hierarchy" + §"Canonical Model Integration" + §"Digital Twin Touchpoints" - OtOpcUa corrections doc: `gitea.dohertylan.com/dohertj2/3yearplan` → `handoffs/otopcua-corrections-2026-04-17.md` §B2 (schemas-repo dependencies) + §D1 (pilot class) + §D2 (format) - OtOpcUa v2 plan: `gitea.dohertylan.com/dohertj2/lmxopcua` → `docs/v2/plan.md` decisions #108–115 + §"UNS naming hierarchy"