diff --git a/workbench-ui/src/app/TopBar.tsx b/workbench-ui/src/app/TopBar.tsx
index 2881e2ff..6614bf4f 100644
--- a/workbench-ui/src/app/TopBar.tsx
+++ b/workbench-ui/src/app/TopBar.tsx
@@ -1,5 +1,6 @@
import { CommandPalette } from "../design/components/primitives/CommandPalette";
import { useRuntimeStatus } from "../api/queries";
+import { WrongZeroFrame } from "./WrongZeroFrame";
export function TopBar({
paletteOpen,
@@ -64,6 +65,8 @@ export function TopBar({
+
+
{connectionPill}
diff --git a/workbench-ui/src/app/WrongZeroFrame.test.tsx b/workbench-ui/src/app/WrongZeroFrame.test.tsx
new file mode 100644
index 00000000..c0dd636c
--- /dev/null
+++ b/workbench-ui/src/app/WrongZeroFrame.test.tsx
@@ -0,0 +1,80 @@
+import { QueryClientProvider } from "@tanstack/react-query";
+import { render, screen } from "@testing-library/react";
+import { MemoryRouter } from "react-router-dom";
+import { afterEach, describe, expect, it, vi } from "vitest";
+import { createTestQueryClient } from "../test/createTestQueryClient";
+import type { ServingMetrics } from "../types/api";
+import { WrongZeroFrame } from "./WrongZeroFrame";
+
+function renderFrame() {
+ return render(
+
+
+
+
+ ,
+ );
+}
+
+function stub(metrics: ServingMetrics[] | "error") {
+ vi.stubGlobal(
+ "fetch",
+ vi.fn(() =>
+ metrics === "error"
+ ? Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ok: false,
+ generated_at: "now",
+ error: { code: "read_error", message: "boom" },
+ }),
+ })
+ : Promise.resolve({
+ json: () => Promise.resolve({ ok: true, generated_at: "now", data: { items: metrics } }),
+ }),
+ ),
+ );
+}
+
+function lane(correct: number, refused: number, wrong: number, name: string): ServingMetrics {
+ return {
+ lane: name,
+ correct,
+ refused,
+ wrong,
+ sample_count: correct + refused + wrong,
+ source_path: `evals/${name}/report.json`,
+ source_digest: "sha256:x",
+ };
+}
+
+describe("WrongZeroFrame", () => {
+ afterEach(() => {
+ vi.restoreAllMocks();
+ localStorage.clear();
+ });
+
+ it("aggregates the live serving triplet across lanes with wrong load-bearing", async () => {
+ stub([lane(4, 46, 0, "train_sample"), lane(5, 495, 0, "holdout_dev")]);
+ renderFrame();
+ // 9 correct · 541 refused · 0 wrong
+ expect(await screen.findByText(/9 correct · 541 refused ·/)).toBeInTheDocument();
+ expect(screen.getByText("0 wrong")).toBeInTheDocument();
+ // it links to the discipline behind it
+ expect(screen.getByRole("link")).toHaveAttribute("href", "/calibration");
+ });
+
+ it("is a mirror — renders a non-zero wrong honestly, not a hard-coded zero", async () => {
+ stub([lane(90, 5, 5, "drifted")]);
+ renderFrame();
+ expect(await screen.findByText("5 wrong")).toBeInTheDocument();
+ expect(screen.queryByText("0 wrong")).not.toBeInTheDocument();
+ });
+
+ it("renders an honest 'metrics unavailable', never a fake zero, on error", async () => {
+ stub("error");
+ renderFrame();
+ expect(await screen.findByText(/metrics unavailable/)).toBeInTheDocument();
+ expect(screen.queryByText("0 wrong")).not.toBeInTheDocument();
+ });
+});
diff --git a/workbench-ui/src/app/WrongZeroFrame.tsx b/workbench-ui/src/app/WrongZeroFrame.tsx
new file mode 100644
index 00000000..546cb5e4
--- /dev/null
+++ b/workbench-ui/src/app/WrongZeroFrame.tsx
@@ -0,0 +1,59 @@
+import { Link } from "react-router-dom";
+import { useServingMetrics } from "../api/queries";
+
+// The project's thesis, made a constant presence: the live serving outcome
+// with the wrong count load-bearing. It is a MIRROR of /serving/metrics —
+// it shows whatever the committed reports say, never a hard-coded zero, and
+// says so honestly when the metrics can't be read.
+export function WrongZeroFrame() {
+ const { data, isLoading, isError } = useServingMetrics();
+
+ const base =
+ "shrink-0 rounded-full border px-3 py-1 text-xs tabular-nums focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--color-focus-ring)]";
+
+ if (isLoading) {
+ return (
+
+ wrong=0 …
+
+ );
+ }
+
+ if (isError || !data || data.length === 0) {
+ return (
+
+ wrong=0: metrics unavailable
+
+ );
+ }
+
+ const correct = data.reduce((sum, m) => sum + m.correct, 0);
+ const refused = data.reduce((sum, m) => sum + m.refused, 0);
+ const wrong = data.reduce((sum, m) => sum + m.wrong, 0);
+
+ return (
+
+ {correct} correct · {refused} refused ·
+ 0
+ ? "font-semibold text-[var(--color-state-contradicted)]"
+ : "font-semibold text-[var(--color-state-verified)]"
+ }
+ >
+ {wrong} wrong
+
+
+ );
+}