feat(scripts): ScriptAlarm.IsMesReportable + Alarms.MesReportableAsync() mirrored on both compile surfaces

Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
This commit is contained in:
Joseph Doherty
2026-09-11 10:12:47 -04:00
parent ce8fc092c8
commit 17d9a4cd2c
8 changed files with 92 additions and 4 deletions
@@ -161,6 +161,18 @@ public class SandboxAlarmsAccessor
"Alarms.CurrentAsync() reads the site Instance Actor's live alarm conditions, " +
"which aren't available in the central Test Run sandbox — deploy to a site to " +
"exercise alarm-reading scripts.");
/// <summary>
/// Mirrors <c>AlarmsAccessor.MesReportableAsync</c> for compile parity; unsupported at
/// run time in the central Test Run sandbox.
/// </summary>
/// <param name="cancellationToken">Token used to cancel the read (unused in the sandbox).</param>
/// <returns>Never returns; always throws <see cref="ScriptSandboxException"/> in the sandbox.</returns>
public Task<IReadOnlyList<ScriptAlarm>> MesReportableAsync(CancellationToken cancellationToken = default)
=> throw new ScriptSandboxException(
"Alarms.MesReportableAsync() reads the site Instance Actor's live alarm conditions, " +
"which aren't available in the central Test Run sandbox — deploy to a site to " +
"exercise alarm-reading scripts.");
}
/// <summary>
@@ -55,6 +55,10 @@ namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Scripts;
/// True for a placeholder row standing in for a CONFIGURED native source binding that
/// currently holds no conditions. Scripts enumerating real alarms should filter these out.
/// </param>
/// <param name="IsMesReportable">
/// True when the deployed configuration flags the alarm as MES-reportable (template
/// checkbox or instance override). Always false for native conditions.
/// </param>
public sealed record ScriptAlarm(
string Name,
string SourceReference,
@@ -76,4 +80,5 @@ public sealed record ScriptAlarm(
DateTimeOffset? AckTime,
string CurrentValue,
string LimitValue,
bool IsConfiguredPlaceholder);
bool IsConfiguredPlaceholder,
bool IsMesReportable = false);
@@ -154,6 +154,12 @@ public sealed class ScriptCompileSurface
/// <returns>The instance's current alarm conditions.</returns>
public Task<IReadOnlyList<ScriptAlarm>> CurrentAsync(CancellationToken cancellationToken = default)
=> throw new NotSupportedException(CompileOnly);
/// <summary>Mirrors <c>AlarmsAccessor.MesReportableAsync</c>.</summary>
/// <param name="cancellationToken">Token used to cancel the read.</param>
/// <returns>The MES-reportable subset of the instance's current alarm conditions.</returns>
public Task<IReadOnlyList<ScriptAlarm>> MesReportableAsync(CancellationToken cancellationToken = default)
=> throw new NotSupportedException(CompileOnly);
}
/// <summary>Compile-only mirror of <c>ScriptRuntimeContext.ExternalSystemHelper</c>.</summary>
@@ -398,6 +398,18 @@ public class AlarmsAccessor
/// <returns>The instance's current alarm conditions; empty when it holds none.</returns>
public Task<IReadOnlyList<ScriptAlarm>> CurrentAsync(CancellationToken cancellationToken = default)
=> _ctx.GetAlarmsAsync(cancellationToken);
/// <summary>
/// <see cref="CurrentAsync"/> restricted to alarms whose deployed configuration flags them
/// MES-reportable (the template checkbox, or an instance override). Only computed alarms
/// can carry the flag — the Instance Actor stamps it from the deployed config — so native
/// conditions and their placeholder rows are never included. Callers still filter on
/// <c>Active</c> to get only triggered alarms.
/// </summary>
/// <param name="cancellationToken">Cancels the wait for the actor's reply.</param>
/// <returns>The MES-reportable subset of the instance's current alarm conditions.</returns>
public Task<IReadOnlyList<ScriptAlarm>> MesReportableAsync(CancellationToken cancellationToken = default)
=> _ctx.GetMesReportableAlarmsAsync(cancellationToken);
}
internal static class ScopeAccessorFactory
@@ -1272,6 +1272,12 @@ public class ScriptRuntimeContext
return response.Alarms.Select(ToScriptAlarm).ToList();
}
/// <summary><see cref="GetAlarmsAsync"/> restricted to rows flagged MES-reportable.</summary>
/// <param name="cancellationToken">Cancels the wait for the actor's reply.</param>
/// <returns>The MES-reportable subset of the instance's current alarm conditions.</returns>
internal async Task<IReadOnlyList<ScriptAlarm>> GetMesReportableAlarmsAsync(CancellationToken cancellationToken = default)
=> (await GetAlarmsAsync(cancellationToken)).Where(a => a.IsMesReportable).ToList();
/// <summary>
/// Projects a retained <see cref="AlarmStateChanged"/> onto the flat, script-facing
/// <see cref="ScriptAlarm"/> shape. <c>Condition</c> is the authority for the
@@ -1301,7 +1307,8 @@ public class ScriptRuntimeContext
AckTime: a.AckTime,
CurrentValue: a.CurrentValue,
LimitValue: a.LimitValue,
IsConfiguredPlaceholder: a.IsConfiguredPlaceholder);
IsConfiguredPlaceholder: a.IsConfiguredPlaceholder,
IsMesReportable: a.IsMesReportable);
/// <summary>
/// Site-local tracking-status API for cached operations.