Update equipment identifier model per v2 hardening addendum
- EquipmentId is now system-generated ('EQ-' + 12 hex from UUID), never
operator-supplied — eliminates duplicate-identity corruption from typos
and bulk-import renames (lmxopcua decision #125)
- ZTag and SAPID fleet-wide uniqueness enforced via ExternalIdReservation
table outside generation versioning — rollback-safe (decision #124)
- Identifier table now shows who-sets-it column (3 operator, 2 system)
- Note added: ExternalIdReservation pattern is a precedent for non-versioned
cross-generation invariants; check for similar hazard when scoping ACLs
This commit is contained in:
@@ -155,13 +155,17 @@ The path is the **navigation identifier**: it tells you where the equipment live
|
|||||||
|
|
||||||
The plan commits to a **multi-identifier model** — the v2 implementation design surfaced that production usage requires more than UUID + path. Every equipment instance carries **five identifiers**, all exposed as OPC UA properties on the equipment node so external systems can resolve by their preferred identifier without a sidecar service:
|
The plan commits to a **multi-identifier model** — the v2 implementation design surfaced that production usage requires more than UUID + path. Every equipment instance carries **five identifiers**, all exposed as OPC UA properties on the equipment node so external systems can resolve by their preferred identifier without a sidecar service:
|
||||||
|
|
||||||
| Identifier | Required? | Uniqueness | Mutable? | Purpose |
|
| Identifier | Required? | Uniqueness | Mutable? | Who sets it? | Purpose |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|---|
|
||||||
| **EquipmentUuid** | Yes | Fleet-wide | **Immutable** | Downstream events, canonical model joins, cross-system lineage. RFC 4122 UUIDv4 (random). Not derived from the path. |
|
| **EquipmentUuid** | Yes | Fleet-wide | **Immutable** | System-generated (UUIDv4) | Downstream events, canonical model joins, cross-system lineage. Not derived from the path. |
|
||||||
| **EquipmentId** | Yes | Within cluster | **Immutable after publish** | Internal logical key for cross-generation config diffs. Not user-facing. |
|
| **EquipmentId** | Yes | Within cluster | **Immutable** | **System-generated** (`'EQ-' + first 12 hex chars of EquipmentUuid`) | Internal logical key for cross-generation config diffs. Never operator-supplied, never editable, never present in CSV imports. System-generation eliminates the corruption path where operator typos or bulk-import renames would mint duplicate equipment identities and permanently split downstream UUID-keyed lineage. |
|
||||||
| **MachineCode** | Yes | Within cluster | Mutable (rename tracked) | **Operator-facing colloquial name** (e.g., `machine_001`). This is what operators say on the radio and write in runbooks — UUID and path are not mnemonic enough for daily operations. Surfaced prominently in Admin UI alongside ZTag. |
|
| **MachineCode** | Yes | Within cluster | Mutable (rename tracked) | **Operator-set** | **Operator-facing colloquial name** (e.g., `machine_001`). What operators say on the radio and write in runbooks. Surfaced prominently in Admin UI alongside ZTag. |
|
||||||
| **ZTag** | Optional | Fleet-wide | Mutable (re-assigned by ERP) | **ERP equipment identifier.** Primary identifier for browsing in Admin UI per operational request. |
|
| **ZTag** | Optional | Fleet-wide | Mutable (re-assigned by ERP) | **Operator-set** (sourced from ERP) | **ERP equipment identifier.** Primary identifier for browsing in Admin UI per operational request. Fleet-wide uniqueness enforced via `ExternalIdReservation` table outside generation versioning (see below). |
|
||||||
| **SAPID** | Optional | Fleet-wide | Mutable (re-assigned by SAP PM) | **SAP PM equipment identifier.** Required for maintenance system join. |
|
| **SAPID** | Optional | Fleet-wide | Mutable (re-assigned by SAP PM) | **Operator-set** (sourced from SAP PM) | **SAP PM equipment identifier.** Required for maintenance system join. Fleet-wide uniqueness enforced via `ExternalIdReservation` table (see below). |
|
||||||
|
|
||||||
|
**Three operator-set fields** (MachineCode, ZTag, SAPID), **two system-generated** (EquipmentUuid, EquipmentId). CSV imports match by `EquipmentUuid` for updates; rows without UUID create new equipment with system-generated identifiers.
|
||||||
|
|
||||||
|
**`ExternalIdReservation` table — fleet-wide uniqueness for ZTag and SAPID across rollback and re-enable.** Fleet-wide uniqueness for external identifiers cannot be expressed within generation-versioned tables because old generations and disabled equipment can still hold the same values — rollback or re-enable would silently reintroduce duplicates that corrupt downstream ERP/SAP joins. A dedicated `ExternalIdReservation` table sits **outside generation versioning**; `sp_PublishGeneration` reserves IDs atomically at publish; FleetAdmin-only `sp_ReleaseExternalIdReservation` (audit-logged, requires reason) is the only path to free a value for reuse. This is a precedent: some cross-generation invariants need their own non-versioned tables. When ACL design is scoped (see OtOpcUa → Authorization model), check whether any ACL grant has a similar rollback-reuse hazard.
|
||||||
|
|
||||||
**Path** (the 5-level UNS hierarchy address) is a **sixth** identifier but is **not** stored on the equipment node as a flat property — it is the node's **browse path** by construction. Path can change (equipment moves, area renamed); UUID and EquipmentId cannot.
|
**Path** (the 5-level UNS hierarchy address) is a **sixth** identifier but is **not** stored on the equipment node as a flat property — it is the node's **browse path** by construction. Path can change (equipment moves, area renamed); UUID and EquipmentId cannot.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user