Skip to content

Commit 5badfb8

Browse files
committed
feat(showcase-dashboard): D6-ceiling chip color algorithm + aggregate key
Update depth-utils to treat D6 as an integration-scoped aggregate (d6:<slug> not d6:<slug>/<featureId>), raise maxPossible from 5 to 6 when D5 mapping exists, and adjust chipColor derivation so D5-green without D6 yields amber instead of green. Update composed-cell memo comparator and cell-drilldown dimensions. Comprehensive test updates across cell-model, depth-utils, compute-tally-detail, unified-cell, and status-tab.
1 parent fc8ce6e commit 5badfb8

7 files changed

Lines changed: 225 additions & 77 deletions

File tree

showcase/shell-dashboard/src/components/__tests__/compute-tally-detail.test.tsx

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,19 @@ function makeIntegration(slug: string, demoIds: string[]): Integration {
3838
return {
3939
slug,
4040
name: slug,
41+
category: "python",
4142
language: "python",
43+
description: "",
44+
repo: "",
4245
backend_url: `https://${slug}.example.com`,
43-
docs_url: "",
44-
source_url: "",
46+
deployed: true,
47+
features: demoIds,
4548
demos: demoIds.map((id) => ({
4649
id,
50+
name: id,
51+
description: "",
52+
tags: [],
4753
route: `/${id}`,
48-
command: "",
4954
})),
5055
} as Integration;
5156
}
@@ -56,7 +61,7 @@ function makeFeature(id: string, name: string): Feature {
5661
name,
5762
description: "",
5863
category: "core",
59-
kind: "standard",
64+
kind: "primary",
6065
} as Feature;
6166
}
6267

@@ -85,17 +90,18 @@ describe("computeColumnTallyDetail", () => {
8590
});
8691
});
8792

