fix(alarms): Severity runs one direction, higher = more urgent; raw priority kept (#129)

AlarmConditionState.Severity mixed two conventions: OPC UA rows carried Part 9
Severity (higher = more severe) while MxGateway native alarms and computed
alarms carried a raw AVEVA-style priority (1 = most urgent). Every consumer
ranks higher as worse, so Worst Severity, the severity filter/sort and the
site event-log Error threshold picked the LEAST urgent MxGateway/computed
alarms.

- AlarmPriorityBands: the OtOpcUa GalaxyAlarmPriority table (lmxopcua#887,
  b61f3e05), value for value: 1-250 -> 1000, 251-500 -> 750, 501-750 -> 500,
  751-999 -> 250; <= 0 clamps to Critical, > 999 to Low.
- MxGatewayAlarmMapper bands the gateway severity (= AVEVA priority);
  AlarmConditionStateFactory.ForComputed bands PriorityLevel. OPC UA unchanged.
- AlarmConditionState gains trailing Priority (int?): the raw source number,
  exactly the pre-#129 Severity. AlarmStateChanged.Priority and the wire
  AlarmStateUpdate.priority keep that meaning (no proto change); central derives
  Severity by kind (SeverityFromPriority), so an older site decodes correctly.
- ScriptAlarm gains trailing Priority. The native MES 900-999 band and the MES
  API Severity/MinSeverity/MaxSeverity key off Priority; rig seed scripts moved
  from a.Severity to a.Priority, so MES output is unchanged.
- AlarmActor raise logs Error when the banded severity >= 700 (same threshold
  as NativeAlarmActor): priority 1-500 Error, 501+ Warning (was raw >= 700).
- NativeAlarmActor upgrades pre-#129 native_alarm_state rows on rehydrate.
- Debug snapshot decode restores Condition.Priority from the row's priority.
- Docs: Commons, DCL, SiteRuntime, Communication, CentralUI, InboundAPI,
  HighLevelReqs, MES alarm-status plan, CLAUDE.md.

Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
This commit is contained in:
Joseph Doherty
2026-11-12 13:58:28 -05:00
parent e36cd6055e
commit dd4f1c2aa3
39 changed files with 686 additions and 120 deletions
+1 -1
View File
@@ -254,7 +254,7 @@ Inbound API scripts **cannot** call shared scripts directly — shared scripts a
> **Reading alarm state via a routed script.** There is deliberately **no** `Route.To(...).GetAlarms(...)` verb. An inbound method that needs a machine's current alarms resolves the instance and calls a **site script** that uses the Site Runtime `Alarms.CurrentAsync()` accessor — `Route.To(code).Call("SimpleAlarmStatus", new { ... })`. Alarm state is per-instance and lives on the site's Instance Actor; keeping the read inside a site script means the filtering/shaping happens where the data is, and central stays a thin router. This is the shape the MES alarm-status endpoints use (`docs/plans/2026-06-30-mes-alarm-status-api.md` §5.1); see [Component-SiteRuntime.md](Component-SiteRuntime.md) → *Alarm State (read-only)* for the accessor.
>
> **Example — `AlarmStatus`.** The rig demo template `MesAlarmDemo`'s site script (`docker/seed-mes-alarm-demo.sh`) answers `Route.To(MachineCode).Call("AlarmStatus", new { AlarmFilter = new { FlaggedOnly, IncludeAcked, MinSeverity, MaxSeverity, NameFilter } })` with the legacy `AlarmStatusResponse { WasSuccessful, ErrorText, Alarms: AlarmInfo[] }`, setting `IsFlaggedForMES = a.IsMesReportable` per row for **computed** alarms (the template's `TemplateAlarm.IsMesReportable` flag, instance-overridable) and the **900–999 severity band** for **native** alarms, which carry no per-alarm `IsMesReportable` row. `SimpleAlarmStatus` is the same shape with `FlaggedOnly` hard-wired true.
> **Example — `AlarmStatus`.** The rig demo template `MesAlarmDemo`'s site script (`docker/seed-mes-alarm-demo.sh`) answers `Route.To(MachineCode).Call("AlarmStatus", new { AlarmFilter = new { FlaggedOnly, IncludeAcked, MinSeverity, MaxSeverity, NameFilter } })` with the legacy `AlarmStatusResponse { WasSuccessful, ErrorText, Alarms: AlarmInfo[] }`, setting `IsFlaggedForMES = a.IsMesReportable` per row for **computed** alarms (the template's `TemplateAlarm.IsMesReportable` flag, instance-overridable) and the **900–999 priority band** (on `ScriptAlarm.Priority`) for **native** alarms, which carry no per-alarm `IsMesReportable` row. The MES `Severity` field and `MinSeverity`/`MaxSeverity` filters are that raw 0–999 priority (`ScriptAlarm.Priority`), not the unified `ScriptAlarm.Severity`, which since Gitea #129 is banded and runs higher = more urgent. `SimpleAlarmStatus` is the same shape with `FlaggedOnly` hard-wired true.
#### Input/Output
- **Input parameters** are available as defined in the method definition.