diff --git a/canvas/src/components/MemoryInspectorPanel.tsx b/canvas/src/components/MemoryInspectorPanel.tsx
index ed54d8b5..4f49242b 100644
--- a/canvas/src/components/MemoryInspectorPanel.tsx
+++ b/canvas/src/components/MemoryInspectorPanel.tsx
@@ -427,11 +427,18 @@ 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-400 italic",
+ ].join(" ")}
title={`Similarity: ${(entry.similarity_score * 100).toFixed(1)}%`}
data-testid="similarity-badge"
>
- {Math.round(entry.similarity_score * 100)}%
+ {entry.similarity_score < 0.5 ? "~" : ""}{Math.round(entry.similarity_score * 100)}%
)}
diff --git a/canvas/src/components/__tests__/MemoryInspectorPanel.test.tsx b/canvas/src/components/__tests__/MemoryInspectorPanel.test.tsx
index 1cb709ac..31ef0925 100644
--- a/canvas/src/components/__tests__/MemoryInspectorPanel.test.tsx
+++ b/canvas/src/components/__tests__/MemoryInspectorPanel.test.tsx
@@ -475,6 +475,47 @@ 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-400 italic with tilde prefix 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-400");
+ expect(badge?.className).toContain("italic");
+ expect(badge?.className).not.toContain("text-blue-500");
+ expect(badge?.className).not.toContain("text-zinc-600");
+ expect(badge?.textContent).toBe("~31%");
+ });
+
it("clear button resets debouncedQuery immediately and re-fetches without ?q=", async () => {
vi.useFakeTimers();
// eslint-disable-next-line @typescript-eslint/no-explicit-any