fix(alarms): revert a native ack that reaches no driver; refuse native acks while the host is Stale (lmxopcua#765)

Residuals of #760:

1. An ack routed to a disabled / not-yet-spawned driver, or to a stubbed child
   (driver does not run on this node, or its factory rejected the config), was
   dropped and left the condition Acknowledged. DriverHostActor now reverts it
   through the same NativeAlarmProjector.TryRevertAcknowledge path as a refused
   ack.

2. A native ack arriving while the host is Stale was dropped before the projector
   recorded it, so it could never be reverted. Stale now marks the whole
   NativeAlarmAckPreflightView unavailable (SetHostUnavailable), so the node
   manager refuses every native ack synchronously; BecomeSteady clears it.

3. (keyed sessions without a Galaxy identity) is not addressed.

Tests: DriverHostActorNativeAlarmTests' client-ack test and the FOCAS respawn
theory now start the host's own driver (AckingAlarmDriver; a factory building a
real FocasDriver per spawn over per-instance fake CNCs, with a real config-change
respawn) - both fail against the fix in their old shape. New: ack to a disabled
driver reverts, ack to a stubbed driver reverts, a Stale host refuses through the
pre-check view - all three fail with the fix mutated out. Runtime.Tests 943/0/3.
Docs: AlarmTracking.md, .claude/rules/alarms.md.

Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
Joseph Doherty
2026-11-09 13:29:15 -05:00
parent 7f29a75edb
commit f54922f94c
8 changed files with 312 additions and 87 deletions
+6 -2
View File
@@ -464,12 +464,16 @@ from the scripted `AlarmCommandRouter`:
driver refuses or fails the ack (or is still connecting / reconnecting),
`DriverInstanceActor` replies `AlarmAckFailed` and
`DriverHostActor` re-projects the condition **unacknowledged** (a fresh
condition event). Only an ack still pending in `NativeAlarmProjector` is
condition event). An ack whose owning driver is not running (disabled,
not yet spawned) or is a stub on this node is reverted the same way by
the host itself (#765). Only an ack still pending in `NativeAlarmProjector` is
reverted: a driver transition projected since then is authoritative. A
refusal the driver can decide without I/O (Galaxy: an anonymous session
and no fallback ack account) is instead returned synchronously as
`BadUserAccessDenied` by the node manager's `NativeAlarmAckPreflight`
before anything is applied. Galaxy value writes have a separate correlated
before anything is applied — as is every native ack while the driver host
is Stale (configuration database unreachable at boot), when no ack can be
routed or reverted (#765). Galaxy value writes have a separate correlated
write-outcome path. An awaited
ack RPC does not prove the ack reached AVEVA event history: the H6 live
verification remains [operator-gated](plans/2026-06-15-stillpending-phase-3-opcua-standards-design.md).