test+docs(v3-batch4-wp5): 2-node dual-namespace harness tests + address-space docs
Tests: - OpcUaServer.IntegrationTests/DualNamespaceAddressSpaceTests.cs (NEW, over-the-wire, offline-safe): both namespace URIs registered + distinct; Raw + UNS subtrees browse and read; UNS variable Organizes-references its raw node; single-source fan-out parity (identical value/quality/timestamp on both NodeIds); HistoryRead via either NodeId -> GoodNoData under the shared tagname; WriteOperate gate symmetric across both NodeIds. - Host.IntegrationTests/EquipmentNamespaceMaterializationTests.cs (extended): full deploy -> persisted-artifact -> ParseComposition round-trip carrying both realms, sealing across the redundant 2-node cluster (redundancy non-interference). In-memory harness, offline. Docs (dual-namespace reality): - CLAUDE.md: new "v3 OPC UA Address Space (Batch 4)" section + Batch-4 testing paragraph. - docs/Uns.md: address-space projection (two namespaces, Organizes edge, effective-name leaf). - docs/Historian.md: dual-registration (both NodeIds -> one tagname); updated CLI examples. - docs/ScriptedAlarms.md + docs/AlarmTracking.md: multi-notifier fan-out, ConditionId=RawPath. - docs/ScriptEditor.md: dual-namespace clarification (script tag-path semantics unchanged). Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox
This commit is contained in:
+35
@@ -110,6 +110,41 @@ UNS-referenced, or named by a script literal — see [`Raw.md`](Raw.md).
|
||||
`GalaxyMxGateway` driver in `/raw`, referenced into equipment like any other raw
|
||||
tag. There is no separate alias concept or `SystemPlatform`-kind namespace.
|
||||
|
||||
### OPC UA address-space projection (v3 Batch 4 — dual namespace)
|
||||
|
||||
> **v3 (Batch 4):** the server now exposes the address space under **two OPC UA
|
||||
> namespaces** instead of the old single `https://zb.com/otopcua/ns`:
|
||||
>
|
||||
> | Namespace URI | Subtree | NodeId `s=` scheme |
|
||||
> |---|---|---|
|
||||
> | `https://zb.com/otopcua/raw` | the `/raw` device tree (Folder → Driver → Device → TagGroup → Tag) | the node's **RawPath** (e.g. `Plant/Modbus/dev1/Speed`) |
|
||||
> | `https://zb.com/otopcua/uns` | the UNS tree (Area → Line → Equipment → signal) | the slash-joined **`Area/Line/Equipment/EffectiveName`** |
|
||||
|
||||
Every device value has **exactly one source** — the raw tag's node in the Raw
|
||||
namespace. A `UnsTagReference` projects that raw tag into an equipment as a
|
||||
**UNS-namespace variable** whose NodeId leaf is the reference's **effective name**
|
||||
(the display-name override else the raw tag's `Name`). The UNS variable does not
|
||||
bind a driver of its own: it carries an **`Organizes` reference to its backing raw
|
||||
node** and mirrors it. A single driver publish for a RawPath **fans out** to the
|
||||
raw NodeId AND every referencing UNS NodeId with identical value / quality /
|
||||
source-timestamp — the two NodeIds never drift.
|
||||
|
||||
- **Reads / subscriptions** work through either NodeId and return the same data.
|
||||
- **Writes** route through either NodeId to the same backing driver ref under the
|
||||
**same `WriteOperate` gating** (a UNS write is neither more nor less privileged
|
||||
than the raw write it fans from); a failed device write reverts both NodeIds via
|
||||
the shared fan-out.
|
||||
- **HistoryRead** works through either NodeId and returns the same series — both
|
||||
NodeIds register the **same historian tagname** (see [`Historian.md`](Historian.md)).
|
||||
- **Native alarms** materialize once at the raw tag (`ConditionId = RawPath`) and
|
||||
fan via SDK notifiers to the raw device folder AND every referencing equipment
|
||||
folder — see [`ScriptedAlarms.md`](ScriptedAlarms.md) / [`AlarmTracking.md`](AlarmTracking.md).
|
||||
|
||||
Note the two distinct identity strings: the wire **NodeId** is the path
|
||||
`Area/Line/Equipment/EffectiveName`, while the **effective-name uniqueness key**
|
||||
above is `{EquipmentId}/{EffectiveName}` (the logical per-equipment collision
|
||||
space the guards enforce). They are related but not the same string.
|
||||
|
||||
### Virtual tags
|
||||
|
||||
A virtual tag is bound to an equipment and driven by a **script** (no driver).
|
||||
|
||||
Reference in New Issue
Block a user