Skip to content

Commit 6146f65

Browse files
authored
revert(ui): restore previous QA trial display (#1146)
1 parent 8f0ecb2 commit 6146f65

3 files changed

Lines changed: 19 additions & 167 deletions

File tree

frontend/src/components/experiment-trials-table.tsx

Lines changed: 16 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -76,15 +76,11 @@ import {
7676
taskHasCancellableWork,
7777
} from "@/lib/job-status";
7878
import {
79-
ANALYSIS_CLASSIFICATION_LABELS,
8079
formatPartialRewardBadgeValue,
8180
formatRewardPercent,
8281
formatRewardValue,
8382
getMatrixStatus,
84-
getQaGlyphMatrixClass,
8583
getRewardStyle,
86-
getVisibleAnalysisClassification,
87-
QA_TONE_MATRIX_CLASS,
8884
STATUS_CONFIG,
8985
STATUS_GLYPH_BOX,
9086
type MatrixStatus,
@@ -335,12 +331,12 @@ const ANALYSIS_LEGEND_ITEMS: Array<{
335331
},
336332
{
337333
key: "good",
338-
label: "Good",
334+
label: "Pass",
339335
dotClass: ANALYSIS_CONFIG.GOOD_SUCCESS.dotClass,
340336
},
341337
{
342338
key: "bad",
343-
label: "Bad",
339+
label: "Fail",
344340
dotClass: ANALYSIS_CONFIG.BAD_SUCCESS.dotClass,
345341
},
346342
{
@@ -1566,22 +1562,6 @@ export function ExperimentTrialsTable({
15661562
"analysis-failed": "var(--paper-a-failed)",
15671563
};
15681564

1569-
// Good/bad chips show the tone painted on both outcome shapes — a ✓✗
1570-
// pair — so the legend teaches the cell semiotics (shape = outcome,
1571-
// color = QA verdict) instead of implying green means "pass".
1572-
const renderToneGlyphPair = (tone: "good" | "bad") => (
1573-
<span className="inline-flex items-center gap-[2px]">
1574-
{(["pass", "fail"] as const).map((shape) => (
1575-
<span
1576-
key={shape}
1577-
className={`inline-flex h-[14px] w-[16px] items-center justify-center rounded-[3px] border ${QA_TONE_MATRIX_CLASS[tone]}`}
1578-
>
1579-
<StatusIcon status={shape} className="h-2 w-2" />
1580-
</span>
1581-
))}
1582-
</span>
1583-
);
1584-
15851565
const renderAnalyzerChip = (item: (typeof ANALYSIS_LEGEND_ITEMS)[number]) => {
15861566
const isDimmed = dimmedAnalysisKeys.has(item.key);
15871567
return (
@@ -1595,14 +1575,10 @@ export function ExperimentTrialsTable({
15951575
isDimmed ? "line-through opacity-[0.38]" : ""
15961576
}`}
15971577
>
1598-
{item.key === "good" || item.key === "bad" ? (
1599-
renderToneGlyphPair(item.key)
1600-
) : (
1601-
<span
1602-
className={`inline-block h-2 w-2 rounded-full ${item.animate ? "animate-pulse" : ""}`}
1603-
style={{ background: ANALYZER_CHIP_COLOR[item.key] }}
1604-
/>
1605-
)}
1578+
<span
1579+
className={`inline-block h-2 w-2 rounded-full ${item.animate ? "animate-pulse" : ""}`}
1580+
style={{ background: ANALYZER_CHIP_COLOR[item.key] }}
1581+
/>
16061582
<span>{item.label}</span>
16071583
</Button>
16081584
</TooltipTrigger>
@@ -1617,46 +1593,31 @@ export function ExperimentTrialsTable({
16171593
<Tooltip>
16181594
<TooltipTrigger asChild>
16191595
<div className="flex items-center gap-2.5 border-r border-dashed border-[color:var(--paper-line)] pr-2.5 pl-1.5 font-mono text-[9.5px] leading-tight text-[color:var(--paper-ink-3)]">
1620-
<span className="relative inline-flex gap-[3px]">
1596+
<span className="relative inline-flex">
16211597
<span
16221598
className={`flex items-center justify-center border-transparent bg-[color:var(--paper-pass)] text-white ${STATUS_GLYPH_BOX}`}
16231599
>
16241600
<StatusIcon status="pass" />
16251601
</span>
1626-
<span
1627-
className={`flex items-center justify-center border-transparent text-white ${STATUS_GLYPH_BOX} ${
1628-
showAnalysis
1629-
? "bg-[color:var(--paper-pass)]"
1630-
: "bg-[color:var(--paper-fail)]"
1631-
}`}
1632-
>
1633-
<StatusIcon status="fail" />
1634-
</span>
16351602
{showAnalysis && (
1636-
<span className="absolute -top-[2px] -right-[2px] h-[7px] w-[7px] animate-pulse rounded-full bg-[color:var(--paper-a-analyzing)] ring-[1.5px] ring-[color:var(--paper-surface)]" />
1603+
<span className="absolute -top-[2px] -right-[2px] h-[7px] w-[7px] rounded-full bg-[color:var(--paper-a-good)] ring-[1.5px] ring-[color:var(--paper-surface)]" />
16371604
)}
16381605
</span>
16391606
<span className="flex flex-col gap-0.5">
16401607
<span className="inline-flex items-center gap-1.5 whitespace-nowrap">
1641-
<StatusIcon status="pass" className="h-2.5 w-2.5" />
1642-
<StatusIcon status="fail" className="h-2.5 w-2.5" />
1643-
shape = trial result
1608+
<span className="inline-block h-2.5 w-2.5 rounded-[2px] bg-[color:var(--paper-pass)]" />
1609+
trial result
16441610
</span>
16451611
{showAnalysis && (
16461612
<span className="inline-flex items-center gap-1.5 whitespace-nowrap">
1647-
<span className="inline-block h-2.5 w-2.5 rounded-[2px] bg-[color:var(--paper-pass)]" />
1648-
<span className="inline-block h-2.5 w-2.5 rounded-[2px] bg-[color:var(--paper-fail)]" />
1649-
color = QA verdict
1613+
<span className="mx-[1px] inline-block h-2 w-2 rounded-full bg-[color:var(--paper-a-good)]" />
1614+
QA result
16501615
</span>
16511616
)}
16521617
</span>
16531618
</div>
16541619
</TooltipTrigger>
1655-
<TooltipContent>
1656-
How to read a cell: ✓/✗ is the trial outcome; once QA classifies a
1657-
trial, green means the outcome is good (expected) and red means bad — a
1658-
green ✗ is a good failure. A pulsing dot means QA is still running.
1659-
</TooltipContent>
1620+
<TooltipContent>How to read a cell</TooltipContent>
16601621
</Tooltip>
16611622
);
16621623

@@ -2474,26 +2435,6 @@ export function ExperimentTrialsTable({
24742435
dimmedAnalysisKeys.has(analysisLegendKey)
24752436
? "opacity-25"
24762437
: "";
2477-
// A classified binary outcome takes its QA
2478-
// tone as the glyph fill: shape = outcome,
2479-
// color = QA verdict. A good failure is a
2480-
// green ✗, a bad success a red ✓. The
2481-
// classification (and with it the fill and
2482-
// label) is null when QA is hidden.
2483-
const classification =
2484-
getVisibleAnalysisClassification(
2485-
showAnalysis,
2486-
trial
2487-
);
2488-
const qaGlyphClass = getQaGlyphMatrixClass(
2489-
status,
2490-
classification
2491-
);
2492-
const cellLabel = classification
2493-
? ANALYSIS_CLASSIFICATION_LABELS[
2494-
classification
2495-
]
2496-
: config.shortLabel;
24972438
const baseTitle = getTrialTitle(
24982439
trial,
24992440
status
@@ -2535,9 +2476,9 @@ export function ExperimentTrialsTable({
25352476
trialGroups,
25362477
});
25372478
}}
2538-
className={`relative grid place-items-center gap-0 p-0 leading-none transition-transform hover:-translate-y-px ${STATUS_GLYPH_BOX} ${qaGlyphClass ?? config.matrixClass} ${isPartial ? "font-mono text-[9.5px] font-semibold tracking-[-0.02em] tabular-nums" : ""}`}
2479+
className={`relative grid place-items-center gap-0 p-0 leading-none transition-transform hover:-translate-y-px ${STATUS_GLYPH_BOX} ${config.matrixClass} ${isPartial ? "font-mono text-[9.5px] font-semibold tracking-[-0.02em] tabular-nums" : ""}`}
25392480
style={getRewardStyle(trial.reward)}
2540-
aria-label={`Trial ${trialIndex + 1} ${cellLabel}`}
2481+
aria-label={`Trial ${trialIndex + 1} ${config.shortLabel}`}
25412482
title={fullTitle}
25422483
>
25432484
{isPartial ? (
@@ -2546,7 +2487,7 @@ export function ExperimentTrialsTable({
25462487
<StatusIcon status={status} />
25472488
)}
25482489
</Button>
2549-
{analysisIndicator && !qaGlyphClass && (
2490+
{analysisIndicator && (
25502491
<span
25512492
aria-hidden="true"
25522493
className={`pointer-events-none absolute -top-[1px] -right-[1px] h-[4px] w-[4px] rounded-full ring-[1px] ring-[color:var(--paper-surface)] ${analysisIndicator.dotClass} ${analysisIndicator.animate ? "animate-pulse" : ""}`}

frontend/src/components/trial-detail-panel.tsx

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,11 @@ import {
7474
sumTaskTrialCost,
7575
} from "@/lib/format";
7676
import {
77-
ANALYSIS_CLASSIFICATION_LABELS,
7877
formatPartialRewardBadgeValue,
7978
formatRewardPercent,
8079
formatRewardValue,
8180
getMatrixStatus,
82-
getQaGlyphMatrixClass,
8381
getRewardStyle,
84-
getVisibleAnalysisClassification,
8582
STATUS_CONFIG,
8683
STATUS_GLYPH_BOX,
8784
type MatrixStatus,
@@ -1258,21 +1255,6 @@ export function TrialDetailPanel({
12581255
groupTrial.error_message,
12591256
);
12601257
const groupConfig = STATUS_CONFIG[groupStatus];
1261-
// Same cell semiotics as the experiment matrix: a
1262-
// classified binary outcome takes its QA tone as the
1263-
// glyph fill (good failure = green ✗, bad success = red ✓).
1264-
// The shared gate keeps QA hidden on public share views.
1265-
const groupClassification = getVisibleAnalysisClassification(
1266-
showAnalysis,
1267-
groupTrial,
1268-
);
1269-
const groupQaGlyphClass = getQaGlyphMatrixClass(
1270-
groupStatus,
1271-
groupClassification,
1272-
);
1273-
const groupLabel = groupClassification
1274-
? ANALYSIS_CLASSIFICATION_LABELS[groupClassification]
1275-
: groupConfig.shortLabel;
12761258
const isPartial = groupStatus === "partial";
12771259
const partialLabel = isPartial
12781260
? formatPartialRewardBadgeValue(groupTrial.reward)
@@ -1288,7 +1270,7 @@ export function TrialDetailPanel({
12881270
className={cn(
12891271
"flex items-center justify-center p-0 leading-none transition hover:opacity-90",
12901272
STATUS_GLYPH_BOX,
1291-
groupQaGlyphClass ?? groupConfig.matrixClass,
1273+
groupConfig.matrixClass,
12921274
isPartial
12931275
? "font-mono text-[9.5px] font-semibold tracking-[-0.02em] tabular-nums"
12941276
: "",
@@ -1297,8 +1279,8 @@ export function TrialDetailPanel({
12971279
: "",
12981280
)}
12991281
style={getRewardStyle(groupTrial.reward)}
1300-
aria-label={`Trial ${index + 1} ${groupLabel}`}
1301-
title={`${groupLabel} • Trial ${index + 1}`}
1282+
aria-label={`Trial ${index + 1} ${groupConfig.shortLabel}`}
1283+
title={`${groupConfig.shortLabel} • Trial ${index + 1}`}
13021284
>
13031285
{isPartial ? (
13041286
partialLabel

frontend/src/lib/status-config.ts

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import {
1010
} from "lucide-react";
1111
import type { CSSProperties } from "react";
1212

13-
import type { AnalysisClassification, Trial } from "@/lib/types";
14-
1513
/**
1614
* Trial status types that map to visual states in the UI.
1715
* These are derived from trial.status and trial.reward values.
@@ -27,75 +25,6 @@ export type MatrixStatus =
2725
| "queued"
2826
| "running";
2927

30-
/**
31-
* QA judgment tone for a classified trial. The glyph semiotics are:
32-
* shape = execution outcome (✓ pass / ✗ fail), fill color = QA verdict
33-
* (green = good, red = bad). This makes an expected "good failure" render
34-
* as a green ✗ instead of a red ✗ with a nearly-invisible green dot, and
35-
* a "bad success" as a red ✓ instead of an unqualified green ✓.
36-
*/
37-
export type QaTone = "good" | "bad";
38-
39-
/**
40-
* Matrix glyph fill for a QA tone. Reuses the pass/fail paper tokens so a
41-
* recolored cell is indistinguishable in hue from an unclassified one —
42-
* only the shape-vs-color meaning changes.
43-
*/
44-
export const QA_TONE_MATRIX_CLASS: Record<QaTone, string> = {
45-
good: "bg-paper-pass text-white border-paper-pass hover:opacity-90",
46-
bad: "bg-paper-fail text-white border-paper-fail hover:opacity-90",
47-
};
48-
49-
/** Human label per QA classification, shared by every trial-glyph surface. */
50-
export const ANALYSIS_CLASSIFICATION_LABELS: Record<
51-
AnalysisClassification,
52-
string
53-
> = {
54-
GOOD_SUCCESS: "Good success",
55-
GOOD_FAILURE: "Good failure",
56-
BAD_SUCCESS: "Bad success",
57-
BAD_FAILURE: "Bad failure",
58-
HARNESS_ERROR: "Harness error",
59-
};
60-
61-
/**
62-
* The classification a view is allowed to show, or null. This is the ONLY
63-
* place the QA-visibility gate lives: public share surfaces pass
64-
* `showAnalysis: false` to hide QA entirely, and a classification counts
65-
* only once the trial's analysis succeeded. Every glyph fill, label,
66-
* aria-label, and dot consumer must derive from this function so the gate
67-
* cannot drift between surfaces.
68-
*/
69-
export function getVisibleAnalysisClassification(
70-
showAnalysis: boolean,
71-
trial: Pick<Trial, "analysis_status" | "analysis">,
72-
): AnalysisClassification | null {
73-
if (!showAnalysis || trial.analysis_status !== "success") return null;
74-
return trial.analysis?.classification ?? null;
75-
}
76-
77-
/**
78-
* Glyph fill override for a classified trial, or null when the outcome
79-
* glyph keeps its default color. Only binary outcomes (pass/fail) take the
80-
* QA tone; partials keep their warm ramp and non-terminal or non-scored
81-
* states keep their neutral styling, with the QA tone still surfaced
82-
* through the corner dot. GOOD_SUCCESS pass and BAD_FAILURE fail resolve
83-
* to the same color they already had — the rule stays uniform.
84-
*/
85-
export function getQaGlyphMatrixClass(
86-
status: MatrixStatus,
87-
classification: AnalysisClassification | null | undefined
88-
): string | null {
89-
if (status !== "pass" && status !== "fail") return null;
90-
if (classification === "GOOD_SUCCESS" || classification === "GOOD_FAILURE") {
91-
return QA_TONE_MATRIX_CLASS.good;
92-
}
93-
if (classification === "BAD_SUCCESS" || classification === "BAD_FAILURE") {
94-
return QA_TONE_MATRIX_CLASS.bad;
95-
}
96-
return null;
97-
}
98-
9928
/**
10029
* Status configuration for consistent styling across the UI.
10130
*

0 commit comments

Comments
 (0)