From c670f6b6666e6f91241e6ba2e20f77b768c3bc1e Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 01:21:25 +0100 Subject: [PATCH 1/2] Guide stored charts on Overview without losing incident peaks Replace the removed PBS drawer History route with the current Overview chart and range control, while preserving older installed tabs and safe no-replay diagnosis. Explain bucket averages, low-high bounds and local peaks without treating them as continuous coverage or incident timestamps. Keep both shipped guide mirrors and their rendered links checked. Contract-Neutral: Existing documentation and consuming guide tests only; no monitoring, storage, permissions, entitlement or navigation contract changes. Change-source: pulse-maintainer --- docs/METRICS_HISTORY.md | 22 ++++ docs/PBS.md | 22 ++-- .../public/docs/METRICS_HISTORY.md | 22 ++++ frontend-modern/public/docs/PBS.md | 22 ++-- .../docs/__tests__/drawerHistoryGuide.test.ts | 107 ++++++++++++++++++ 5 files changed, 181 insertions(+), 14 deletions(-) create mode 100644 frontend-modern/src/features/docs/__tests__/drawerHistoryGuide.test.ts diff --git a/docs/METRICS_HISTORY.md b/docs/METRICS_HISTORY.md index 1555f2b2fb..c64478b480 100644 --- a/docs/METRICS_HISTORY.md +++ b/docs/METRICS_HISTORY.md @@ -4,6 +4,19 @@ Pulse persists metrics history to disk so trend views and sparklines survive res ## Read a History panel +In current drawers, open the affected resource's **Overview** and use **History +range** beside its charts. Proxmox guests and nodes, Docker hosts and resource +drawers (including PBS) show stored charts there instead of a separate History +tab. If your installed version still has a **History** tab, use that tab; do not +upgrade or restart just to follow this guide. A resource without a supported +history target may have no chart. + +These charts are separate from **Alerts → History**, table sparklines and +current summary cards. A current card or a short trend preview does not +establish the observations in the selected stored range. For a PBS host, use +the [Backup Server chart](PBS.md#pbs-is-connected-but-history-stays-empty), +not its datastore or the VM that happens to host it. + Start with the existing chart, not a restart or a storage change. A current reading does not prove that it was stored, and a selected time range does not prove continuous coverage. **Window start** and **Window end** bound the @@ -20,12 +33,21 @@ than borrowing one from the current overview. | **current**, **last known** or **freshness unknown** with no stored history | A separately qualified fallback reading. Keep its label and explanation. | Not proof that the value was persisted or belongs to a past incident. | | **Single observation. No trend yet.** | One stored time in that panel. | Not a flat trend or sustained recovery. | | **Missing observations** | Some series lack readings at other stored times in that panel; lines stop across those gaps. | Not the cause or duration of a monitoring outage. Missing is not measured zero. | +| **Shaded low–high band** | The recorded minimum and maximum within an aggregated bucket, when supplied; the line shows its average. | Not continuous coverage, every original sample, or the duration of a spike. | +| **peak** while inspecting | That metric's maximum in the inspected bucket, when the panel shows it beside the average. | Not necessarily the highest value in the whole selected range or the value at an alert's exact time. | For example, CPU **22% at 12:02** and memory **95% at 12:01** are not one observation. At **Latest stored · 12:02**, memory is a dash if there is no memory point at 12:02; the earlier 95% remains inspectable. Network and disk I/O panels have their own times, not a shared snapshot of the guest. +An aggregated CPU bucket can show **22% average, 10% to 95%**. The line at 22% +does not rule out the recorded 95% peak, and the band does not say how long +that peak lasted. No visible band may mean a single reading, equal bounds or +unavailable bounds; it does not prove that usage stayed constant. Older panels +may not show these bounds. Keep that limitation rather than inferring a peak +from the line alone. + 1. Keep the same resource, metric and range when comparing existing readings. **Inspect history**, when offered, steps through stored times: focus the slider and use the arrow keys, **Home** or **End**, or move it by touch. diff --git a/docs/PBS.md b/docs/PBS.md index a426c45575..0539fc2e2e 100644 --- a/docs/PBS.md +++ b/docs/PBS.md @@ -429,12 +429,19 @@ the pause. Monitoring and alerts are unavailable while Pulse is stopped. ### PBS is connected but History stays empty -Open **Proxmox → Backups → Backup Server → History**, not a datastore or the -PBS virtual machine's row in **Overview**. Record which route fails. A working -VM chart can use a different metrics target from the PBS host chart; it does -not establish that the PBS chart can read the same series. Current CPU and -memory values, a green connection badge, and an **API+Agent** label also do not -prove that stored host history is available. +Open **Proxmox → Backups**, choose the **Backup Server** row, then use the +drawer's **Overview** charts and **History range** selector. If your installed +version still has a separate **History** tab, use that tab instead; no upgrade +or restart is needed just to find the chart. This is not a datastore chart, +**Alerts → History**, or the PBS virtual machine's row in Proxmox **Overview**. +Record which route fails. A working VM chart can use a different metrics target +from the PBS host chart; it does not establish that the PBS chart can read the +same series. Current CPU and memory values, a green connection badge, and an +**API+Agent** label also do not prove that stored host history is available. + +Use the chart's selected stored range, not a current summary card or table +sparkline. For observation times, missing samples and aggregated low–high bands, +see [reading a History panel](METRICS_HISTORY.md#read-a-history-panel). Start with one affected PBS and a recent, unlocked time range: @@ -447,7 +454,8 @@ Start with one affected PBS and a recent, unlocked time range: 2. If the target is already known, inspect the chart's request instead of collecting the identities again. In your signed-in browser, open developer tools → **Network**, filter for `metrics-store/history`, then open the - affected **History** tab. Do not refresh or restart the server. Inspect one + affected drawer's **Overview** charts (or **History** tab on older versions). + Do not refresh or restart the server. Inspect one completed request for the drawer's `resourceType`, `resourceId` and `range`. The drawer normally fetches all chart metrics together: a request **without `metric`** is expected, so do not wait for a separate `metric=cpu` request. diff --git a/frontend-modern/public/docs/METRICS_HISTORY.md b/frontend-modern/public/docs/METRICS_HISTORY.md index 1555f2b2fb..c64478b480 100644 --- a/frontend-modern/public/docs/METRICS_HISTORY.md +++ b/frontend-modern/public/docs/METRICS_HISTORY.md @@ -4,6 +4,19 @@ Pulse persists metrics history to disk so trend views and sparklines survive res ## Read a History panel +In current drawers, open the affected resource's **Overview** and use **History +range** beside its charts. Proxmox guests and nodes, Docker hosts and resource +drawers (including PBS) show stored charts there instead of a separate History +tab. If your installed version still has a **History** tab, use that tab; do not +upgrade or restart just to follow this guide. A resource without a supported +history target may have no chart. + +These charts are separate from **Alerts → History**, table sparklines and +current summary cards. A current card or a short trend preview does not +establish the observations in the selected stored range. For a PBS host, use +the [Backup Server chart](PBS.md#pbs-is-connected-but-history-stays-empty), +not its datastore or the VM that happens to host it. + Start with the existing chart, not a restart or a storage change. A current reading does not prove that it was stored, and a selected time range does not prove continuous coverage. **Window start** and **Window end** bound the @@ -20,12 +33,21 @@ than borrowing one from the current overview. | **current**, **last known** or **freshness unknown** with no stored history | A separately qualified fallback reading. Keep its label and explanation. | Not proof that the value was persisted or belongs to a past incident. | | **Single observation. No trend yet.** | One stored time in that panel. | Not a flat trend or sustained recovery. | | **Missing observations** | Some series lack readings at other stored times in that panel; lines stop across those gaps. | Not the cause or duration of a monitoring outage. Missing is not measured zero. | +| **Shaded low–high band** | The recorded minimum and maximum within an aggregated bucket, when supplied; the line shows its average. | Not continuous coverage, every original sample, or the duration of a spike. | +| **peak** while inspecting | That metric's maximum in the inspected bucket, when the panel shows it beside the average. | Not necessarily the highest value in the whole selected range or the value at an alert's exact time. | For example, CPU **22% at 12:02** and memory **95% at 12:01** are not one observation. At **Latest stored · 12:02**, memory is a dash if there is no memory point at 12:02; the earlier 95% remains inspectable. Network and disk I/O panels have their own times, not a shared snapshot of the guest. +An aggregated CPU bucket can show **22% average, 10% to 95%**. The line at 22% +does not rule out the recorded 95% peak, and the band does not say how long +that peak lasted. No visible band may mean a single reading, equal bounds or +unavailable bounds; it does not prove that usage stayed constant. Older panels +may not show these bounds. Keep that limitation rather than inferring a peak +from the line alone. + 1. Keep the same resource, metric and range when comparing existing readings. **Inspect history**, when offered, steps through stored times: focus the slider and use the arrow keys, **Home** or **End**, or move it by touch. diff --git a/frontend-modern/public/docs/PBS.md b/frontend-modern/public/docs/PBS.md index a426c45575..0539fc2e2e 100644 --- a/frontend-modern/public/docs/PBS.md +++ b/frontend-modern/public/docs/PBS.md @@ -429,12 +429,19 @@ the pause. Monitoring and alerts are unavailable while Pulse is stopped. ### PBS is connected but History stays empty -Open **Proxmox → Backups → Backup Server → History**, not a datastore or the -PBS virtual machine's row in **Overview**. Record which route fails. A working -VM chart can use a different metrics target from the PBS host chart; it does -not establish that the PBS chart can read the same series. Current CPU and -memory values, a green connection badge, and an **API+Agent** label also do not -prove that stored host history is available. +Open **Proxmox → Backups**, choose the **Backup Server** row, then use the +drawer's **Overview** charts and **History range** selector. If your installed +version still has a separate **History** tab, use that tab instead; no upgrade +or restart is needed just to find the chart. This is not a datastore chart, +**Alerts → History**, or the PBS virtual machine's row in Proxmox **Overview**. +Record which route fails. A working VM chart can use a different metrics target +from the PBS host chart; it does not establish that the PBS chart can read the +same series. Current CPU and memory values, a green connection badge, and an +**API+Agent** label also do not prove that stored host history is available. + +Use the chart's selected stored range, not a current summary card or table +sparkline. For observation times, missing samples and aggregated low–high bands, +see [reading a History panel](METRICS_HISTORY.md#read-a-history-panel). Start with one affected PBS and a recent, unlocked time range: @@ -447,7 +454,8 @@ Start with one affected PBS and a recent, unlocked time range: 2. If the target is already known, inspect the chart's request instead of collecting the identities again. In your signed-in browser, open developer tools → **Network**, filter for `metrics-store/history`, then open the - affected **History** tab. Do not refresh or restart the server. Inspect one + affected drawer's **Overview** charts (or **History** tab on older versions). + Do not refresh or restart the server. Inspect one completed request for the drawer's `resourceType`, `resourceId` and `range`. The drawer normally fetches all chart metrics together: a request **without `metric`** is expected, so do not wait for a separate `metric=cpu` request. diff --git a/frontend-modern/src/features/docs/__tests__/drawerHistoryGuide.test.ts b/frontend-modern/src/features/docs/__tests__/drawerHistoryGuide.test.ts new file mode 100644 index 0000000000..019a029df4 --- /dev/null +++ b/frontend-modern/src/features/docs/__tests__/drawerHistoryGuide.test.ts @@ -0,0 +1,107 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describe, expect, it } from 'vitest'; +import { createGuideFixture } from './guideFixture'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../..'); +const read = (file: string) => readFileSync(path.join(root, file), 'utf8'); +const shipped = (name: string) => read(`frontend-modern/public/docs/${name}.md`); +const render = createGuideFixture(shipped); +const prose = (element: Element) => (element.textContent ?? '').replace(/\s+/g, ' ').trim(); + +function section(name: string, fragment: string) { + const heading = render(name).querySelector(`#${fragment}`); + expect(heading).not.toBeNull(); + const element = document.createElement('section'); + for (let next = heading!.nextElementSibling; next; next = next.nextElementSibling) { + if (next.matches('h1, h2, h3')) break; + element.appendChild(next.cloneNode(true)); + } + return element; +} + +const pbs = () => section('PBS', 'pbs-is-connected-but-history-stays-empty'); +const history = () => section('METRICS_HISTORY', 'read-a-history-panel'); + +describe('stored-chart navigation and interpretation help', () => { + it.each(['PBS', 'METRICS_HISTORY'])('ships the exact canonical %s guide', (name) => { + expect(shipped(name)).toBe(read(`docs/${name}.md`)); + }); + + it('routes PBS to its host Overview, not its datastore, VM or alert history', () => { + const text = prose(pbs()); + expect(text).toContain('Proxmox → Backups, choose the Backup Server row'); + expect(text).toContain("drawer's Overview charts and History range selector"); + expect(text).toContain('not a datastore chart, Alerts → History'); + expect(text).toContain("PBS virtual machine's row in Proxmox Overview"); + expect(text).not.toContain('Backup Server → History'); + expect(text).toContain('resourceType, resourceId and range'); + expect(text).toContain('a request without metric is expected'); + expect(text).toContain('metrics.cpu'); + expect(text).toContain('points array for that single metric'); + }); + + it('supports older installed tabs without making an upgrade part of diagnosis', () => { + expect(prose(pbs())).toContain('If your installed version still has a separate History tab'); + expect(prose(pbs())).toContain('no upgrade or restart is needed just to find the chart'); + expect(prose(history())).toContain('If your installed version still has a History tab'); + expect(prose(history())).toContain('do not upgrade or restart just to follow this guide'); + expect(prose(history())).toContain( + 'A resource without a supported history target may have no chart', + ); + }); + + it('binds the new instructions to the current consuming drawer and control', () => { + const overview = read( + 'frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx', + ); + expect(overview).toContain(' { + const text = prose(history()); + expect(text).toContain('22% average, 10% to 95%'); + expect(text).toContain('does not rule out the recorded 95% peak'); + expect(text).toContain('does not say how long that peak lasted'); + expect(text).toContain('does not prove that usage stayed constant'); + const rows = [...history().querySelectorAll('tbody tr')]; + const band = rows.find((row) => prose(row).startsWith('Shaded low–high band'))!; + const peak = rows.find((row) => prose(row).startsWith('peak while inspecting'))!; + expect(prose(band)).toContain('Not continuous coverage, every original sample'); + expect(prose(peak)).toContain('Not necessarily the highest value'); + expect(prose(peak)).toContain("alert's exact time"); + expect(text).toContain('Missing is not measured zero'); + expect(text).toContain('Window start and Window end bound the requested interval'); + expect(text).toContain('not the first and last successful observations'); + }); + + it('keeps both existing bookmarks and the new cross-guide links usable', () => { + for (const [element, name, fragment] of [ + [pbs(), 'METRICS_HISTORY', 'read-a-history-panel'], + [history(), 'PBS', 'pbs-is-connected-but-history-stays-empty'], + ] as const) { + expect(element.querySelector(`a[href="/docs/${name}#${fragment}"]`)).not.toBeNull(); + expect(render(name).querySelector(`#${fragment}`)).not.toBeNull(); + } + }); + + it('retains the safe no-replay and private-evidence investigation path', () => { + expect(prose(pbs())).toContain('Do not edit or replay the request'); + expect(prose(pbs())).toContain('Do not refresh or restart the server'); + expect(prose(pbs())).toContain('Do not share a HAR export'); + expect(prose(pbs())).toContain('Do not delete and re-add connections'); + expect(prose(history())).toContain('do not run Diagnostics or guest-agent probes'); + expect(prose(history())).toContain('not chart inspection'); + expect( + history().querySelector('a[href="/docs/VM_DISK_MONITORING#backup-safety"]'), + ).not.toBeNull(); + }); +}); From 647664b637958d6c44b361cd079bb8c237463eca Mon Sep 17 00:00:00 2001 From: "pulse-triage[bot]" <249995291+pulse-triage[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 01:26:38 +0100 Subject: [PATCH 2/2] Record consuming proof for stored-chart navigation help Bind actual Docs producer responses, desktop keyboard and phone touch links, and inspected navigation/bucket-bound pixels to the unchanged guide source. Contract-Neutral: Browser evidence metadata only; no product or subsystem contract change. Change-source: pulse-maintainer --- .../2026-10-14-history-guide.json | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 frontend-modern/browser-verification/2026-10-14-history-guide.json diff --git a/frontend-modern/browser-verification/2026-10-14-history-guide.json b/frontend-modern/browser-verification/2026-10-14-history-guide.json new file mode 100644 index 0000000000..004f2d69c2 --- /dev/null +++ b/frontend-modern/browser-verification/2026-10-14-history-guide.json @@ -0,0 +1,68 @@ +{ + "version": 1, + "result": "passed", + "base_sha": "c670f6b6666e6f91241e6ba2e20f77b768c3bc1e", + "changed_paths": [ + "frontend-modern/public/docs/PBS.md", + "frontend-modern/public/docs/METRICS_HISTORY.md" + ], + "content_sha256": { + "frontend-modern/public/docs/PBS.md": "a4e7aa00bf32f8269a20f8f1c3609214d8dadb1da79a3ed0e7b4b980789741cf", + "frontend-modern/public/docs/METRICS_HISTORY.md": "24d00753afb3bc8a15f079958d6fcb964cecfbfcf14f2f9e42e8916be5fd8250" + }, + "routes": [ + "/docs/PBS#pbs-is-connected-but-history-stays-empty", + "/docs/METRICS_HISTORY#read-a-history-panel" + ], + "states": [ + "Actual canonical/shipped Markdown through production Docs and sanitised renderer in a Vite source preview; only local security/API GET fixtures.", + "PBS host Overview chart/range versus old installed History tab, VM/datastore and Alerts History.", + "Stored observation/window semantics and aggregated averages/minimum/maximum/local peaks without continuous-coverage or incident-time claims." + ], + "interactions": [ + "Desktop keyboard Enter and390px WebKit touch follow both cross-guide links to existing bookmarks.", + "Scroll to bounds/peak rows and worked example in the real article. Actual served Markdown hashes match their committed producers." + ], + "viewports": [ + { + "width": 1440, + "height": 1000 + }, + { + "width": 390, + "height": 844 + } + ], + "verified_at": "2026-10-14T00:23:19.647Z", + "runtime": { + "playwright": "1.56.1", + "chromium": "141.0.7390.37", + "webkit": "26.0" + }, + "pixel_review": { + "tool": "native view_image", + "opened": [ + "chromium-pbs-navigation.jpg", + "chromium-history-navigation.jpg", + "chromium-bucket-bounds.jpg", + "chromium-peak-example.jpg", + "webkit-pbs-navigation.jpg", + "webkit-history-navigation.jpg", + "webkit-bucket-bounds.jpg", + "webkit-peak-example.jpg" + ], + "observations": [ + "Desktop: revised PBS host route, old-tab compatibility, Overview/range guidance and both cross-guide links are readable; the complete bounds/peak table fits the page.", + "390 px WebKit: new navigation and no-upgrade/no-restart caveat wrap within the page. All three columns of the bounds/peak rows remain readable without page overflow, and the22% average/95% peak example and its duration/constant-usage limits are visible.", + "Desktop bucket-bounds capture is byte-identical to the already presented history-navigation image; that same presented pixel content covers both cases.", + "Keyboard Enter and phone touch followed both preserved bookmarks in both directions. No API, guest, backup, credential or installed monitoring operation was performed." + ], + "remaining": null + }, + "browser_cleanup": { + "closed": true, + "preview_exit": 143, + "preview_signal": null + }, + "evidence": "PI OUTCOME.md/RECEIPTS.md/BROWSER.json and eight retained native-inspected captures bind ten consuming cases to c670f6b6. Does not establish native guest/PBS recovery, installed acceptance, protected delivery or release availability." +}