diff --git a/docs/release-control/v6/internal/subsystems/performance-and-scalability.md b/docs/release-control/v6/internal/subsystems/performance-and-scalability.md index 157acbbb5..0037bff18 100644 --- a/docs/release-control/v6/internal/subsystems/performance-and-scalability.md +++ b/docs/release-control/v6/internal/subsystems/performance-and-scalability.md @@ -703,7 +703,9 @@ change may globally weaken the Task 03 lifecycle-state idempotency invariant. accumulating, but it must never be expanded into synthetic timestamps or a flat line. Fewer than two stored points remains `Collecting history` and only metrics-store samples may contribute chart geometry, bounds, or hover - inspection. + inspection. Current-value legends must preserve the same availability + semantics as workload rows: the poller's negative unknown-disk sentinel is + unavailable and renders `-`, never a fabricated negative percentage. History cards must let the plot area stretch to the card height instead of pinning the SVG wrapper to a fixed short height, so guest and node drawer history cards do not leave unused card space when headers have different diff --git a/frontend-modern/browser-verification.json b/frontend-modern/browser-verification.json index 82e026017..26615cc2e 100644 --- a/frontend-modern/browser-verification.json +++ b/frontend-modern/browser-verification.json @@ -1,30 +1,35 @@ { "version": 1, - "base_sha": "caf7f80867871f0a601d9a572cbab309f8d4b41f", - "verified_at": "2026-08-25T18:42:00Z", + "base_sha": "3678d583bf43840d0086e4ba70c81aec77dadd01", + "verified_at": "2026-08-25T19:06:05Z", "result": "passed", "changed_paths": [ - "frontend-modern/src/components/AI/AICostDashboard.tsx", - "frontend-modern/src/utils/aiCostPresentation.ts" + "frontend-modern/src/components/Workloads/guestDrawerModel.ts" ], "content_sha256": { - "frontend-modern/src/components/AI/AICostDashboard.tsx": "eb9291049d9c415bfc24868cf45da5f9d862bb24f98100bc0fb10e2188554100", - "frontend-modern/src/utils/aiCostPresentation.ts": "816376697dc3eefa1b3d3a198ab29f80ae9148ddbffaf3dc1ab18fb22bc46041" + "frontend-modern/src/components/Workloads/guestDrawerModel.ts": "5aaccadfaa746f391431c5138e7a1c051b643e264e57fb8e2f58f121cffb0de9" }, - "routes": ["/settings/pulse-intelligence/provider"], + "routes": [ + "/proxmox/overview", + "/docker/overview", + "/kubernetes/overview", + "/truenas/apps" + ], "viewports": [ - { "width": 1440, "height": 900 }, + { "width": 1280, "height": 800 }, { "width": 390, "height": 844 } ], "states": [ - "loaded provider usage range with no provider/model rows", - "phone projection retaining Provider, Model, and Est. USD", - "desktop projection restoring Input, Output, and Total" + "stopped Proxmox guest History drawer using the negative unknown-disk sentinel", + "running Docker container History drawer with populated utilization data", + "degraded Kubernetes pod History drawer with populated utilization and network data", + "TrueNAS app Overview drawer with long container and identity values" ], "interactions": [ - "navigated to Provider & Models and scrolled the settings surface to Provider Usage & Spend", - "verified the empty-state row is fully readable at 390px after correcting fixed-table text clipping", - "measured zero table-shell and page overflow at 390px and 1440px", - "confirmed all six desktop headers return at 1440px" + "opened the stopped dev-portal Proxmox guest and switched from Overview to History at 390px", + "verified the unavailable disk fallback renders as a dash instead of a negative percentage at 390px and 1280px", + "opened Docker and Kubernetes History tabs to confirm valid current metrics and chart geometry remain intact", + "opened a TrueNAS app drawer and inspected long-value truncation, stacking, scrolling, and tab placement", + "restored the browser viewport after responsive verification" ] } diff --git a/frontend-modern/src/components/Workloads/GuestDrawer.test.tsx b/frontend-modern/src/components/Workloads/GuestDrawer.test.tsx index acc35dab5..4fea39bfc 100644 --- a/frontend-modern/src/components/Workloads/GuestDrawer.test.tsx +++ b/frontend-modern/src/components/Workloads/GuestDrawer.test.tsx @@ -502,6 +502,33 @@ describe('GuestDrawer', () => { expect(utilizationChart.querySelector('path')).toBeNull(); }); + it('renders unavailable current disk usage as a dash', async () => { + chartsApiMocks.getMetricsHistory.mockResolvedValue({ + resourceType: 'vm', + resourceId: 'inst1:node1:100', + range: '24h', + start: 0, + end: 0, + metrics: {}, + source: 'store', + }); + render(() => ( + + )); + + await fireEvent.click(screen.getByText('History')); + await waitFor(() => expect(chartsApiMocks.getMetricsHistory).toHaveBeenCalled()); + + const utilizationChart = screen.getAllByTestId('guest-history-group-chart')[0]; + expect(utilizationChart).toHaveTextContent('Disk-'); + expect(utilizationChart).not.toHaveTextContent('Disk-100.0%'); + }); + it('updates grouped metric header values on History chart hover', async () => { render(() => ); diff --git a/frontend-modern/src/components/Workloads/__tests__/guestDrawerModel.branchcov2.test.ts b/frontend-modern/src/components/Workloads/__tests__/guestDrawerModel.branchcov2.test.ts index 66eec4cbd..f4e5d9bf9 100644 --- a/frontend-modern/src/components/Workloads/__tests__/guestDrawerModel.branchcov2.test.ts +++ b/frontend-modern/src/components/Workloads/__tests__/guestDrawerModel.branchcov2.test.ts @@ -142,6 +142,15 @@ describe('guestDrawerModel (branch coverage)', () => { expect(result.memory).toBeUndefined(); }); + it('does not render the negative unknown-disk sentinel as a current history value', () => { + const result = getGuestDrawerCurrentMetrics( + makeGuest({ + disk: { total: 100, used: 0, free: 100, usage: -1 }, + }), + ); + expect(result.disk).toBeUndefined(); + }); + it('drops a non-finite network value via the finite() guard', () => { const result = getGuestDrawerCurrentMetrics( makeGuest({ networkIn: Number.POSITIVE_INFINITY }), diff --git a/frontend-modern/src/components/Workloads/guestDrawerModel.ts b/frontend-modern/src/components/Workloads/guestDrawerModel.ts index 7f9aa8595..766c563e3 100644 --- a/frontend-modern/src/components/Workloads/guestDrawerModel.ts +++ b/frontend-modern/src/components/Workloads/guestDrawerModel.ts @@ -73,13 +73,19 @@ export const getGuestDrawerCurrentMetrics = (guest: Guest): Record= 0 + ? reportedDiskUsage + : undefined; const finite = (value: number | undefined): number | undefined => typeof value === 'number' && Number.isFinite(value) ? value : undefined; return { cpu: finite(cpuPercent), memory: finite(memUsage), - disk: finite(diskUsage), + disk: diskUsage, netin: available('networkIO') ? finite(guest.networkIn) : undefined, netout: available('networkIO') ? finite(guest.networkOut) : undefined, diskread: available('diskIO') ? finite(guest.diskRead) : undefined,