From cdc51d4d303c157f615b06d931e69523b5626a79 Mon Sep 17 00:00:00 2001 From: Molecule AI Frontend Engineer Date: Fri, 17 Apr 2026 18:51:22 +0000 Subject: [PATCH] fix(canvas): color-code similarity badge by score tier (issue #783) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Badge was always text-zinc-500; apply blue-500 (>=0.8), zinc-400 (0.5–0.8), zinc-600 (<0.5) per spec. Add 3 vitest tests for each color tier (725 total). Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/MemoryInspectorPanel.tsx | 9 ++++- .../__tests__/MemoryInspectorPanel.test.tsx | 39 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/canvas/src/components/MemoryInspectorPanel.tsx b/canvas/src/components/MemoryInspectorPanel.tsx index ed54d8b5..83be9df4 100644 --- a/canvas/src/components/MemoryInspectorPanel.tsx +++ b/canvas/src/components/MemoryInspectorPanel.tsx @@ -427,7 +427,14 @@ function MemoryEntryRow({ {/* Similarity score badge — only rendered when backend provides a score */} {entry.similarity_score != null && ( = 0.8 + ? "text-blue-500" + : entry.similarity_score >= 0.5 + ? "text-zinc-400" + : "text-zinc-600", + ].join(" ")} title={`Similarity: ${(entry.similarity_score * 100).toFixed(1)}%`} data-testid="similarity-badge" > diff --git a/canvas/src/components/__tests__/MemoryInspectorPanel.test.tsx b/canvas/src/components/__tests__/MemoryInspectorPanel.test.tsx index 1cb709ac..e6a17fca 100644 --- a/canvas/src/components/__tests__/MemoryInspectorPanel.test.tsx +++ b/canvas/src/components/__tests__/MemoryInspectorPanel.test.tsx @@ -475,6 +475,45 @@ describe("MemoryInspectorPanel — semantic search", () => { ).toBeNull(); }); + it("colors similarity-badge blue-500 when score >= 0.8", async () => { + mockGet.mockResolvedValue([ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + { ...ENTRY_A, similarity_score: 0.92 }, + ] as any); + render(); + await waitFor(() => screen.getByText("task-queue")); + const badge = document.querySelector('[data-testid="similarity-badge"]'); + expect(badge?.className).toContain("text-blue-500"); + expect(badge?.className).not.toContain("text-zinc-400"); + expect(badge?.className).not.toContain("text-zinc-600"); + }); + + it("colors similarity-badge zinc-400 when score is between 0.5 and 0.8", async () => { + mockGet.mockResolvedValue([ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + { ...ENTRY_A, similarity_score: 0.65 }, + ] as any); + render(); + await waitFor(() => screen.getByText("task-queue")); + const badge = document.querySelector('[data-testid="similarity-badge"]'); + expect(badge?.className).toContain("text-zinc-400"); + expect(badge?.className).not.toContain("text-blue-500"); + expect(badge?.className).not.toContain("text-zinc-600"); + }); + + it("colors similarity-badge zinc-600 when score is below 0.5", async () => { + mockGet.mockResolvedValue([ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + { ...ENTRY_A, similarity_score: 0.31 }, + ] as any); + render(); + await waitFor(() => screen.getByText("task-queue")); + const badge = document.querySelector('[data-testid="similarity-badge"]'); + expect(badge?.className).toContain("text-zinc-600"); + expect(badge?.className).not.toContain("text-blue-500"); + expect(badge?.className).not.toContain("text-zinc-400"); + }); + it("clear button resets debouncedQuery immediately and re-fetches without ?q=", async () => { vi.useFakeTimers(); // eslint-disable-next-line @typescript-eslint/no-explicit-any