fix(hosts): a driver that never built a tag table reports NO ANSWER, not zero skips

Found on the docker-dev live gate, not in tests. Two drivers that faulted
during initialise (rtu-gate, opcua1) each rendered "0 tags" on /hosts against
two authored tags apiece, because a ledger that had never committed returned
SkippedTagReport.Empty.

A zero report is a positive claim -- "this driver skipped nothing" -- and
making it on behalf of a driver that never got as far as looking is exactly
the quiet inaccuracy #541 exists to remove. GetSkippedTags() and
SkippedTagLedger.Snapshot() now return null until the first committed build,
so the column renders the same em-dash it already used for a driver that
cannot report at all. Both are 'no answer'; neither is 'nothing skipped'.

Knock-on: a FOCAS driver whose only init threw now reports null rather than a
zero report, which is strictly more honest than the assertion the test
originally made.
This commit is contained in:
Joseph Doherty
2026-08-05 20:16:31 -04:00
parent 39db75083d
commit dd900f970a
19 changed files with 94 additions and 51 deletions
@@ -234,8 +234,11 @@ else
Healthy, Errors/5 min stays 0, Last error stays empty, and Last
read keeps advancing off the tags that DID map. On the Makino in
#540 that read as a perfectly healthy driver ignoring 20 of its 22
tags. "—" means the driver cannot report skips, which is distinct
from reporting none. *@
tags. "—" means NO ANSWER — either the driver cannot report skips,
or it faulted before building a tag table — which is distinct from
the positive claim "this driver skipped nothing". A pre-fix build
rendered "0 tags" for two faulted drivers on the docker-dev rig
that had two authored tags apiece. *@
@if (d.SkippedTags is null)
{
<span class="text-muted">—</span>
@@ -44,9 +44,10 @@ public sealed record HostsDriverInstanceInfo(string DriverInstanceId, string Clu
/// <param name="HostStatuses">Per-host connectivity for a multi-device driver, ordered by host name; null
/// when the driver reports no per-host detail. Lets one unreachable device show even while the driver
/// row itself is Healthy.</param>
/// <param name="SkippedTags">Authored tags the driver could not build into its poll table; null when the
/// driver cannot report them. Lets "ignoring 20 of 22 tags" show even while every other column on the
/// row — state, last read, error count, last error — reads perfectly healthy (Gitea #541).</param>
/// <param name="SkippedTags">Authored tags the driver could not build into its poll table; null when there
/// is no answer — the driver cannot report skips, or it faulted before building a tag table. Lets
/// "ignoring 20 of 22 tags" show even while every other column on the row — state, last read, error
/// count, last error — reads perfectly healthy (Gitea #541).</param>
public sealed record HostsDriverRow(
string DriverInstanceId, string? Name, string? DriverType, string State,
DateTime? LastSuccessfulReadUtc, string? LastError, int ErrorCount5Min, DateTime PublishedUtc,