chore: organize solution into module folders (Core/Server/Drivers/Client/Tooling)

Group all 69 projects into category subfolders under src/ and tests/ so the
Rider Solution Explorer mirrors the module structure. Folders: Core, Server,
Drivers (with a nested Driver CLIs subfolder), Client, Tooling.

- Move every project folder on disk with git mv (history preserved as renames).
- Recompute relative paths in 57 .csproj files: cross-category ProjectReferences,
  the lib/ HintPath+None refs in Driver.Historian.Wonderware, and the external
  mxaccessgw refs in Driver.Galaxy and its test project.
- Rebuild ZB.MOM.WW.OtOpcUa.slnx with nested solution folders.
- Re-prefix project paths in functional scripts (e2e, compliance, smoke SQL,
  integration, install).

Build green (0 errors); unit tests pass. Docs left for a separate pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-17 01:55:28 -04:00
parent 69f02fed7f
commit a25593a9c6
1044 changed files with 365 additions and 343 deletions
@@ -0,0 +1,81 @@
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions;
/// <summary>
/// Driver capability for alarm events. Optional — only drivers whose backends expose
/// alarm conditions implement this. Currently: Galaxy (MxAccess alarms), FOCAS
/// (CNC alarms), OPC UA Client (A&amp;C events from upstream server).
/// </summary>
public interface IAlarmSource
{
/// <summary>
/// Subscribe to alarm events for a node-set (typically: a folder or equipment subtree).
/// The driver fires <see cref="OnAlarmEvent"/> for every alarm transition.
/// </summary>
Task<IAlarmSubscriptionHandle> SubscribeAlarmsAsync(
IReadOnlyList<string> sourceNodeIds,
CancellationToken cancellationToken);
/// <summary>Cancel an alarm subscription returned by <see cref="SubscribeAlarmsAsync"/>.</summary>
Task UnsubscribeAlarmsAsync(IAlarmSubscriptionHandle handle, CancellationToken cancellationToken);
/// <summary>Acknowledge one or more active alarms by source node ID + condition ID.</summary>
Task AcknowledgeAsync(
IReadOnlyList<AlarmAcknowledgeRequest> acknowledgements,
CancellationToken cancellationToken);
/// <summary>Server-pushed alarm transition (raise / clear / change).</summary>
event EventHandler<AlarmEventArgs>? OnAlarmEvent;
}
/// <summary>Opaque alarm-subscription identity returned by <see cref="IAlarmSource.SubscribeAlarmsAsync"/>.</summary>
public interface IAlarmSubscriptionHandle
{
/// <summary>Driver-internal subscription identifier (for diagnostics + post-mortem).</summary>
string DiagnosticId { get; }
}
/// <summary>One alarm acknowledgement in a batch.</summary>
public sealed record AlarmAcknowledgeRequest(
string SourceNodeId,
string ConditionId,
string? Comment);
/// <summary>Event payload for <see cref="IAlarmSource.OnAlarmEvent"/>.</summary>
/// <param name="SubscriptionHandle">Subscription this event belongs to.</param>
/// <param name="SourceNodeId">Driver-side identifier for the alarm source.</param>
/// <param name="ConditionId">Stable id correlating raise / ack / clear of the same condition.</param>
/// <param name="AlarmType">Driver-defined alarm type name (e.g. AnalogLimitAlarm.HiHi).</param>
/// <param name="Message">Human-readable alarm description.</param>
/// <param name="Severity">Four-bucket severity ladder.</param>
/// <param name="SourceTimestampUtc">When this transition occurred.</param>
/// <param name="OperatorComment">
/// Operator-supplied comment recorded by the upstream alarm system on Acknowledge
/// transitions. Null on raise / clear, or when the upstream path can't surface
/// the comment (the Galaxy sub-attribute fallback path collapses comments into a
/// single string write — null on that path; the driver-native gateway path
/// populates this).
/// </param>
/// <param name="OriginalRaiseTimestampUtc">
/// When the alarm originally entered the active state. Preserved across
/// Acknowledge transitions so OPC UA Part 9 conditions keep the original raise
/// time in <c>Time</c>. Null when the upstream path doesn't surface it.
/// </param>
/// <param name="AlarmCategory">
/// Upstream alarm taxonomy bucket (e.g. <c>Process</c> / <c>Safety</c> /
/// <c>Diagnostics</c>). Maps to OPC UA <c>ConditionClassName</c> downstream when
/// a class mapping is configured. Null when the upstream path doesn't carry it.
/// </param>
public sealed record AlarmEventArgs(
IAlarmSubscriptionHandle SubscriptionHandle,
string SourceNodeId,
string ConditionId,
string AlarmType,
string Message,
AlarmSeverity Severity,
DateTime SourceTimestampUtc,
string? OperatorComment = null,
DateTime? OriginalRaiseTimestampUtc = null,
string? AlarmCategory = null);
/// <summary>Mirrors the <c>NodePermissions</c> alarm-severity enum in <c>docs/v2/acl-design.md</c>.</summary>
public enum AlarmSeverity { Low, Medium, High, Critical }