feat(site-runtime): persist native-alarm display metadata so rehydrated conditions render fully (UA4)

This commit is contained in:
Joseph Doherty
2026-07-09 01:09:13 -04:00
parent 326d945d85
commit 2efe1a4202
3 changed files with 98 additions and 18 deletions
@@ -191,13 +191,26 @@ public class NativeAlarmActor : ReceiveActor
continue;
}
// Metadata (type/category/message) is not persisted — rehydrate the
// condition + key so the DebugView reflects last-known state until the
// first source snapshot replaces it.
// Restore the persisted display metadata (UA4) so the rehydrated condition renders
// fully (type/category/message/values) until the first source snapshot replaces it.
// Null/malformed metadata falls back to empty strings (pre-UA4 rows behave as before).
NativeAlarmMetadata meta = EmptyMetadata;
if (!string.IsNullOrEmpty(row.MetadataJson))
{
try
{
meta = JsonSerializer.Deserialize<NativeAlarmMetadata>(row.MetadataJson) ?? EmptyMetadata;
}
catch (JsonException)
{
meta = EmptyMetadata;
}
}
var t = new NativeAlarmTransition(
row.SourceReference, string.Empty, string.Empty, AlarmTransitionKind.Snapshot,
condition, string.Empty, string.Empty, string.Empty, string.Empty, string.Empty,
null, row.LastTransitionAt, string.Empty, string.Empty);
row.SourceReference, string.Empty, meta.AlarmTypeName, AlarmTransitionKind.Snapshot,
condition, meta.Category, string.Empty, meta.Message, string.Empty, string.Empty,
null, row.LastTransitionAt, meta.CurrentValue, meta.LimitValue);
_alarms[row.SourceReference] = t;
// Rehydration replays last-known state on (re)start — surface it
// upward for the DebugView but do NOT re-log it as a fresh operational
@@ -479,7 +492,12 @@ public class NativeAlarmActor : ReceiveActor
return;
var batch = _dirtyUpserts.Values
.Select(t => (t.SourceReference, JsonSerializer.Serialize(t.Condition), t.TransitionTime))
.Select(t => (
t.SourceReference,
JsonSerializer.Serialize(t.Condition),
(string?)JsonSerializer.Serialize(new NativeAlarmMetadata(
t.AlarmTypeName, t.Category, t.Message, t.CurrentValue, t.LimitValue)),
t.TransitionTime))
.ToList();
_dirtyUpserts.Clear();
@@ -519,4 +537,16 @@ public class NativeAlarmActor : ReceiveActor
public static readonly FlushPersistence Instance = new();
private FlushPersistence() { }
}
/// <summary>Empty metadata fallback for pre-UA4 rows or malformed <c>metadata_json</c>.</summary>
private static readonly NativeAlarmMetadata EmptyMetadata =
new(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty);
/// <summary>
/// Persisted display metadata for a native alarm condition (UA4). Serialized into the
/// <c>metadata_json</c> column so a rehydrated condition renders fully (type/category/message/
/// current+limit values) before the first source snapshot re-supplies it.
/// </summary>
private sealed record NativeAlarmMetadata(
string AlarmTypeName, string Category, string Message, string CurrentValue, string LimitValue);
}