Repository navigation
Job History tab speaks display names - #2128
Conversation
Both the Server filter dropdown and the Server column showed the raw collected server name while every other tab shows the operator's alias. Both readers (job history and the Agent status header) now resolve through the servers registry — COALESCE(display_name, raw name), the FinOps precedent — so the filter combo, the column, the per-column filter popup, and the CSV export all speak the same names as the rest of the viewer, and the Agent roll-up sorts by them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review: Job History tab speaks display namesThe Darling-side fix itself looks correct:
Lite/Darling parity gap: this fix isn't mirrored in Lite.
Net: today, Job History is the one tab in Lite that still shows raw collected names instead of the operator's alias — this PR narrows that gap to Lite-only rather than closing it everywhere. Worth a follow-up issue if it's not folded into this PR. No other correctness, security, or performance issues found in the diff. |
…y half Lite can't take Darling's SQL-side join: its display-name concept lives at the config layer (ServerConnection), not in DuckDB — the stored servers.display_name column is unpopulated by design. So the shell passes a server_id → alias snapshot into the tab, Overview-style (the same GetDeterministicHashCode(GetServerNameForStorage(...)) identity the Overview refresh already uses), and rows swap in the alias on every refresh. A server no longer in config keeps its raw collected name — job history is a durable record and rows can outlive their registration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Review taken — the Lite parity gap is real and is now closed in 4468d50, your way rather than a copy-paste: Lite's display-name concept lives at the config layer (the stored Also updated the PR title's scope: this now closes the gap in BOTH SKUs, not just Darling. (The earlier |
| /* #2126: rows carry the raw collected server name; swap in the operator's alias where the | ||
| config layer knows one, so the Server column and filter speak the same names as every | ||
| other tab. A server no longer in config keeps its raw name (the durable-record case). */ | ||
| if (_displayNames?.Invoke() is { Count: > 0 } names) | ||
| { | ||
| foreach (var row in all) | ||
| { | ||
| if (names.TryGetValue(row.ServerId, out var alias) && !string.IsNullOrEmpty(alias)) | ||
| { | ||
| row.ServerName = alias; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Once this swap makes row.ServerName a live-editable alias, PopulateServerFilter a few lines below (same file) goes stale in a way it never could before: its rebuild-skip check only compares server IDs:
var newIds = servers.Select(s => s.ServerId.ToString()).ToList();
if (newIds.SequenceEqual(existingIds)) return;not the display text. Renaming a server's alias in Manage Servers doesn't touch the id set (and RefreshServerList() never calls JobHistoryContent.RefreshJobs() either), so on the next tick where this tab does refresh (the 30s auto-refresh or a tab reselect) the grid rows pick up the new alias here, but the Server-filter ComboBoxItem.Content built earlier is never regenerated — the dropdown keeps showing the old alias indefinitely (until a server is actually added/removed) while the grid shows the new one. It still filters correctly since Tag is the id, but the label is wrong.
Before this PR ServerName was the raw collected server name, effectively invariant for a session, so that early-return was harmless. Now that it's meant to track an operator-editable alias (the point of #2126), the skip-check needs to include the name too, e.g. compare (id, name) pairs instead of just ids.
Same reused-helper shape exists in Darling's JobHistoryTab.xaml.cs::PopulateServerFilter (not touched by this diff, but it now consumes the same COALESCE(reg.display_name, ...)-resolved name from ViewerDataService.GetJobHistoryAsync, so it has the identical staleness gap there too).
|
Reviewed the diff (CHANGELOG.md, Correctness
Darling SQL (
Lite/Darling parity
No missing-index or other DMV-folklore suggestions, and no security issues spotted (no new user input reaches SQL text directly; everything stays parameterized). |
…e-2126 # Conflicts: # CHANGELOG.md
ReviewWent through the full diff ( Darling (SQL)
Lite (config-layer)
Parity
No correctness, security, or SQL-injection concerns (all filters are parameterized), and no missing-index recommendations to make. |
…ixes erikdarlingdata#2818) Both live retention tests passed logger: null to EnsureRetentionPoliciesAsync, so the per-relation catch discarded all seventeen warning messages and a nightly's one 'expected 17, got 0' was untriageable by construction. Pass the CapturingTestLogger erikdarlingdata#2128 added for exactly this shape (erikdarlingdata#1564), fold Joined into every count assertion, and capture the EnsureContinuousAggregatesAsync pass too, since a swallowed CAGG failure is a plausible upstream cause of the same symptom. Proven both ways against live TimescaleDB 2.29: the injected all-relations-throw shape now names the actual Postgres error per relation (TS001: not a hypertable), and the healthy path applies 17/17, idempotent, with zero warnings captured. The shared logger's empty-case placeholder stops claiming to be about purges; nothing asserts on that literal. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MX6HyjsuDCs15qGB2rh4Gy
Closes #2126.
The gap
ghauan runs the fleet by aliases and the Job History tab was the one place that refused to speak them: both the Server filter dropdown and the Server column carried the raw collected
server_name, while every other tab resolves the operator's display alias.The fix
Darling — both Job History readers now resolve names through the
serversregistry withCOALESCE(reg.display_name, <raw name>)— the exact pattern the FinOps inventory reader already uses:GetJobHistoryAsync— the base CTE joinsserversand emits the alias asserver_name, so the Server column, the Server filter combo (which keys onserver_id, so filtering is unchanged), the per-column filter popup, and the CSV export all show display names with zero tab-side changes.GetAgentStatusAsync— same join; the fleet Agent roll-up now also sorts by display name.display_nameis never empty on the write path (DarlingConfig.DisplayNamefalls back to the host), and theCOALESCEcovers pre-existing rows written before the column existed.Lite (robot review catch — same gap, different mechanism): Lite's display-name concept lives at the config layer (
ServerConnection), not in DuckDB — the storedservers.display_namecolumn is unpopulated by design. So the shell passes aserver_id → aliassnapshot into the tab Overview-style (the sameGetDeterministicHashCode(GetServerNameForStorage(...))identity the Overview refresh already uses), and rows swap in the alias on every refresh. A server no longer in config keeps its raw collected name — job history is a durable record and rows can outlive their registration.Tests
No SQL-shape pins exist for these readers (checked — only schema-probe sentinels reference
job_history), and the Darling change is a projection swap with the join precedent already live in two other readers. The Lite change is display-only row post-processing behind an optionalInitializeparameter, defaulting to off.🤖 Generated with Claude Code