fix(canvas): color-code similarity badge by score tier (issue #783)

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 <noreply@anthropic.com>
This commit is contained in:
Molecule AI Frontend Engineer 2026-04-17 18:51:22 +00:00
parent 6c6e703ec9
commit cdc51d4d30
2 changed files with 47 additions and 1 deletions

View File

@ -427,7 +427,14 @@ function MemoryEntryRow({
{/* Similarity score badge — only rendered when backend provides a score */}
{entry.similarity_score != null && (
<span
className="text-[9px] text-zinc-500 shrink-0 font-mono tabular-nums"
className={[
"text-[9px] shrink-0 font-mono tabular-nums",
entry.similarity_score >= 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"
>

View File

@ -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(<MemoryInspectorPanel workspaceId="ws-1" />);
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(<MemoryInspectorPanel workspaceId="ws-1" />);
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(<MemoryInspectorPanel workspaceId="ws-1" />);
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