63289d377c
Wire the materialised AlarmConditionState method handlers so a client calling Acknowledge/Confirm/Shelve/AddComment is gated on the AlarmAck data-plane role and, when allowed, routed back to the scripted-alarm engine via a new `alarm-commands` DistributedPubSub topic. - Commons: new AlarmCommand DTO (AlarmId/Operation/User/Comment/UnshelveAtUtc). - ScriptedAlarmHostActor: add AlarmCommandsTopic const. - OtOpcUaNodeManager: settable AlarmCommandRouter + wire OnAcknowledge/OnConfirm/ OnAddComment/OnShelve/OnTimedUnshelve. Each resolves the principal off ISessionOperationContext.UserIdentity as RoleCarryingUserIdentity, fails closed (BadUserAccessDenied) when the AlarmAck role is absent or no identity, else maps + routes an AlarmCommand and returns Good. OnShelve discriminates OneShotShelve/ TimedShelve/Unshelve from the SDK flags; TimedShelve expiry = UtcNow + ms. No Akka/IActorRef handle — only the Action<AlarmCommand> delegate. T20 de-dup note left; WriteAlarmCondition untouched. - OpcUaServer.Security: OpcUaDataPlaneRoles.AlarmAck shared const (the role was a bare string everywhere; introduced one symbol for the gate + tests). - OtOpcUaSdkServer: SetAlarmCommandRouter pass-through. - Host: boot wiring publishes each command via mediator.Tell(Publish(...)) using a lazy ActorSystem accessor (mirrors DpsScriptLogPublisher). - Tests: 11 new gate + mapping tests (OpcUaServer.Tests 88->99, all green).