From bb25a661b0e3b1b81c5b5964177f1ee16db02326 Mon Sep 17 00:00:00 2001 From: Leticia Date: Fri, 10 Apr 2026 16:40:51 +0200 Subject: [PATCH] fix(desktop): align snapshot refresh status semantics --- .agents/session-log.md | 13 ++++++ desktop/renderer/modules/tab-renderers.js | 14 +++--- desktop/tests/snapshot-status.test.mjs | 52 +++++++++++++++++++++++ 3 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 desktop/tests/snapshot-status.test.mjs diff --git a/.agents/session-log.md b/.agents/session-log.md index 3cc7dfc..07dee70 100644 --- a/.agents/session-log.md +++ b/.agents/session-log.md @@ -1,5 +1,18 @@ # Session Log - QuantLab +## 2026-04-10 — Snapshot Status Contract Alignment (Issue #361) +- **Session Focus**: Align the desktop snapshot-status renderer semantics with the shared `desktop/shared/models/snapshot.ts` contract. +- **Tasks Completed**: + - Updated `desktop/renderer/modules/tab-renderers.js` so snapshot refresh labels now branch on `ok`, `degraded`, `error`, and `idle` instead of stale `ready` / `loading` values. + - Kept healthy snapshots mapped to `Live`, degraded snapshots mapped to warning semantics, and explicit error snapshots mapped to negative/unavailable semantics. + - Added a small `node:test` regression file to lock the snapshot label/tone mapping against the current shared contract. +- **Key Decisions**: + - The shared snapshot contract remains the source of truth; the renderer adapts to it rather than expanding the contract back to old status names. + - `degraded` and `error` remain separate operator states so local fallback or partial data does not look identical to a hard runtime failure. +- **Validation Notes**: + - Validate with `npm run typecheck`, `node --check renderer/app.js`, `node --check renderer/modules/tab-renderers.js`, and `node --test tests/snapshot-status.test.mjs` from `desktop/`. + - Keep desktop smoke coverage in place to ensure the slice does not regress the current shell path. + ## 2026-04-10 — Real-Path Desktop Validation and Smoke Semantics (Issue #275) - **Session Focus**: Restore an honest distinction between fallback desktop smoke and real-path desktop validation. - **Tasks Completed**: diff --git a/desktop/renderer/modules/tab-renderers.js b/desktop/renderer/modules/tab-renderers.js index f7dc051..824ac6b 100644 --- a/desktop/renderer/modules/tab-renderers.js +++ b/desktop/renderer/modules/tab-renderers.js @@ -1792,25 +1792,25 @@ function renderOpsChipRow(label, counts) { `; } -function describeSnapshotRefresh(snapshotStatus) { - if (snapshotStatus?.status === "ready") { +export function describeSnapshotRefresh(snapshotStatus) { + if (snapshotStatus?.status === "ok") { return { label: snapshotStatus.refreshPaused ? "Paused" : "Live", tone: snapshotStatus.refreshPaused ? "tone-warning" : "tone-positive", lastSuccessAt: snapshotStatus.lastSuccessAt ? formatDateTime(snapshotStatus.lastSuccessAt) : "Never", }; } - if (snapshotStatus?.status === "error") { + if (snapshotStatus?.status === "degraded") { return { label: snapshotStatus.refreshPaused ? "Review required" : "Degraded", - tone: "tone-negative", + tone: "tone-warning", lastSuccessAt: snapshotStatus.lastSuccessAt ? formatDateTime(snapshotStatus.lastSuccessAt) : "Never", }; } - if (snapshotStatus?.status === "loading") { + if (snapshotStatus?.status === "error") { return { - label: "Refreshing", - tone: "tone-warning", + label: snapshotStatus.refreshPaused ? "Review required" : "Unavailable", + tone: "tone-negative", lastSuccessAt: snapshotStatus.lastSuccessAt ? formatDateTime(snapshotStatus.lastSuccessAt) : "Never", }; } diff --git a/desktop/tests/snapshot-status.test.mjs b/desktop/tests/snapshot-status.test.mjs new file mode 100644 index 0000000..c5dbf8b --- /dev/null +++ b/desktop/tests/snapshot-status.test.mjs @@ -0,0 +1,52 @@ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { describeSnapshotRefresh } from "../renderer/modules/tab-renderers.js"; + +const ISO_TIME = "2026-04-10T14:00:00.000Z"; + +test("ok snapshots render as live", () => { + const result = describeSnapshotRefresh({ + status: "ok", + refreshPaused: false, + lastSuccessAt: ISO_TIME, + }); + + assert.equal(result.label, "Live"); + assert.equal(result.tone, "tone-positive"); + assert.notEqual(result.lastSuccessAt, "Never"); +}); + +test("degraded snapshots stay warning-toned and do not fall back to waiting", () => { + const result = describeSnapshotRefresh({ + status: "degraded", + refreshPaused: false, + lastSuccessAt: ISO_TIME, + }); + + assert.equal(result.label, "Degraded"); + assert.equal(result.tone, "tone-warning"); +}); + +test("error snapshots remain negative and explicitly unavailable", () => { + const result = describeSnapshotRefresh({ + status: "error", + refreshPaused: false, + lastSuccessAt: ISO_TIME, + }); + + assert.equal(result.label, "Unavailable"); + assert.equal(result.tone, "tone-negative"); +}); + +test("idle snapshots remain waiting", () => { + const result = describeSnapshotRefresh({ + status: "idle", + refreshPaused: false, + lastSuccessAt: null, + }); + + assert.equal(result.label, "Waiting"); + assert.equal(result.tone, "tone-warning"); + assert.equal(result.lastSuccessAt, "Never"); +});