feat(mesh-phase4): DriverHostActor runs ConfigDb-free (LocalDb alarm store, guarded acks)

Nullable ConfigDb factory; UpsertNodeDeploymentState no-ops when absent
(central persists acks from the ApplyAck); scripted-alarm condition state
served from the LocalDb store instead of the ConfigDb-backed Ef store.
Combines Phase-4 Tasks 4 + 6. Removes the interim dbFactory! cast.

Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
Joseph Doherty
2026-07-23 12:39:41 -04:00
parent 4f4cdd05ec
commit d907160747
7 changed files with 466 additions and 20 deletions
@@ -11,7 +11,9 @@ using ZB.MOM.WW.LocalDb.Replication;
using ZB.MOM.WW.OtOpcUa.Host.Configuration;
using ZB.MOM.WW.OtOpcUa.Host.Health;
using ZB.MOM.WW.OtOpcUa.Host.Observability;
using ZB.MOM.WW.OtOpcUa.Core.ScriptedAlarms;
using ZB.MOM.WW.OtOpcUa.Runtime.DeploymentCache;
using ZB.MOM.WW.OtOpcUa.Runtime.ScriptedAlarms;
namespace ZB.MOM.WW.OtOpcUa.Host.IntegrationTests;
@@ -107,6 +109,18 @@ public sealed class LocalDbWiringTests : IDisposable
.ShouldBeOfType<LocalDbDeploymentArtifactCache>();
}
[Fact]
public void DriverGraph_AlarmStateStoreResolvesToTheLocalDbBackedImplementation()
{
// Phase 4: scripted-alarm condition state is served from the replicated LocalDb store on a
// driver node. A dropped registration would silently fall the actor back to the EF store (or,
// DB-less, skip the alarm host) — this pins the LocalDb store as the resolved implementation.
var sp = BuildDriverGraph();
sp.GetService<IAlarmStateStore>()
.ShouldBeOfType<LocalDbAlarmConditionStateStore>();
}
[Fact]
public void DriverGraph_DefaultOff_SyncStatusReportsNotConnectedAndNoPeer()
{
@@ -142,6 +156,8 @@ public sealed class LocalDbWiringTests : IDisposable
sp.GetService<ILocalDb>().ShouldBeNull();
sp.GetService<IDeploymentArtifactCache>().ShouldBeNull();
// Phase 4: an admin-only node never registers the LocalDb alarm store either.
sp.GetService<IAlarmStateStore>().ShouldBeNull();
// The unconditionally-registered health check must still resolve and construct — it is meant
// to no-op to Healthy when LocalDb is absent, not to fail because ISyncStatus is missing.