fix(utc/locale): close Theme 2 — 8 UTC / time / locale findings
UTC invariant + culture-safety fixes across UI form binding, audit entity hydrate, and locale-dependent parses. Highlights: - CentralUI-026/027: AuditFilterBar / SiteCallsReport / NotificationReport / EventLogs now apply SpecifyKind(Local) + ToUniversalTime() at form submit so browser-local datetime-local inputs aren't silently treated as UTC. - Commons-019: AuditEvent.OccurredAtUtc / IngestedAtUtc init-setters re-tag any incoming DateTime as Kind=Utc, documenting the invariant. - CD-018: AuditLogEntityTypeConfiguration adds UTC ValueConverters on the *Utc DateTime columns so EF hydrate yields Kind=Utc (SQL Server's datetime2 has no Kind metadata, so reads were returning Unspecified). - CD-020: GetPartitionBoundariesOlderThanAsync now SpecifyKind(Utc) on the raw-ADO read, matching the existing defence in AuditLogPartitionMaintenance. - SEL-021: EventLogQueryService.DateTimeOffset.Parse now uses InvariantCulture + AssumeUniversal | AdjustToUniversal. - SR-023: Convert.ToDouble in ScriptActor + AlarmActor (4 sites) now passes InvariantCulture so non-US locales don't mis-parse string values. - HM-020: CentralHealthAggregator.MarkHeartbeat anchors LastHeartbeatAt to max(receivedAt, now) on offline→online so a stale receivedAt can't leave a recovered site one tick from re-going-offline. 3 new tests added (AuditLog UTC converter, AuditFilterBar/EventLogs/ NotificationReport-touching CentralUI tests already cover Apply paths, heartbeat offline→online). Build clean; ConfigurationDatabase 236, Commons 330, HealthMonitoring 71, SiteRuntime 301, SiteEventLogging 50, CentralUI 50 — all green. README regenerated: 104 open (was 112).
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
| Last reviewed | 2026-05-28 |
|
||||
| Reviewer | claude-agent |
|
||||
| Commit reviewed | `1eb6e97` |
|
||||
| Open findings | 7 |
|
||||
| Open findings | 6 |
|
||||
|
||||
## Summary
|
||||
|
||||
@@ -975,9 +975,19 @@ counter and per-site stalled state.
|
||||
|--|--|
|
||||
| Severity | Low |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Open |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.HealthMonitoring/CentralHealthAggregator.cs:128-147` |
|
||||
|
||||
**Resolution (2026-05-28):** `MarkHeartbeat` now branches on
|
||||
`existing.IsOnline`: when transitioning offline-to-online it anchors
|
||||
`LastHeartbeatAt` to `max(receivedAt, _timeProvider.GetUtcNow())` so an
|
||||
out-of-order or older `receivedAt` cannot leave the recovered site one tick
|
||||
away from re-going-offline. The online path retains the prior
|
||||
`max(receivedAt, existing.LastHeartbeatAt)` semantics. Regression test
|
||||
`MarkHeartbeat_OfflineToOnline_StampsFreshLastHeartbeatAt` asserts both the
|
||||
fresh `LastHeartbeatAt` (within 5 s of "now") and that the next
|
||||
`CheckForOfflineSites` does not flap the site back to offline.
|
||||
|
||||
**Description**
|
||||
|
||||
The CAS path in `MarkHeartbeat` picks `newHeartbeat = max(receivedAt, existing.LastHeartbeatAt)`,
|
||||
|
||||
Reference in New Issue
Block a user