Skip to content

Commit c506d8b

Browse files
committed
fix(showcase): deriveDepth D4 uses worst-state-wins instead of OR
A present red chat/tools row now pulls D4 down even if its sibling is green, matching cell-model resolveD4. Single-side present-green cases still achieve D4 (absent sibling is skipped).
1 parent afd3bdb commit c506d8b

2 files changed

Lines changed: 46 additions & 14 deletions

File tree

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,22 @@ describe("deriveDepth", () => {
161161
expect(result.achieved).toBe(4);
162162
});
163163

164+
it("D4 worst-state wins: green chat + red tools does NOT achieve D4", () => {
165+
// Unification D: D4 was `chatGreen || toolsGreen` (OR), which credited
166+
// D4 even when one half was red. Match cell-model's resolveD4 worst-
167+
// state-wins — a red tools row pulls D4 down so achieved caps at D3.
168+
const c = cell("lgp", "agentic-chat");
169+
const live = mapOf([
170+
row("health:lgp", "health", "green"),
171+
row("agent:lgp", "agent", "green"),
172+
row("e2e:lgp/agentic-chat", "e2e", "green"),
173+
row("chat:lgp", "chat", "green"),
174+
row("tools:lgp", "tools", "red"),
175+
]);
176+
const result = deriveDepth(c, live);
177+
expect(result.achieved).toBe(3);
178+
});
179+
164180
it("short-circuits: D1 red means D0 even if D2+ green", () => {
165181
const c = cell("lgp", "agentic-chat");
166182
const live = mapOf([

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

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,29 @@ function isGreenAndFresh(
8686
return !isStale(row, now, maxAgeMs);
8787
}
8888

89+
/**
90+
* Check whether D4 (real-time chat/tools) is green for a given slug, using
91+
* worst-state-wins semantics that mirror `cell-model.ts` `resolveD4`: D4 is
92+
* green only when at least one of `chat:<slug>` / `tools:<slug>` is present
93+
* AND every present row is green-and-fresh. A present red/degraded/stale row
94+
* pulls D4 down even if its sibling is green — the old `chatGreen ||
95+
* toolsGreen` OR wrongly credited D4 when one half was failing.
96+
*/
97+
function isD4Green(live: LiveStatusMap, slug: string, now: number): boolean {
98+
const chatRow = live.get(keyFor("chat", slug)) ?? null;
99+
const toolsRow = live.get(keyFor("tools", slug)) ?? null;
100+
// Neither present → D4 has no evidence, not achieved.
101+
if (!chatRow && !toolsRow) return false;
102+
// Every present row must be green-and-fresh (worst-state wins).
103+
for (const present of [chatRow, toolsRow]) {
104+
if (!present) continue;
105+
if (!isGreenAndFresh(live, present.key, now, D4_STALE_AFTER_MS)) {
106+
return false;
107+
}
108+
}
109+
return true;
110+
}
111+
89112
/**
90113
* Check whether all D5 PB rows for a given (slug, catalogFeatureId) are green
91114
* AND fresh. Returns false if the feature has no D5 mapping or any mapped row
@@ -235,20 +258,13 @@ export function deriveDepth(
235258
}
236259
achieved = 3;
237260

238-
// D4: chat:<slug> OR tools:<slug> green (real-time window)
239-
const chatGreen = isGreenAndFresh(
240-
live,
241-
keyFor("chat", cell.integration),
242-
now,
243-
D4_STALE_AFTER_MS,
244-
);
245-
const toolsGreen = isGreenAndFresh(
246-
live,
247-
keyFor("tools", cell.integration),
248-
now,
249-
D4_STALE_AFTER_MS,
250-
);
251-
if (!(chatGreen || toolsGreen)) {
261+
// D4: chat:<slug> + tools:<slug>, worst-state wins (real-time window).
262+
// Mirrors cell-model.ts `resolveD4`: a present green chat with a present
263+
// red tools yields a NOT-green D4 (the old `chatGreen || toolsGreen` OR
264+
// credited D4 even when one half was failing). A present row that is not
265+
// green-and-fresh pulls D4 down; D4 is achieved only when at least one
266+
// chat/tools row is present and EVERY present row is green-and-fresh.
267+
if (!isD4Green(live, cell.integration, now)) {
252268
return {
253269
achieved,
254270
maxPossible,

0 commit comments

Comments
 (0)