Files
scadaproj/components/health
Joseph Doherty 3dd7aa40ff docs: publish LocalDb 0.1.0 to the feed + reconcile component status against verified state
Publishes the three ZB.MOM.WW.LocalDb packages to the Gitea feed (restore-verified
from a scratch consumer) and adds the build/push.sh the other shared libs already have.

The status prose across CLAUDE.md, README.md and components/*/GAPS.md had drifted from
reality, so it was re-derived from the feed listing and the actual PackageReferences +
registration calls on each consumer's default branch rather than from prior claims.
Five claims were false: Health "not yet adopted" (all four apps wire MapZbHealth),
GalaxyRepository's mxaccessgw adoption "a follow-on" (its Server wires
AddZbGalaxyRepository), Configuration "not yet pushed", Secrets G-8 "not yet
committed", and Theme pinned at 0.2.0 (all four are on 0.3.1). Every doc also said
"three apps" while HistorianGateway is a fourth consumer of seven libs, and all
eight libraries' test counts were stale (re-ran each suite; all green).

Surfaces one previously unrecorded gap: Secrets source is at 0.1.3 with KEK rotation
committed, but the feed tops out at 0.1.2, so no app can consume rotation until it
is published.

Health and observability divergence tables are labelled historical, not re-verified —
the libraries are proven wired, but per-app probe coverage vs spec was not re-walked.

Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
2026-07-18 03:06:49 -04:00
..

Health (readiness / liveness / active-node)

Second normalized component under the operability cluster. Goal: path to shared code — converge the three sister projects onto a common three-tier health endpoint convention and a set of shared probe implementations, proposed as the ZB.MOM.WW.Health library set (3 packages), while each project keeps its own probe registration and orchestrator wiring.

Why health is a strong normalization candidate

Both OtOpcUa and ScadaBridge trace their health-check structure to the same "ScadaLink three-tier pattern" (HealthEndpoints.cs:13 says so explicitly) but have already diverged in probe logic, status semantics, response writer, and endpoint registration style. MxAccessGateway has no shared ancestry here — it has a single hardcoded /health/live endpoint with no real probes at all. The common core (three tiers, database probe, Akka cluster probe, active-node probe) is re-implemented twice and absent once. Shared probe implementations with configurable policies close the gap without forcing identical behavior onto projects with legitimately different cluster semantics.

Status by project

Project Endpoints today Probes today Response writer /healthz IActiveNodeGate Adoption status
OtOpcUa /health/ready, /health/active, /healthz Database (query), AkkaCluster (2-way), AdminRoleLeader (role-filtered) Default (plain-text/JSON) present Not started
MxAccessGateway /health/live only (raw MapGet; hardcoded "Healthy") None (AddHealthChecks() called but unused) Bespoke GatewayHealthReply JSON absent Not started
ScadaBridge /health/ready, /health/active Database (CanConnectAsync), AkkaCluster (3-way), ActiveNode (role-less) HealthChecks.UI.Client JSON absent ActiveNodeGate (backs Inbound API 503 gate) Not started

See each project's current-state/<project>/CURRENT-STATE.md for the code-verified detail and its adoption plan.

Normalized vs. left per-project

Normalized (the shared target):

  • Three-tier endpoint convention: /health/ready (tag ready), /health/active (tag active), /healthz (bare liveness). Mapped by app.MapZbHealth() from ZB.MOM.WW.Health.
  • Canonical JSON response writer (lifted from HealthChecks.UI.Client style; no per-project writer wiring needed).
  • IActiveNodeGate seam — generalized from ScadaBridge's ActiveNodeGate; wired into MapZbHealth for automatic active-tier response.
  • GrpcDependencyHealthCheck — reachability probe for a downstream gRPC dependency (covers OtOpcUa → MxAccessGateway channel and MxAccessGateway → worker IPC).
  • AkkaClusterHealthCheck (in ZB.MOM.WW.Health.Akka) with a configurable status policy. Default = ScadaBridge's three-way policy; OtOpcUaCompat preset preserves OtOpcUa's two-way self-Up-among-members scan.
  • ActiveNodeHealthCheck (in ZB.MOM.WW.Health.Akka) with an optional role filter. Role-less = ScadaBridge's behavior (Up + cluster leader); role-filtered = OtOpcUa's AdminRoleLeader behavior.
  • DatabaseHealthCheck<TContext> (in ZB.MOM.WW.Health.EntityFrameworkCore) with default CanConnectAsync and an optional ProbeQuery delegate.
  • AllowAnonymous on all three tiers by default (consistent across all three projects today).

Left per-project (not forced together):

  • Which probes each app registers, their names, and which tags they carry.
  • Orchestrator / Traefik wiring (sidecars, route rules, upstreams).
  • ScadaBridge's HealthMonitoring/ distributed aggregation pipeline (SiteHealthCollector, CentralHealthAggregator, HealthReportSender, etc.) — domain-specific, no shared-library equivalent.
  • MxAccessGateway's GatewayHealthReply metadata (DefaultBackend, WorkerProtocolVersion) — keep as a bespoke /info endpoint.
  • The x86 worker process — out of process and out of scope; the gateway-side GrpcDependencyHealthCheck observes it indirectly.

Package structure

ZB.MOM.WW.Health ships as three dependency-split packages:

Package Contents Consumers
ZB.MOM.WW.Health Core tiers, MapZbHealth, canonical writer, IActiveNodeGate, GrpcDependencyHealthCheck All three
ZB.MOM.WW.Health.Akka AkkaClusterHealthCheck + status presets, ActiveNodeHealthCheck + role filter OtOpcUa, ScadaBridge
ZB.MOM.WW.Health.EntityFrameworkCore DatabaseHealthCheck<TContext> + optional probe delegate OtOpcUa, ScadaBridge

MxAccessGateway consumes the core package only (no Akka, no EF). OtOpcUa and ScadaBridge consume all three.

Component status

Status: Draft — library built at 0.1.0. Spec and shared-contract written; current-state docs verified; GAPS backlog populated. Library implemented and packed at ../../ZB.MOM.WW.Health/ (3 packages, 58 tests; ZB.MOM.WW.Health, ZB.MOM.WW.Health.Akka, ZB.MOM.WW.Health.EntityFrameworkCore). Adoption by the three apps is the next follow-on tracked in GAPS.md.