fix(opcua): shelve declaration ids from a fixed set, not an address-space lookup; pin instance-id + state-machine-id shelve calls (#629)

New() ran FindNodeInAddressSpace under Lock, taking other node managers' locks (lock-order
risk); the three AlarmConditionType_ShelvingState_* ids are now a static set. Adds wire tests:
TimedShelve/Unshelve by the condition's own instance method ids (object = condition or its
ShelvingState) succeed and report, and a ShelvedStateMachineType_* id call is pinned as
BadMethodInvalid with a positive control.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 15:01:54 -04:00
parent 1de8357d13
commit 66c47c3ddd
3 changed files with 111 additions and 12 deletions
+5 -3
View File
@@ -135,9 +135,11 @@ them by type + browse path), and neither were the Part 9 methods — calling the
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.
`MethodDeclarationId` (a fixed set of those three ids — no address-space lookup, which would take other
node managers' locks under ours), so OneShotShelve/TimedShelve/Unshelve by the
`AlarmConditionType_ShelvingState_*` id keep working, as do calls by the condition's own instance method
ids (`{ConditionId}/ShelvingState/TimedShelve`, on the condition or its ShelvingState). Calling them by the
`ShelvedStateMachineType_*` id returns `BadMethodInvalid` — a pinned trade-off.
- **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