fix(health): flag metrics-stale for never-reported sites via FirstSeenAt anchor — null LastReportReceivedAt no longer skips the check (plan R2-01 T8)

This commit is contained in:
Joseph Doherty
2026-07-13 10:45:22 -04:00
parent e4765b2eed
commit 11efe4be05
4 changed files with 55 additions and 5 deletions
@@ -513,4 +513,35 @@ public class CentralHealthAggregatorTests
aggregator.MarkHeartbeat("site-a", time.GetUtcNow());
Assert.NotEqual(offlineAt, aggregator.GetSiteState("site-a")!.LastStatusChangeAt);
}
/// <summary>
/// Round-2 N3: a site known only via heartbeats (LastReportReceivedAt == null)
/// previously skipped the staleness check forever — a report pipeline dead
/// from FIRST BOOT showed "online with no metrics" indefinitely. FirstSeenAt
/// anchors the window instead (LastHeartbeatAt cannot: heartbeats advance it).
/// </summary>
[Fact]
public void HeartbeatOnlySite_NeverReported_IsFlaggedMetricsStale()
{
var (aggregator, time) = NewAggregator(metricsStaleTimeout: TimeSpan.FromMinutes(2));
aggregator.MarkHeartbeat("site-a", time.GetUtcNow()); // registered via heartbeat only
time.Advance(TimeSpan.FromMinutes(3));
aggregator.MarkHeartbeat("site-a", time.GetUtcNow()); // still heartbeating => online
aggregator.CheckForOfflineSites();
var state = aggregator.GetSiteState("site-a")!;
Assert.True(state.IsOnline); // liveness unchanged
Assert.True(state.IsMetricsStale); // was impossible before the fix
}
/// <summary>A heartbeat-only site inside the window is NOT falsely flagged.</summary>
[Fact]
public void HeartbeatOnlySite_WithinStaleWindow_IsNotFlagged()
{
var (aggregator, time) = NewAggregator(metricsStaleTimeout: TimeSpan.FromMinutes(2));
aggregator.MarkHeartbeat("site-a", time.GetUtcNow());
time.Advance(TimeSpan.FromMinutes(1));
aggregator.MarkHeartbeat("site-a", time.GetUtcNow());
aggregator.CheckForOfflineSites();
Assert.False(aggregator.GetSiteState("site-a")!.IsMetricsStale);
}
}