Merge rows 80+73+71: nullable LocalDb health fields on unreplicated sites (Host supplies ReplicationIsConfigured), StartupReconcilerActive on the health report (proto field 29) with central No-self-heal badge, standby active-node ERR downgraded via narrowly-keyed Serilog filter

# Conflicts:
#	CLAUDE.md
This commit is contained in:
Joseph Doherty
2026-08-16 04:17:40 -04:00
22 changed files with 1208 additions and 69 deletions
@@ -267,6 +267,14 @@
Replication backlog
</span>
}
@if (IsStartupReconcilerMissing(state))
{
<span class="badge bg-warning text-dark"
data-test="startup-reconciler-badge"
title="This site reported that a node booted without its SiteReconciliationActor (no IDeploymentConfigFetcher), so the startup self-heal is disabled: a deploy that lands while the node is DOWN will not be recovered on restart. Config still reaches the node via LocalDb replication while it is up. Check the node's configuration.">
No self-heal
</span>
}
@if (!state.IsOnline && state.LastStatusChangeAt is { } changedAt)
{
<small class="text-muted">offline since @changedAt.ToString("u")</small>
@@ -566,6 +574,22 @@
&& state.LocalDbBacklogAboveSince is { } since
&& DateTimeOffset.UtcNow - since >= HealthOptions.Value.LocalDbBacklogSustainedFor;
// Register row 73: the "No self-heal" badge.
//
// Warning-level treatment, deliberately not an error and never an offline-style state:
// the node still receives config through LocalDb replication while it is up, so what it
// has lost is recovery from a deploy that landed while it was DOWN. That is degraded,
// not down — which is exactly what a warning badge says.
//
// Tri-state, and only the explicit false is badged. Null means "not reported": the
// central self-report row (where a site reconciler is meaningless) and any site node on
// a pre-row-73 build both send null, and badging those would fire on every site the
// moment central is upgraded ahead of the sites. Offline sites are skipped for the same
// reason the backlog badge skips them — the Offline badge is the signal that matters.
private bool IsStartupReconcilerMissing(SiteHealthState state) =>
state.IsOnline
&& state.LatestReport?.StartupReconcilerActive == false;
// Online central nodes, from the same ClusterNodes list the Nodes column renders.
// Fewer than two means no standby, which disables the manual-failover control. This is
// a display-side guard only — AkkaManualFailoverService re-checks against live cluster