Skip to content

Commit 9125ec5

Browse files
committed
fix(showcase): gate Coverage D6 badge + stats by depth ladder; gated indicator only on genuine lower-rung failure
1 parent 64461e1 commit 9125ec5

6 files changed

Lines changed: 426 additions & 33 deletions

File tree

showcase/shell-dashboard/src/components/__tests__/unified-cell.test.tsx

Lines changed: 102 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ vi.mock("@/components/depth-chip", () => ({
4242
}));
4343

4444
vi.mock("@/components/badges", () => ({
45+
// Mirror the REAL Badge contract: a "?" label means no-data and the real
46+
// Badge returns null (hides). Replicating that here keeps these tests from
47+
// being overfit to a mock that renders unconditionally — a gated D6 routed
48+
// through label "?" would vanish in production but pass against a naive mock.
4549
Badge: vi.fn(
4650
({
4751
name,
@@ -50,11 +54,12 @@ vi.mock("@/components/badges", () => ({
5054
name: string;
5155
state: { tone: string; label: string };
5256
title?: string;
53-
}) => (
54-
<span data-testid={`mock-badge-${name}`} data-tone={state.tone}>
55-
{name} {state.label}
56-
</span>
57-
),
57+
}) =>
58+
state.label === "?" ? null : (
59+
<span data-testid={`mock-badge-${name}`} data-tone={state.tone}>
60+
{name} {state.label}
61+
</span>
62+
),
5863
),
5964
FlashOnChange: vi.fn(
6065
({ children }: { children: React.ReactNode; tone: string }) => (
@@ -166,6 +171,7 @@ function makeModel(overrides?: Partial<CellModel>): CellModel {
166171
d4: makeLevel(true, "green"),
167172
d5: makeLevel(true, "green"),
168173
d6: makeLevel(false),
174+
d6Effective: null,
169175
achievedDepth: 5,
170176
ceilingDepth: 5,
171177
chipColor: "green",
@@ -412,7 +418,15 @@ describe("UnifiedCell", () => {
412418
// d6 pill surfaces the depth chip + health badges (incl. the D6 badge).
413419
it("renders depth + health content (not blank) for a {d6}-only overlay set", () => {
414420
const ctx = makeCtx();
415-
const model = makeModel({ d6: makeLevel(true, "green") });
421+
// Fully-intact ladder (D3-D5 green by default) with a present green D6 →
422+
// d6Effective passes through as green, so the D6 badge renders visibly.
423+
// (The default makeModel d6Effective is null, which models a no-data
424+
// ladder — that would correctly suppress the D6 badge, defeating this
425+
// test's intent, so set it consistently here.)
426+
const model = makeModel({
427+
d6: makeLevel(true, "green"),
428+
d6Effective: "green",
429+
});
416430
const { getByTestId, queryByTestId } = render(
417431
<UnifiedCell ctx={ctx} model={model} overlays={overlaySet("d6")} />,
418432
);
@@ -427,6 +441,83 @@ describe("UnifiedCell", () => {
427441
});
428442
});
429443

444+
// ── D6 badge ladder-gating (D6 never green if D5 fails) ────────────
445+
describe("D6 badge reflects ladder-gated d6Effective", () => {
446+
it("renders a VISIBLE gated D6 badge ('—', gray) when D5 is red even though raw d6 is green", () => {
447+
const ctx = makeCtx();
448+
// Raw D6 dimension is green, but D5 is red so the ladder is broken
449+
// below D6 → d6Effective null. The D6 badge must render a real, VISIBLE
450+
// not-achieved indicator ("—", gray) — NOT a "?" that the real Badge
451+
// hides, and never green; CV stays per-dimension red (diagnostic).
452+
const model = makeModel({
453+
d3: makeLevel(true, "green"),
454+
d4: makeLevel(true, "green"),
455+
d5: makeLevel(true, "red"),
456+
d6: makeLevel(true, "green"),
457+
d6Effective: null,
458+
chipColor: "red",
459+
achievedDepth: 4,
460+
});
461+
const { getByTestId } = render(
462+
<UnifiedCell ctx={ctx} model={model} overlays={overlaySet("health")} />,
463+
);
464+
465+
// The gated D6 badge is PRESENT (does not vanish) and renders the
466+
// em-dash. With the mock honoring the real "?"→null rule, this would
467+
// FAIL against a naive "?"-emitting implementation — proving the fix.
468+
const d6Badge = getByTestId("mock-badge-D6");
469+
expect(d6Badge).toBeInTheDocument();
470+
expect(d6Badge.getAttribute("data-tone")).toBe("gray");
471+
expect(d6Badge.getAttribute("data-tone")).not.toBe("green");
472+
expect(d6Badge.textContent).toContain("—");
473+
474+
// CV badge still shows the real per-dimension D5 failure (red).
475+
expect(getByTestId("mock-badge-CV").getAttribute("data-tone")).toBe(
476+
"red",
477+
);
478+
});
479+
480+
it("hides the D6 badge entirely when D6 has no data (does not exist)", () => {
481+
const ctx = makeCtx();
482+
// D6 not mapped/no row → does not exist. Gated rendering must NOT kick
483+
// in; the badge is simply absent (no "—" for a non-existent rung).
484+
const model = makeModel({
485+
d3: makeLevel(true, "green"),
486+
d4: makeLevel(true, "green"),
487+
d5: makeLevel(true, "green"),
488+
d6: makeLevel(false),
489+
d6Effective: null,
490+
chipColor: "amber",
491+
achievedDepth: 5,
492+
});
493+
const { queryByTestId } = render(
494+
<UnifiedCell ctx={ctx} model={model} overlays={overlaySet("health")} />,
495+
);
496+
497+
expect(queryByTestId("mock-badge-D6")).not.toBeInTheDocument();
498+
});
499+
500+
it("renders D6 badge green on a fully-intact ladder (d6Effective green)", () => {
501+
const ctx = makeCtx();
502+
const model = makeModel({
503+
d3: makeLevel(true, "green"),
504+
d4: makeLevel(true, "green"),
505+
d5: makeLevel(true, "green"),
506+
d6: makeLevel(true, "green"),
507+
d6Effective: "green",
508+
chipColor: "green",
509+
achievedDepth: 6,
510+
});
511+
const { getByTestId } = render(
512+
<UnifiedCell ctx={ctx} model={model} overlays={overlaySet("health")} />,
513+
);
514+
515+
expect(getByTestId("mock-badge-D6").getAttribute("data-tone")).toBe(
516+
"green",
517+
);
518+
});
519+
});
520+
430521
// ── Additional coverage ───────────────────────────────────────────
431522
describe("badge tone mapping", () => {
432523
it("maps green status to green tone with check mark", () => {
@@ -445,20 +536,19 @@ describe("UnifiedCell", () => {
445536
expect(badge.textContent).toContain("✓");
446537
});
447538

448-
it("maps null status to gray tone with question mark", () => {
539+
it("hides a no-data (null status) rung — the real Badge nulls a '?' label", () => {
449540
const ctx = makeCtx();
450541
const model = makeModel({
451-
d3: makeLevel(true, null), // exists but no status yet
542+
d3: makeLevel(true, null), // exists but no status yet → label "?"
452543
d4: makeLevel(false),
453544
d5: makeLevel(false),
454545
});
455-
const { getByTestId } = render(
546+
const { queryByTestId } = render(
456547
<UnifiedCell ctx={ctx} model={model} overlays={overlaySet("health")} />,
457548
);
458549

459-
const badge = getByTestId("mock-badge-API");
460-
expect(badge.getAttribute("data-tone")).toBe("gray");
461-
expect(badge.textContent).toContain("?");
550+
// A no-data rung emits label "?", which the real Badge hides → no badge.
551+
expect(queryByTestId("mock-badge-API")).not.toBeInTheDocument();
462552
});
463553
});
464554
});

showcase/shell-dashboard/src/components/unified-cell.tsx

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,36 @@ export interface UnifiedCellProps {
3838
// TestBadge helper
3939
// ---------------------------------------------------------------------------
4040

41-
function TestBadge({ name, level }: { name: string; level: TestLevel | null }) {
41+
function TestBadge({
42+
name,
43+
level,
44+
gated = false,
45+
}: {
46+
name: string;
47+
level: TestLevel | null;
48+
/**
49+
* When true, the rung EXISTS but is ladder-blocked by a lower rung (its
50+
* effective status collapsed to `null`). Render a real, VISIBLE not-achieved
51+
* indicator ("—", gray) rather than the no-data "?" — the latter is hidden
52+
* by `Badge` (label === "?" → null), which would make a gated D6 vanish.
53+
*/
54+
gated?: boolean;
55+
}) {
4256
if (!level || !level.exists) return null;
4357

58+
// Gated rung: exists but blocked below → visible em-dash, not a hidden "?".
59+
if (gated) {
60+
return (
61+
<FlashOnChange tone="gray">
62+
<Badge
63+
name={name}
64+
state={{ tone: "gray", label: "—" }}
65+
title={`${name}: gated — blocked by a lower rung`}
66+
/>
67+
</FlashOnChange>
68+
);
69+
}
70+
4471
const tone: BadgeTone =
4572
level.status === "green"
4673
? "green"
@@ -64,7 +91,7 @@ function TestBadge({ name, level }: { name: string; level: TestLevel | null }) {
6491
<Badge
6592
name={name}
6693
state={{ tone, label }}
67-
title={`${name}: ${level.status ?? "pending"}`}
94+
title={`${name}: ${level.status ?? "no data"}`}
6895
/>
6996
</FlashOnChange>
7097
);
@@ -172,7 +199,58 @@ function HealthLayer({ model }: { model: CellModel }) {
172199
<TestBadge name="API" level={model.d3} />
173200
<TestBadge name="RT" level={model.d4} />
174201
<TestBadge name="CV" level={model.d5} />
175-
<TestBadge name="D6" level={model.d6} />
202+
{/*
203+
D6 is the TOP of the verification ladder, so its badge must reflect the
204+
LADDER-GATED status (`model.d6Effective`), NOT the raw per-dimension
205+
`model.d6.status`. When the ladder is broken/unverified below D6,
206+
`d6Effective` collapses to null. We distinguish three cases:
207+
- GATED-BY-FAILURE (d6 EXISTS, d6Effective === null, AND a lower rung
208+
is genuinely FAILING — D3/D4 non-green or a mapped D5 red/amber):
209+
render a VISIBLE not-achieved indicator ("—", gray) — NOT the
210+
no-data "?" (which the real Badge hides → the badge would vanish).
211+
The actual lower-rung failure is already shown by the CV/API/RT
212+
badges.
213+
- NO-DATA (d6 does not exist, OR d6Effective null only because the
214+
ladder is unverified/no-data — e.g. empty live map → D5 mapped but
215+
no rows → status null): keep the normal hide behavior, rendering NO
216+
badge. A no-data ladder is NOT a failure, so it shows nothing.
217+
- LADDER INTACT (d6Effective non-null): pass d6Effective through so a
218+
genuine D6 red/amber/green renders per-dimension.
219+
API/RT/CV stay per-dimension (diagnostic); only D6 is gated. See
220+
`d6Effective` in cell-model.ts.
221+
*/}
222+
{(() => {
223+
// A gated "—" is only meaningful when D6 is blocked by a genuine
224+
// FAILING lower rung — not merely absent data. `d6Effective === null`
225+
// is too broad: it collapses to null both when (a) a lower rung is
226+
// actually failing (D3/D4 non-green, or a mapped D5 red/amber) AND
227+
// when (b) the ladder is simply unverified/no-data (empty live map →
228+
// D5 mapped-but-no-rows → status null). Case (b) must render NO badge
229+
// (D6 falls back to the hidden "?" no-data treatment), so the gated
230+
// indicator fires ONLY on case (a). This mirrors `cell-model.ts`'s
231+
// `d1d4GateFails` predicate plus a present, failing D5.
232+
const lowerRungFailing =
233+
Boolean(model.d3?.exists && model.d3.status !== "green") ||
234+
Boolean(model.d4?.exists && model.d4.status !== "green") ||
235+
Boolean(
236+
model.d5?.exists &&
237+
(model.d5.status === "red" || model.d5.status === "amber"),
238+
);
239+
const d6Gated = Boolean(
240+
model.d6?.exists && model.d6Effective === null && lowerRungFailing,
241+
);
242+
return (
243+
<TestBadge
244+
name="D6"
245+
level={
246+
model.d6 && model.d6.exists
247+
? { ...model.d6, status: model.d6Effective }
248+
: model.d6
249+
}
250+
gated={d6Gated}
251+
/>
252+
);
253+
})()}
176254
</div>
177255
);
178256
}
@@ -283,6 +361,7 @@ function modelsEqual(a: CellModel, b: CellModel): boolean {
283361
a.achievedDepth === b.achievedDepth &&
284362
a.ceilingDepth === b.ceilingDepth &&
285363
a.chipColor === b.chipColor &&
364+
a.d6Effective === b.d6Effective &&
286365
a.isRegression === b.isRegression &&
287366
testLevelsEqual(a.d3, b.d3) &&
288367
testLevelsEqual(a.d4, b.d4) &&

showcase/shell-dashboard/src/lib/__tests__/cell-model.test.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,4 +1390,84 @@ describe("buildCellModel", () => {
13901390
expect(model.achievedDepth).toBe(3);
13911391
});
13921392
});
1393+
1394+
// ── d6Effective: ladder-gated D6 status (D6 never green if D5 fails) ──
1395+
describe("d6Effective ladder-gating", () => {
1396+
it("blocks (null) D6 when D5 is RED even though the raw D6 row is GREEN", () => {
1397+
// The exact bug: D5 red but D6 emitted green in isolation. The raw
1398+
// per-dimension d6.status is green, but the top-of-ladder claim is
1399+
// broken below D6, so d6Effective must NOT be green (and not a false
1400+
// red — the CV badge already shows the D5 failure).
1401+
const live = mapOf([
1402+
row(keyFor("e2e", "agno", "agentic-chat"), "e2e", "green"),
1403+
row(keyFor("chat", "agno"), "chat", "green"),
1404+
row(keyFor("tools", "agno"), "tools", "green"),
1405+
row(keyFor("d5", "agno", "agentic-chat"), "d5", "red"),
1406+
row(keyFor("d6", "agno", "agentic-chat"), "d6", "green"),
1407+
]);
1408+
const model = buildCellModel(live, wiredInput("agno", "agentic-chat"));
1409+
// Raw per-dimension D6 is green (diagnostic), but the ladder is broken.
1410+
expect(model.d6!.status).toBe("green");
1411+
// Ladder-gated D6 is blocked → null, NOT green, NOT red.
1412+
expect(model.d6Effective).toBeNull();
1413+
// Chip stays red (D5-broken ladder) and badges below stay per-dimension.
1414+
expect(model.chipColor).toBe("red");
1415+
expect(model.d5!.status).toBe("red");
1416+
expect(model.achievedDepth).toBe(4);
1417+
});
1418+
1419+
it("greens d6Effective only on a FULLY-INTACT ladder (D5 green + D6 green)", () => {
1420+
const live = mapOf([
1421+
row(keyFor("e2e", "agno", "agentic-chat"), "e2e", "green"),
1422+
row(keyFor("chat", "agno"), "chat", "green"),
1423+
row(keyFor("tools", "agno"), "tools", "green"),
1424+
row(keyFor("d5", "agno", "agentic-chat"), "d5", "green"),
1425+
row(keyFor("d6", "agno", "agentic-chat"), "d6", "green"),
1426+
]);
1427+
const model = buildCellModel(live, wiredInput("agno", "agentic-chat"));
1428+
expect(model.d6Effective).toBe("green");
1429+
expect(model.achievedDepth).toBe(6);
1430+
expect(model.chipColor).toBe("green");
1431+
});
1432+
1433+
it("passes through a genuine D6 RED when the ladder is intact through D5", () => {
1434+
// D5 green, D6 red → ladder intact below D6, the D6 failure is real.
1435+
const live = mapOf([
1436+
row(keyFor("e2e", "agno", "agentic-chat"), "e2e", "green"),
1437+
row(keyFor("chat", "agno"), "chat", "green"),
1438+
row(keyFor("tools", "agno"), "tools", "green"),
1439+
row(keyFor("d5", "agno", "agentic-chat"), "d5", "green"),
1440+
row(keyFor("d6", "agno", "agentic-chat"), "d6", "red"),
1441+
]);
1442+
const model = buildCellModel(live, wiredInput("agno", "agentic-chat"));
1443+
expect(model.d6Effective).toBe("red");
1444+
expect(model.chipColor).toBe("amber");
1445+
});
1446+
1447+
it("blocks (null) D6 when the D1-D4 gate fails, regardless of raw D6", () => {
1448+
const live = mapOf([
1449+
// D3 red → gate fails; D6 raw green must be suppressed.
1450+
row(keyFor("e2e", "agno", "agentic-chat"), "e2e", "red"),
1451+
row(keyFor("d5", "agno", "agentic-chat"), "d5", "green"),
1452+
row(keyFor("d6", "agno", "agentic-chat"), "d6", "green"),
1453+
]);
1454+
const model = buildCellModel(live, wiredInput("agno", "agentic-chat"));
1455+
expect(model.d6Effective).toBeNull();
1456+
expect(model.chipColor).toBe("red");
1457+
});
1458+
1459+
it("blocks (null) D6 when D5 is unverified (no-data) even if raw D6 is green", () => {
1460+
const live = mapOf([
1461+
row(keyFor("e2e", "agno", "agentic-chat"), "e2e", "green"),
1462+
row(keyFor("chat", "agno"), "chat", "green"),
1463+
row(keyFor("tools", "agno"), "tools", "green"),
1464+
// D5 mapped but no row emitted → status null (unverified).
1465+
row(keyFor("d6", "agno", "agentic-chat"), "d6", "green"),
1466+
]);
1467+
const model = buildCellModel(live, wiredInput("agno", "agentic-chat"));
1468+
expect(model.d5!.status).toBeNull();
1469+
expect(model.d6Effective).toBeNull();
1470+
expect(model.chipColor).toBe("gray");
1471+
});
1472+
});
13931473
});

0 commit comments

Comments
 (0)