build(deps): OPC Foundation SDK 1.5.378.106 -> 1.5.378.182 (lmxopcua#782 interim hop)
v2-ci / unit-tests (push) Has been cancelled

Behaviour-neutral hop: pin the SDK AggregateManager default to our
TreatUncertainAsBad=false (SDK .182 flipped it to true), parity guard now an
explicit deliberate-divergence assertion plus a booted-server check; adapt to
obsolete FindPredefinedNode(Type)/TraceConfiguration; Microsoft.Extensions.
Logging.Abstractions 10.0.7 -> 10.0.8 (SDK floor); stall wire test's late-flush
positive control is best-effort (.176 preserves publish queue ordering).

Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
Joseph Doherty
2026-11-09 22:47:58 -05:00
parent 42c73bfb83
commit 2da58d0360
9 changed files with 66 additions and 22 deletions
@@ -61,12 +61,12 @@ internal static class AdvertisedAggregateFunctions
var advertised = new List<NodeId>();
lock (diagnostics.Lock)
{
var folder = diagnostics.FindPredefinedNode(Folder, typeof(BaseObjectState));
var folder = diagnostics.FindPredefinedNode<BaseObjectState>(Folder);
if (folder is null) return null;
foreach (var aggregateId in StandardAggregateIds)
{
var aggregateNode = diagnostics.FindPredefinedNode(aggregateId, null);
var aggregateNode = diagnostics.FindPredefinedNode<NodeState>(aggregateId);
if (aggregateNode is null) continue;
var advertise = AggregateFunctionMap.Map(aggregateId) is { } aggregate && served.Contains(aggregate);
@@ -535,7 +535,6 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
},
TransportQuotas = BuildTransportQuotas(_options.Quotas),
ClientConfiguration = new ClientConfiguration(),
TraceConfiguration = new TraceConfiguration(),
};
await config.ValidateAsync(ApplicationType.Server, ct).ConfigureAwait(false);
@@ -234,6 +234,16 @@ public sealed class OtOpcUaSdkServer : StandardServer
IServerInternal server, ApplicationConfiguration configuration)
{
var manager = base.CreateAggregateManager(server, configuration);
// Pin the SDK manager's default AggregateConfiguration (what live AggregateFilter subscriptions compute under
// and what the server advertises) to OUR defaults. Opc.Ua.Server 1.5.378.182 flipped the SDK default of
// TreatUncertainAsBad to true; history-read aggregates (Sql.Common evaluators) are fixed at false, so the live
// and historical paths must agree and stay behaviour-neutral across the SDK hop (lmxopcua#782).
var defaults = manager.GetDefaultConfiguration(null) ?? new AggregateConfiguration();
defaults.TreatUncertainAsBad = ServerAggregateConfiguration.TreatUncertainAsBad;
defaults.PercentDataBad = ServerAggregateConfiguration.PercentDataBad;
defaults.PercentDataGood = ServerAggregateConfiguration.PercentDataGood;
defaults.UseSlopedExtrapolation = ServerAggregateConfiguration.UseSlopedExtrapolation;
manager.SetDefaultConfiguration(defaults);
_otOpcUaNodeManager?.SyncAdvertisedAggregates();
return manager;
}
@@ -15,8 +15,12 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;
/// SDK computes them under it; an interval is Good only when all of
/// it is (<see cref="PercentDataGood"/> = 100) and Bad only when none of it is non-Bad
/// (<see cref="PercentDataBad"/> = 100), otherwise <c>UncertainDataSubNormal</c>; the value past the last sample
/// is held (stepped, <see cref="UseSlopedExtrapolation"/> = false). These are also the SDK's own server defaults
/// (<c>AggregateManager.GetDefaultConfiguration</c>), which a test pins.
/// is held (stepped, <see cref="UseSlopedExtrapolation"/> = false). Part 13's AggregateConfiguration defaults are
/// TreatUncertainAsBad = false, PercentDataBad = PercentDataGood = 100, UseSlopedExtrapolation = false (from the
/// spec as recalled, not re-read offline). The SDK matched these until Opc.Ua.Server 1.5.378.182, which flipped
/// <c>TreatUncertainAsBad</c> to true: that is a DELIBERATE DIVERGENCE we do not follow (consumers such as
/// ScadaBridge read these aggregates). <c>OtOpcUaSdkServer.CreateAggregateManager</c> pushes these values into
/// the SDK manager so live AggregateFilter subscriptions agree with history reads; a test pins both sides.
/// </para>
/// <para>
/// A request asking for <c>UseServerCapabilitiesDefaults</c>, or spelling out exactly these values, is served;
@@ -6,7 +6,7 @@
<ItemGroup>
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Server"/>
<!-- All OPC UA packages aligned at the central 1.5.378.106 (Opc.Ua.Server 1.5.378.106 is now
<!-- All OPC UA packages aligned at the central 1.5.378.182 (Opc.Ua.Server 1.5.378.182 is now
published). The prior VersionOverride pinned Opc.Ua.Configuration/Core to 1.5.374.126 to match
the older Server, but the published Host unified Core to 378 anyway (Driver.OpcUaClient needs
it) → Server 1.5.374 loaded against Core 1.5.378 and threw TypeLoadException(INodeIdFactory).