88-
it("green D3 cells land in green bucket", () => {
93+
it("green D6 cells land in green bucket", () => {
8994
const integration = makeIntegration("my-int", ["feat-a", "feat-b"]);
9095
const features = [
9196
makeFeature("feat-a", "Feature A"),
9297
makeFeature("feat-b", "Feature B"),
9398
];
9499

95-
// Both features have green D3 → achievedDepth=3, ceilingDepth=3 → green chip
100+
// Both features have green D3 + green D6chipColor=green (D6-ceiling)
96101
const liveStatus: LiveStatusMap = new Map([
97102
["e2e:my-int/feat-a", makeRow("e2e:my-int/feat-a", "e2e", "green")],
98103
["e2e:my-int/feat-b", makeRow("e2e:my-int/feat-b", "e2e", "green")],
104+
["d6:my-int", makeRow("d6:my-int", "d6", "green")],
99105
]);
100106

101107
const result = computeColumnTallyDetail(
@@ -114,15 +120,15 @@ describe("computeColumnTallyDetail", () => {
114120
expect(result.red).toEqual([]);
115121
});
116122

117-
it("red D3 cells are gray (achievedDepth=0) and excluded", () => {
123+
it("red D3 → red chip, green D3 without D5/D6 → gray (excluded)", () => {
118124
const integration = makeIntegration("my-int", ["feat-a", "feat-b"]);
119125
const features = [
120126
makeFeature("feat-a", "Feature A"),
121127
makeFeature("feat-b", "Feature B"),
122128
];
123129

124-
// feat-a: D3=red → achievedDepth=0, ceilingDepth=3 → gray (skipped)
125-
// feat-b: D3=green → green chip
130+
// feat-a: D3=red → chipColor=red (d1d4GateFails)
131+
// feat-b: D3=green but no D5/D6 → chipColor=gray (D6-ceiling)
126132
const liveStatus: LiveStatusMap = new Map([
127133
["e2e:my-int/feat-a", makeRow("e2e:my-int/feat-a", "e2e", "red")],
128134
["e2e:my-int/feat-b", makeRow("e2e:my-int/feat-b", "e2e", "green")],
@@ -136,11 +142,11 @@ describe("computeColumnTallyDetail", () => {
136142
);
137143

138144
expect(result.unknown).toBe(false);
139-
expect(result.green).toEqual([
140-
{ label: "Feature B", dimension: "e2e", featureId: "feat-b" },
141-
]);
145+
expect(result.green).toEqual([]);
142146
expect(result.amber).toEqual([]);
143-
expect(result.red).toEqual([]);
147+
expect(result.red).toEqual([
148+
{ label: "Feature A", dimension: "e2e", featureId: "feat-a" },
149+
]);
144150
});
145151

146152
it("features without demos are gray (unwired) and excluded", () => {
@@ -151,8 +157,10 @@ describe("computeColumnTallyDetail", () => {
151157
makeFeature("feat-2", "Feature 2"),
152158
];
153159

160+
// D3=green + D6=green → chipColor=green (D6-ceiling algorithm)
154161
const liveStatus: LiveStatusMap = new Map([
155162
["e2e:partial/feat-1", makeRow("e2e:partial/feat-1", "e2e", "green")],
163+
["d6:partial", makeRow("d6:partial", "d6", "green")],
156164
]);
157165

158166
const result = computeColumnTallyDetail(
@@ -163,7 +171,7 @@ describe("computeColumnTallyDetail", () => {
163171
);
164172

165173
expect(result.unknown).toBe(false);
166-
// Only feat-1 appears (has a demo); feat-2 is unwired → gray → excluded
174+
// feat-1: wired + D3=green + D6=green → green; feat-2: unwired → gray
167175
expect(result.green).toEqual([
168176
{ label: "Feature 1", dimension: "e2e", featureId: "feat-1" },
169177
]);
@@ -203,9 +211,11 @@ describe("computeColumnTallyDetail", () => {
203211
makeFeature("feat-b", "Feature B"),
204212
];
205213

214+
// D3=green + D6=green → chipColor=green for supported features
206215
const liveStatus: LiveStatusMap = new Map([
207216
["e2e:ns-int/feat-a", makeRow("e2e:ns-int/feat-a", "e2e", "green")],
208217
["e2e:ns-int/feat-b", makeRow("e2e:ns-int/feat-b", "e2e", "green")],
218+
["d6:ns-int", makeRow("d6:ns-int", "d6", "green")],
209219
]);
210220

211221
const result = computeColumnTallyDetail(
@@ -216,7 +226,7 @@ describe("computeColumnTallyDetail", () => {
216226
);
217227

218228
expect(result.unknown).toBe(false);
219-
// feat-a: green; feat-b: unsupported → gray → excluded
229+
// feat-a: D3+D6 green → green; feat-b: unsupported → gray → excluded
220230
expect(result.green).toEqual([
221231
{ label: "Feature A", dimension: "e2e", featureId: "feat-a" },
222232
]);

showcase/shell-dashboard/src/components/__tests__/depth-utils.test.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ describe("deriveDepth", () => {
204204
// ── isRegression now compares against maxPossible, not historical max_depth ──
205205

206206
it("isRegression is true when achieved < maxPossible (D5 mapping exists, CV red)", () => {
207-
// "agentic-chat" has D5 mapping → maxPossible=5, achieved=4 → regression
207+
// "agentic-chat" has D5 mapping → maxPossible=6, achieved=4 → regression
208208
const c = cell("lgp", "agentic-chat", "wired", 4);
209209
const live = mapOf([
210210
row("health:lgp", "health", "green"),
@@ -215,7 +215,7 @@ describe("deriveDepth", () => {
215215
]);
216216
const result = deriveDepth(c, live);
217217
expect(result.achieved).toBe(4);
218-
expect(result.maxPossible).toBe(5);
218+
expect(result.maxPossible).toBe(6);
219219
expect(result.isRegression).toBe(true);
220220
});
221221

@@ -235,12 +235,12 @@ describe("deriveDepth", () => {
235235
});
236236

237237
it("isRegression is true when health drops (maxPossible > 0)", () => {
238-
// "agentic-chat" has D5 mapping → maxPossible=5, health red → achieved=0
238+
// "agentic-chat" has D5 mapping → maxPossible=6, health red → achieved=0
239239
const c = cell("lgp", "agentic-chat", "wired", 1);
240240
const live = mapOf([row("health:lgp", "health", "red")]);
241241
const result = deriveDepth(c, live);
242242
expect(result.achieved).toBe(0);
243-
expect(result.maxPossible).toBe(5);
243+
expect(result.maxPossible).toBe(6);
244244
expect(result.isRegression).toBe(true);
245245
});
246246

@@ -350,15 +350,15 @@ describe("deriveDepth", () => {
350350
expect(result.achieved).toBe(4);
351351
});
352352

353-
it("returns D6 when D0-D5 green plus D6 green", () => {
353+
it("returns D6 when D0-D5 green plus D6 green (aggregate key)", () => {
354354
const c = cell("lgp", "agentic-chat");
355355
const live = mapOf([
356356
row("health:lgp", "health", "green"),
357357
row("agent:lgp", "agent", "green"),
358358
row("e2e:lgp/agentic-chat", "e2e", "green"),
359359
row("chat:lgp", "chat", "green"),
360360
row("d5:lgp/agentic-chat", "d5", "green"),
361-
row("d6:lgp/agentic-chat", "d6", "green"),
361+
row("d6:lgp", "d6", "green"),
362362
]);
363363
const result = deriveDepth(c, live);
364364
expect(result.achieved).toBe(6);
@@ -379,7 +379,7 @@ describe("deriveDepth", () => {
379379
// ── maxPossible computation ──
380380

381381
describe("maxPossible", () => {
382-
it("(a) D5 mapping exists, all green → achieved=5, maxPossible=5, chip=GREEN territory", () => {
382+
it("(a) D5 mapping exists, D5 green but D6 missing → achieved=5, maxPossible=6, regression", () => {
383383
const c = cell("lgp", "agentic-chat");
384384
const live = mapOf([
385385
row("health:lgp", "health", "green"),
@@ -390,30 +390,29 @@ describe("deriveDepth", () => {
390390
]);
391391
const result = deriveDepth(c, live);
392392
expect(result.achieved).toBe(5);
393-
expect(result.maxPossible).toBe(5);
394-
// achieved === maxPossible → at ceiling, no regression
395-
expect(result.isRegression).toBe(false);
393+
expect(result.maxPossible).toBe(6);
394+
// achieved < maxPossible → regression (D6 not yet achieved)
395+
expect(result.isRegression).toBe(true);
396396
});
397397

398-
it("(a-full) D5+D6 green → achieved=6, maxPossible=5 (D6 is stretch, still at-ceiling)", () => {
398+
it("(a-full) D5+D6 green → achieved=6, maxPossible=6, at ceiling", () => {
399399
const c = cell("lgp", "agentic-chat");
400400
const live = mapOf([
401401
row("health:lgp", "health", "green"),
402402
row("agent:lgp", "agent", "green"),
403403
row("e2e:lgp/agentic-chat", "e2e", "green"),
404404
row("chat:lgp", "chat", "green"),
405405
row("d5:lgp/agentic-chat", "d5", "green"),
406-
row("d6:lgp/agentic-chat", "d6", "green"),
406+
row("d6:lgp", "d6", "green"),
407407
]);
408408
const result = deriveDepth(c, live);
409409
expect(result.achieved).toBe(6);
410-
expect(result.maxPossible).toBe(5);
411-
// depthColorClass treats `depth >= maxDepth` as at-ceiling, so D6
412-
// still renders green even though it exceeds the structural cap.
410+
expect(result.maxPossible).toBe(6);
411+
// achieved === maxPossible → at ceiling, no regression
413412
expect(result.isRegression).toBe(false);
414413
});
415414

416-
it("(b) D5 mapping exists, CV red → achieved=4, maxPossible=5, chip=AMBER territory", () => {
415+
it("(b) D5 mapping exists, CV red → achieved=4, maxPossible=6, chip=AMBER territory", () => {
417416
const c = cell("lgp", "agentic-chat");
418417
const live = mapOf([
419418
row("health:lgp", "health", "green"),
@@ -424,11 +423,11 @@ describe("deriveDepth", () => {
424423
]);
425424
const result = deriveDepth(c, live);
426425
expect(result.achieved).toBe(4);
427-
expect(result.maxPossible).toBe(5);
426+
expect(result.maxPossible).toBe(6);
428427
expect(result.isRegression).toBe(true);
429428
});
430429

431-
it("(c) D5 mapping exists, CV no data → achieved=4, maxPossible=5, chip=AMBER territory", () => {
430+
it("(c) D5 mapping exists, CV no data → achieved=4, maxPossible=6, chip=AMBER territory", () => {
432431
const c = cell("lgp", "agentic-chat");
433432
const live = mapOf([
434433
row("health:lgp", "health", "green"),
@@ -439,7 +438,7 @@ describe("deriveDepth", () => {
439438
]);
440439
const result = deriveDepth(c, live);
441440
expect(result.achieved).toBe(4);
442-
expect(result.maxPossible).toBe(5);
441+
expect(result.maxPossible).toBe(6);
443442
expect(result.isRegression).toBe(true);
444443
});
445444

@@ -471,7 +470,7 @@ describe("deriveDepth", () => {
471470
expect(result.isRegression).toBe(true);
472471
});
473472

474-
it("(f) D2 with maxPossible=5 → chip=RED territory (3 levels below)", () => {
473+
it("(f) D2 with maxPossible=6 → chip=RED territory (4 levels below)", () => {
475474
const c = cell("lgp", "agentic-chat");
476475
const live = mapOf([
477476
row("health:lgp", "health", "green"),
@@ -480,8 +479,8 @@ describe("deriveDepth", () => {
480479
]);
481480
const result = deriveDepth(c, live);
482481
expect(result.achieved).toBe(2);
483-
expect(result.maxPossible).toBe(5);
484-
// 5 - 2 = 3, which is > 2 → RED territory
482+
expect(result.maxPossible).toBe(6);
483+
// 6 - 2 = 4, which is > 2 → RED territory
485484
expect(result.isRegression).toBe(true);
486485
});
487486

@@ -490,7 +489,7 @@ describe("deriveDepth", () => {
490489
const live = mapOf([]); // no live data
491490
const result = deriveDepth(c, live);
492491
expect(result.achieved).toBe(0);
493-
expect(result.maxPossible).toBe(5); // D5 mapping exists
492+
expect(result.maxPossible).toBe(6); // D5 mapping exists → D6 reachable
494493
expect(result.isRegression).toBe(true);
495494
});
496495

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ function makeModel(overrides?: Partial<CellModel>): CellModel {
165165
d3: makeLevel(true, "green"),
166166
d4: makeLevel(true, "green"),
167167
d5: makeLevel(true, "green"),
168+
d6: makeLevel(false),
168169
achievedDepth: 5,
169170
ceilingDepth: 5,
170171
chipColor: "green",

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ function arePropsEqual(
269269
keyFor("e2e", slug, featureId),
270270
keyFor("smoke", slug),
271271
keyFor("d5", slug, featureId),
272-
keyFor("d6", slug, featureId),
272+
keyFor("d6", slug),
273273
];
274274
for (const k of directKeys) {
275275
if (prev.ctx.liveStatus.get(k) !== next.ctx.liveStatus.get(k)) return false;

showcase/shell-dashboard/src/components/depth-utils.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,13 @@
1111
* D3 = e2e:<slug>/<featureId> green (per-cell)
1212
* D4 = chat:<slug> OR tools:<slug> green (integration-scoped)
1313
* D5 = d5:<slug>/<d5FeatureType> green (per-cell, mapped via CATALOG_TO_D5_KEY)
14-
* D6 = d6:<slug>/<featureId> green (per-cell)
14+
* D6 = d6:<slug> green (integration-scoped aggregate)
1515
*
1616
* Achieved depth = highest D where ALL lower depths are also green.
1717
* Short-circuits: if any level is not green, stop there.
1818
*/
19-
import {
20-
keyFor,
21-
CATALOG_TO_D5_KEY,
22-
type LiveStatusMap,
23-
} from "@/lib/live-status";
19+
import { keyFor, CATALOG_TO_D5_KEY } from "@/lib/live-status";
20+
import type { LiveStatusMap } from "@/lib/live-status";
2421

2522
/** Minimal catalog cell shape consumed by depth derivation. */
2623
export interface CatalogCell {
@@ -93,12 +90,8 @@ function isD5Green(
9390
* - D0: always possible for wired/stub cells
9491
* - D1-D4: always possible if the cell has a feature ID
9592
* - D5: possible only if CATALOG_TO_D5_KEY[featureId] exists and has entries
96-
* - D6: a stretch goal, not a structural ceiling — D6 probes are rare and
97-
* not registered per-feature, so we treat D5 as the ceiling. A cell that
98-
* actually reaches D6 still renders green (depthColorClass treats
99-
* `depth >= maxDepth` as at-ceiling), so capping at 5 doesn't penalize
100-
* the rare D6 achievers — it just stops penalizing every D5 cell as
101-
* "below ceiling" when D6 was never wired.
93+
* - D6: possible when a D5 mapping exists (D6 uses an integration-scoped
94+
* aggregate key, so no additional per-feature mapping is needed)
10295
*/
10396
function computeMaxPossible(cell: CatalogCell): AchievedDepth {
10497
// Unsupported/unshipped: max possible is 0.
@@ -118,8 +111,8 @@ function computeMaxPossible(cell: CatalogCell): AchievedDepth {
118111
return 4;
119112
}
120113

121-
// D5 mapping exists. D6 is a stretch goal — see fn doc above.
122-
return 5;
114+
// D5 mapping exists and D6 is reachable.
115+
return 6;
123116
}
124117

125118
/**
@@ -221,8 +214,8 @@ export function deriveDepth(
221214
}
222215
achieved = 5;
223216

224-
// D6: d6:<slug>/<featureId> green (per-cell)
225-
if (isGreen(live, keyFor("d6", cell.integration, cell.feature))) {
217+
// D6: d6:<slug> green (integration-scoped aggregate)
218+
if (isGreen(live, keyFor("d6", cell.integration))) {
226219
achieved = 6;
227220
}
228221

showcase/shell-dashboard/src/components/status-tab.test.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ function entry(
3636
describe("StatusTab", () => {
3737
it("renders schedule table and running panel", () => {
3838
const { getByTestId } = render(
39-
<StatusTab entries={[entry()]} onTrigger={async () => {}} />,
39+
<StatusTab
40+
entries={[entry()]}
41+
onTrigger={async () => {}}
42+
selectedProbeId={null}
43+
onSelectProbe={() => {}}
44+
/>,
4045
);
4146
expect(getByTestId("status-table")).toBeDefined();
4247
expect(getByTestId("status-running-panel")).toBeDefined();
@@ -45,7 +50,12 @@ describe("StatusTab", () => {
4550
it("forwards trigger callback when row trigger is invoked", async () => {
4651
const onTrigger = vi.fn(async () => {});
4752
const { getByTestId, getByText } = render(
48-
<StatusTab entries={[entry()]} onTrigger={onTrigger} />,
53+
<StatusTab
54+
entries={[entry()]}
55+
onTrigger={onTrigger}
56+
selectedProbeId={null}
57+
onSelectProbe={() => {}}
58+
/>,
4959
);
5060
fireEvent.click(getByTestId("status-trigger-smoke"));
5161
fireEvent.click(getByText("Run all"));
@@ -54,7 +64,12 @@ describe("StatusTab", () => {
5464

5565
it("renders idle panel when no entries provided", () => {
5666
const { getByTestId } = render(
57-
<StatusTab entries={[]} onTrigger={async () => {}} />,
67+
<StatusTab
68+
entries={[]}
69+
onTrigger={async () => {}}
70+
selectedProbeId={null}
71+
onSelectProbe={() => {}}
72+
/>,
5873
);
5974
expect(getByTestId("running-idle")).toBeDefined();
6075
});

0 commit comments

Comments
 (0)