SnowBridge now owns machine-data ingest, in-process .NET transformation, and direct writes to curated tables in Snowflake. Collapses the previous ingest/transform split into a single service; no dbt, no external orchestrator, no Snowflake landing tier. Keeps the in-house .NET pattern consistent with ScadaBridge and OtOpcUa. The "Snowflake dbt Transform Layer" roadmap workstream merges into SnowBridge (7 → 6 workstreams); Year 2 canonical-state-based OEE moves with it. Canonical model still has three surfaces — the third is renamed from "dbt curated layer" to "SnowBridge curated layer in Snowflake"; mechanics unchanged.
82 lines
6.7 KiB
Markdown
82 lines
6.7 KiB
Markdown
# 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.) |
|
||
| **SnowBridge curated layer in Snowflake** | Same templates derive column definitions and dimension tables for the curated analytics model. SnowBridge owns ingest + in-process .NET transform + write; no separate dbt layer. |
|
||
|
||
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"
|