fix(opcua): Part 9 condition children get instance-scoped NodeIds (#629)
Create(assignNodeIds: true) asked CustomNodeManager2.New, whose default returns the
node's current id, so every condition child kept the type's ns=0 instance-declaration id
(or an SDK-generated ns=0 number): translate of a child path returned BadNoMatch and a
Read of a browsed child id was BadNodeIdUnknown or served from the TYPE (UnshelveTime 0
on a condition timed-shelved for a minute), bypassing the data-plane ACL.
OtOpcUaNodeManager.New now derives {conditionId}/{browsePath} in the condition's
namespace, so the ACL scope of a child is its condition's scope plus the path. The
ShelvingState methods adopt their original AlarmConditionType_ShelvingState_* id as
MethodDeclarationId so clients calling them by that id still resolve. Condition removal
and rebuild forget the whole PredefinedNodes subtree so a removed condition's children
stop answering.
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -115,6 +115,38 @@ that `ConditionClassId` / `ConditionClassName` do too. The two class fields are
|
||||
> a live↔history join key. Correlate on `ConditionId` / the RawPath instead. (Pre-existing; the
|
||||
> live-path fix above does not change the history path.)
|
||||
|
||||
### Condition child nodes are instance-scoped (#629)
|
||||
|
||||
Every child of a materialised condition — `ActiveState`, `ActiveState/Id`, `AckedState/Id`,
|
||||
`ShelvingState/UnshelveTime`, `Message`, `Severity`, `Retain`, the method nodes, … — carries the NodeId
|
||||
**`{ConditionId}/{browse path}`** in the condition's own namespace: e.g.
|
||||
`ns=<raw>;s=Plant/Modbus/dev1/temp_hi/ShelvingState/UnshelveTime`, or
|
||||
`ns=<uns>;s=<ScriptedAlarmId>/ActiveState/Id`. So `TranslateBrowsePathsToNodeIds` from the condition
|
||||
resolves, and a direct Read or data-change subscription on a child returns **this condition's** value.
|
||||
|
||||
Before #629 the children kept ns=0 ids: `Create(…, assignNodeIds: true)` asks the node manager's
|
||||
`INodeIdFactory.New`, and the SDK default returns the node's current id — the condition type's
|
||||
instance-declaration id (`i=9189` for UnshelveTime) or an SDK-generated ns=0 number. Every translate of
|
||||
a child path returned `BadNoMatch`; a Read of a browsed child id was either `BadNodeIdUnknown` or served
|
||||
from the **type** (UnshelveTime read `0` on a condition timed-shelved for a minute). `OtOpcUaNodeManager.New`
|
||||
now derives the id. Event delivery was never affected (events copy the instance's fields; clients select
|
||||
them by type + browse path), and neither were the Part 9 methods — calling them by the type's method id
|
||||
(`MethodIds.AcknowledgeableConditionType_Acknowledge`, …) still works, because the SDK matches a method on
|
||||
its declaration id. ⚠️ The ShelvingState methods needed help here: their SDK declaration id is the
|
||||
`ShelvedStateMachineType`'s (`i=2948`…), and they were only ever found by the `AlarmConditionType_ShelvingState_*`
|
||||
id (`i=9212`…) because that WAS their NodeId. `New` adopts that original id as the method's
|
||||
`MethodDeclarationId` (only when it is a real standard-namespace method node, never an SDK-generated
|
||||
number), so OneShotShelve/TimedShelve/Unshelve by the `AlarmConditionType_ShelvingState_*` id keep working.
|
||||
Calling them by the `ShelvedStateMachineType_*` id is not supported.
|
||||
|
||||
- **ACL:** the slash-joined id makes a child's ACL scope its condition's scope plus the browse path, so
|
||||
with `Security:Acl:Enabled` a child is governed exactly like its condition (a grant covering the
|
||||
condition covers its children; one that does not, denies them). Before #629 a child was in ns=0 and
|
||||
bypassed the data-plane gate entirely.
|
||||
- **Removal:** removing or rebuilding a condition forgets its whole subtree, so a removed condition's
|
||||
children answer `BadNodeIdUnknown`, not their last value.
|
||||
- Guarded over the wire by `ConditionChildNodeIdTests`.
|
||||
|
||||
### Condition source-data Quality (#477)
|
||||
|
||||
`ConditionType.Quality` reports the quality of the condition's source data. It was never assigned, and
|
||||
|
||||
Reference in New Issue
Block a user