Phase 7 Stream G — Address-space integration (NodeSourceKind + walker emits VirtualTag/ScriptedAlarm)

Per ADR-002, adds the Driver/Virtual/ScriptedAlarm discriminator to DriverAttributeInfo
so the DriverNodeManager's dispatch layer can route Read/Write/Subscribe to the right
runtime subsystem — drivers (unchanged), VirtualTagEngine (Phase 7 Stream B), or
ScriptedAlarmEngine (Phase 7 Stream C).

## Changes
- NodeSourceKind enum added to Core.Abstractions (Driver=0/Virtual=1/ScriptedAlarm=2).
- DriverAttributeInfo gains Source / VirtualTagId / ScriptedAlarmId parameters — all
  default so existing call sites (every driver) compile unchanged.
- EquipmentNamespaceContent gains VirtualTags + ScriptedAlarms optional collections.
- EquipmentNodeWalker emits:
  - Virtual-tag variables — Source=Virtual, VirtualTagId set, Historize flag honored
  - Scripted-alarm variables — Source=ScriptedAlarm, ScriptedAlarmId set, IsAlarm=true
    (triggers node-manager AlarmConditionState materialization)
  - Skips disabled virtual tags + scripted alarms

## Tests — 13/13 in EquipmentNodeWalkerTests (5 new)
- Virtual-tag variables carry Source=Virtual + VirtualTagId + Historize flag
- Scripted-alarm variables carry Source=ScriptedAlarm + IsAlarm=true + Boolean type
- Disabled rows skipped
- Null VirtualTags/ScriptedAlarms collections safe (back-compat for non-Phase-7 callers)
- Driver tags default Source=Driver (ensures no discriminator regression)

## Next
Stream G follow-up: DriverNodeManager dispatch (Read/Write/Subscribe routing by
NodeSourceKind), SealedBootstrap wiring of VirtualTagEngine + ScriptedAlarmEngine,
end-to-end integration test.
This commit is contained in:
Joseph Doherty
2026-04-20 19:41:01 -04:00
parent e97db2d108
commit f1f53e1789
3 changed files with 214 additions and 5 deletions

View File

@@ -33,6 +33,18 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
/// (holding registers with level-set values, set-point writes to analog tags) — the
/// capability invoker respects this flag when deciding whether to apply Polly retry.
/// </param>
/// <param name="Source">
/// Per ADR-002 — discriminates which runtime subsystem owns this node's dispatch.
/// Defaults to <see cref="NodeSourceKind.Driver"/> so existing callers are unchanged.
/// </param>
/// <param name="VirtualTagId">
/// Set when <paramref name="Source"/> is <see cref="NodeSourceKind.Virtual"/> — stable
/// logical id the VirtualTagEngine addresses by. Null otherwise.
/// </param>
/// <param name="ScriptedAlarmId">
/// Set when <paramref name="Source"/> is <see cref="NodeSourceKind.ScriptedAlarm"/> —
/// stable logical id the ScriptedAlarmEngine addresses by. Null otherwise.
/// </param>
public sealed record DriverAttributeInfo(
string FullName,
DriverDataType DriverDataType,
@@ -41,4 +53,21 @@ public sealed record DriverAttributeInfo(
SecurityClassification SecurityClass,
bool IsHistorized,
bool IsAlarm = false,
bool WriteIdempotent = false);
bool WriteIdempotent = false,
NodeSourceKind Source = NodeSourceKind.Driver,
string? VirtualTagId = null,
string? ScriptedAlarmId = null);
/// <summary>
/// Per ADR-002 — discriminates which runtime subsystem owns this node's Read/Write/
/// Subscribe dispatch. <c>Driver</c> = a real IDriver capability surface;
/// <c>Virtual</c> = a Phase 7 <see cref="DriverAttributeInfo"/>.VirtualTagId'd tag
/// computed by the VirtualTagEngine; <c>ScriptedAlarm</c> = a scripted Part 9 alarm
/// materialized by the ScriptedAlarmEngine.
/// </summary>
public enum NodeSourceKind
{
Driver = 0,
Virtual = 1,
ScriptedAlarm = 2,
}