Commit Graph

8 Commits

Author SHA1 Message Date
benjamin.baker
f77a288bdc Show empty-state text on empty table panels
A table panel with no rows rendered its column headers over an empty body. On a live PC Details page that made Network Interfaces and Listening Ports look like cards that had failed to load, when the real answer was that the agent had not reported any yet. List panels already honoured panel.empty; table panels did not.

Also records the simulation-suite requirement uncovered when rolling containers: the pytest suite builds its schema from the models, so an unapplied migration is invisible to it while every query against the affected table 500s in the running image.
2026-09-05 07:22:58 -04:00
benjamin.baker
0c9bd1ed32 add mapped drives card
Mapped drives existed only as a comma-joined line in the user context card, which is fine for three drives and unreadable for a dozen. They now get their own list card in Monitors: one row per letter, remote path as meta, health as a badge. Reuses the statecolor/levels vocabulary the tracked-services cards already declare rather than new CSS. Only unhealthy drives are coloured. Green on every working drive makes the broken one just another badge in a row of badges, and the card exists to make the exception findable at a glance. Unhealthy rows sort first for the same reason - a user with a dozen mappings should not hunt for the broken one - and the sort is on health alone, so drive-letter order survives within each group and the list does not reshuffle between refreshes. The merge logic is untouched. _mapped_drive_rows now returns structured rows and the user-context summary line is built from them, so the card and the line cannot drift apart about a drive's status. The two silent-failure paths are mutation-tested: forcing every badge green failed 7 tests, and the first sort test passed a mutation that added a secondary key because every broken drive in it said the same word - it now uses statuses that would reorder under a text sort. Also corrects a stale warning claiming the merge is untested; it has been covered since Phase 1.
2026-09-05 07:12:21 -04:00
benjamin.baker
e00bb44d6b merge storage and disk health into one card with two sections
Volume capacity and physical drive health were two adjacent cards, and the operator reading a full disk is usually the operator reading a dying disk in the same minute. They are now one Storage card with two sections. Visual grouping only - the two tables share no key, storage being per volume and health per physical device, and one drive can back several volumes or none the operator sees. Nothing is reconciled across the sections; this is not the mapped-drive merge where two sources described the same drive and the worse status won. The tabs render type was the only sections-in-one-card mechanism and emitted label/value fields with no table path, so it now takes table sections too. That is the renderer every plugin uses, so both behaviour changes in it are mutation-tested. Two things only surfaced on contact: the empty-section filter had to grow a table branch, because a table section declares columns up front and dropping it when it has no rows takes its tab with it and reads as no disks rather than nothing reported; and full-width span was keyed off the declared render type, but a tabs panel holding a six-column table needs the same span and that is only knowable from fetched data. The diskhealth route stays. It no longer backs a panel, but it is a stable read for callers outside the renderer and removing it for a UI-only change would break them.
2026-09-05 07:05:30 -04:00
benjamin.baker
9ab1b4f702 Document Phase 2 system telemetry
Records why rebootreasons is not redundant with pendingreboot, why bootinfo carries two facts that must not be collapsed, and why defender is stored unsurfaced.

Also corrects the notes: pending file-rename was already being collected and OR-ed into pendingreboot, so the gap was that the stronger signal was flattened into the weaker one rather than missing. Records that the columns landed as 0015 because 0014 was taken by disk health earlier in this phase.
2026-09-05 06:41:28 -04:00
benjamin.baker
1c836e1c1b Scope the Storage and Disk health grouping
Records the agreed plan to combine the two cards into one with two collapsible sections, as VISUAL GROUPING ONLY. The two tables cannot share rows: Storage is per volume, Disk health is per physical device, and one drive can back several volumes or none the operator sees. Stating that explicitly so this is never mistaken for the Phase 1 mapped-drive merge, where two sources described the same drive and the worse status won.

Deferred to its own phase because the tabs render type emits label/value fields only and has no table path, so this means extending the renderer every plugin uses. Bundling that with the Phase 2 telemetry work would turn a UI regression and a telemetry regression into one commit to bisect.

Also scopes the not nested cards density rule to the header block it was written for, having checked it does not block this.
2026-09-05 06:32:11 -04:00
benjamin.baker
71847d940a Document the disk health field
Records why there are two sources and why they are not reconciled, so the next person does not simplify the ATA SMART path back in and silently blind the fleet on NVMe hardware.

Also notes that diskhealth is per physical device and is not the same list as disks, and that a null predictfailure is unknown rather than healthy.
2026-09-05 06:26:06 -04:00
benjamin.baker
5d7a426bb2 Cut time sync collection, pin Windows Update history
w32time is Stopped on provisioned endpoints, confirmed on more than one box, so w32tm returns 0x80070426 fleet-wide and there is no offset to read. It appears to be stopped by policy after provisioning. Collecting it would return null everywhere and give us an alerting signal that can never fire, which is worse than not having one: a permanently-null health check reads as no problem found.

Implemented first, then removed - collector, both parsers, the process helper, and the contract field. Kept one note in the notes file: parse the offset by label, not by first value ending in s, because w32tm prints Root Delay and Root Dispersion in the same format beforehand and a first-match parser reports network latency as clock skew. That bug was written and caught here.

Windows Update history is pinned rather than cut. The COM update searcher is slow, but the blocking concern is that some endpoints host COM server applications where driving it risks interfering with collections or the hosted application. Needs its own investigation. The Phase 4 card that depended on it is marked blocked so the two do not drift apart.
2026-09-05 06:00:40 -04:00
benjamin.baker
aa901c4111 Report mapped drives from both Windows sources, worse status wins
Windows exposes mapped drives twice and the two views disagree. Captured on one
box at one moment, same two mappings: Get-SmbMapping reported OK for both while
net use reported Disconnected and Reconnecting. Collecting only Get-SmbMapping -
the nicer, more structured one - would have reported a healthy Q: on a machine
whose Q: was down, which is the exact failure this telemetry exists to catch.

So collect both and keep them apart. The probe emits netuse and smbmapping as
separate keys and does not reconcile them; the disagreement is the signal and
normalising it in the agent would discard it before anyone could see it.

The server merges by drive letter and shows the WORSE of the two. A drive that
either source calls broken is broken for the operator, and a drive neither
source gave a status for renders as Unknown rather than blank - an unannotated
row reads as healthy, so a failed check would present as a working drive.
Drives seen by only one source are kept, not dropped: Get-SmbMapping is absent
on some builds and session types, and requiring agreement would silently hide
every mapped drive on those machines.

No active reachability testing. Windows already knows the status, so touching
each share would be wasted work and would reintroduce the hang risk the bounded
probe exists to avoid.

The probe stays unelevated in the operator's session. UAC token separation
gives an elevated context a different mapped-drive table, often empty, so
elevating this later would quietly empty the card.

Adds a commented-out remap_drive seam in the command catalog. Not implemented,
but placed so the next person finds the user-session and elevation constraints
before writing it rather than after.

The merge logic has no test coverage yet; the docstring names the three
behaviours that must not be broken.
2026-09-05 05:47:31 -04:00