fix(twincat): publish BadNodeIdUnknown for unresolvable native-subscribe references (U12)

The native subscribe path silently skipped a reference it could not resolve
(unknown RawPath, or a tag routed to an unconfigured device), leaving the node
on whatever status the server seeded. It now publishes one BadNodeIdUnknown
snapshot, matching the poll path.

Refs #739
Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
Joseph Doherty
2026-10-22 13:57:01 -04:00
parent 8a4cf8b823
commit de21a54949
2 changed files with 73 additions and 2 deletions
@@ -666,8 +666,16 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
{
foreach (var reference in fullReferences)
{
if (!_resolver.TryResolve(reference, out var def)) continue;
if (!_devices.TryGetValue(def.DeviceHostAddress, out var device)) continue;
// An unresolvable reference (unknown RawPath, or a tag routed to an unconfigured device)
// publishes BadNodeIdUnknown once — the poll path's status — instead of leaving the node on
// whatever status the server seeded it with.
if (!_resolver.TryResolve(reference, out var def)
|| !_devices.TryGetValue(def.DeviceHostAddress, out var device))
{
RaiseDataChange(handle, reference, new DataValueSnapshot(
null, TwinCATStatusMapper.BadNodeIdUnknown, null, DateTime.UtcNow));
continue;
}
var parsed = TwinCATSymbolPath.TryParse(def.SymbolPath);
var symbolName = parsed?.ToAdsSymbolName() ?? def.SymbolPath;
@@ -724,6 +732,10 @@ public sealed class TwinCATDriver : IDriver, IReadable, IWritable, ITagDiscovery
return handle;
}
/// <summary>Raises one data change for a native subscription.</summary>
private void RaiseDataChange(ISubscriptionHandle handle, string reference, DataValueSnapshot snapshot) =>
OnDataChange?.Invoke(this, new DataChangeEventArgs(handle, reference, snapshot));
/// <summary>
/// Registers one native notification and records its replayable intent on the device — both
/// under the device <see cref="DeviceState.ConnectGate"/> so the register can't race a