fix(abcip): ALMA review round 1 + ALMD polls InAlarm (not InFaulted)

M1 drop-out is a no-row Unspecified+IsRestatement update (projector case); M2 ack judged over every declared
limit; L1 ActiveAcknowledged for an already-acked new limit; L2 Bad Acked/severity carried/skipped; L3 host
end-to-end test; L4 BOOL member-by-member tests + mixed ALMD/ALMA; L5 detection requires no plain Acked.
ALMD active bit is InAlarm per Rockwell's ALMD reference; InFaulted is input health.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-09 04:22:45 -04:00
parent b3838fcce9
commit 83d8de303c
13 changed files with 641 additions and 161 deletions
@@ -456,6 +456,28 @@ public class NativeAlarmProjectorTests
rows.ShouldBe([kind]);
}
/// <summary>hw4 (AbCip ALMA) — an Unspecified + IsRestatement update on an ACTIVE condition moves the text/severity,
/// keeps active/acked, and writes NO row; an unflagged Unspecified keeps its historical "Activated" row.</summary>
[Fact]
public void A_flagged_Unspecified_update_moves_text_and_severity_without_a_row()
{
var sut = new NativeAlarmProjector();
sut.Project("n1", Evt(AlarmTransitionKind.Raise, AlarmSeverity.Critical, "HH alarm"), out IReadOnlyList<AlarmTransitionKind> _);
sut.Project("n1", Evt(AlarmTransitionKind.Acknowledge), out IReadOnlyList<AlarmTransitionKind> _);
var snap = sut.Project("n1", Evt(AlarmTransitionKind.Unspecified, AlarmSeverity.High, "H alarm", restated: true), out IReadOnlyList<AlarmTransitionKind> rows);
rows.ShouldBeEmpty();
snap.Active.ShouldBeTrue();
snap.Acknowledged.ShouldBeTrue();
snap.Message.ShouldBe("H alarm");
snap.Severity.ShouldBe((ushort)700);
// Control: the same update WITHOUT the flag still writes its row (unchanged behaviour for other sources).
sut.Project("n1", Evt(AlarmTransitionKind.Unspecified, AlarmSeverity.High, "H alarm"), out IReadOnlyList<AlarmTransitionKind> legacy);
legacy.ShouldBe([AlarmTransitionKind.Unspecified]);
}
private static AlarmEventArgs Evt(
AlarmTransitionKind kind,
AlarmSeverity sev = AlarmSeverity.High,