feat(hosts): driver diagnostics channel on /hosts, S7 negotiated PDU size first (#640)

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 16:57:38 -04:00
parent a8b07ae12d
commit c2bdb7d5de
23 changed files with 469 additions and 20 deletions
@@ -189,6 +189,17 @@ else
@* Own line — inline after the name the two identifiers ran together. *@
<div class="mono small text-muted">@d.DriverInstanceId</div>
}
@if (d.DiagnosticItems.Count > 0)
{
@* Driver-reported diagnostics (Gitea #640), e.g. S7 negotiated PDU size.
Renders nothing for a driver with none. *@
<div class="small text-muted" data-testid="driver-diagnostics">
@foreach (var kv in d.DiagnosticItems)
{
<div class="mono">@kv.Key: @kv.Value</div>
}
</div>
}
</td>
<td>@(d.DriverType ?? "—")</td>
<td><span class="chip @DriverChipClass(d.State)">@d.State</span></td>
@@ -52,6 +52,8 @@ public sealed record HostsDriverInstanceInfo(
/// 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>
/// <param name="Diagnostics">Driver-reported diagnostics (e.g. S7 negotiated PDU size); null or empty when
/// the driver has none to show (Gitea #640).</param>
/// <param name="Enabled">Whether the matching configured instance is authored enabled; <see langword="true"/>
/// when no instance matched. Fed to the row's expandable <c>DriverStatusPanel</c> (Gitea #546). An
/// unmatched row defaults to enabled on purpose: the row only exists because a live snapshot arrived,
@@ -62,8 +64,16 @@ public sealed record HostsDriverRow(
DateTime? RediscoveryNeededUtc = null, string? RediscoveryReason = null,
IReadOnlyList<HostConnectivityStatus>? HostStatuses = null,
SkippedTagReport? SkippedTags = null,
bool Enabled = true)
bool Enabled = true,
IReadOnlyDictionary<string, string>? Diagnostics = null)
{
/// <summary>Diagnostics as ordered key/value pairs for rendering; empty when there are none, in which
/// case the page renders nothing.</summary>
public IReadOnlyList<KeyValuePair<string, string>> DiagnosticItems { get; } =
(Diagnostics ?? new Dictionary<string, string>())
.OrderBy(k => k.Key, StringComparer.Ordinal)
.ToList();
/// <summary>Whether this driver is ignoring at least one authored tag — the condition the whole
/// column exists to make visible.</summary>
public bool HasSkippedTags => SkippedTags is { SkippedCount: > 0 };
@@ -177,7 +187,8 @@ public static class HostsDriverView
s.RediscoveryReason,
s.HostStatuses,
s.SkippedTags,
instance?.Enabled ?? true);
instance?.Enabled ?? true,
s.Diagnostics);
})
.OrderBy(d => d.Name ?? d.DriverInstanceId, StringComparer.OrdinalIgnoreCase)
.ThenBy(d => d.DriverInstanceId, StringComparer.OrdinalIgnoreCase)