Skip to content

Commit f1a7867

Browse files
committed
feat: show application validation badges
1 parent 0c5fbc4 commit f1a7867

7 files changed

Lines changed: 240 additions & 5 deletions

File tree

frontend/src/api/api.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ export interface LeaderboardDetail {
3636
user_name: string;
3737
submission_id: number;
3838
line_count?: number;
39+
validation_status?: "completed" | "failed" | null;
40+
validation_shapes_passed?: number | null;
41+
validation_shapes_total?: number | null;
42+
validation_fully_validated?: boolean | null;
43+
validation_geomean_speedup?: number | null;
44+
validation_contract_version?: string | null;
45+
validation_checked_at?: string | null;
3946
}>
4047
>;
4148
}

frontend/src/pages/leaderboard/Leaderboard.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,62 @@ describe("Leaderboard", () => {
108108
expect(screen.getByText(/custom_kernel/)).toBeInTheDocument();
109109
});
110110

111+
it("shows full and partial application validation badges beside submitters", () => {
112+
const mockData = {
113+
deadline: mockDeadline,
114+
description: mockDescription,
115+
name: mockName,
116+
reference: mockReference,
117+
starter: mockStarter,
118+
gpu_types: ["B200"],
119+
rankings: {
120+
B200: [
121+
{
122+
file_name: "fast.py",
123+
prev_score: 0,
124+
rank: 1,
125+
score: 3.25,
126+
user_name: "stable-user",
127+
submission_id: 101,
128+
validation_status: "completed",
129+
validation_shapes_passed: 8,
130+
validation_shapes_total: 8,
131+
validation_fully_validated: true,
132+
validation_geomean_speedup: 1.4,
133+
validation_contract_version: "v1",
134+
},
135+
{
136+
file_name: "partial.py",
137+
prev_score: 0.1,
138+
rank: 2,
139+
score: 3.5,
140+
user_name: "partial-user",
141+
submission_id: 102,
142+
validation_status: "completed",
143+
validation_shapes_passed: 6,
144+
validation_shapes_total: 8,
145+
validation_fully_validated: false,
146+
validation_geomean_speedup: 1.1,
147+
validation_contract_version: "v1",
148+
},
149+
],
150+
},
151+
};
152+
153+
(apiHook.fetcherApiCallback as ReturnType<typeof vi.fn>).mockReturnValue({
154+
data: mockData,
155+
loading: false,
156+
error: null,
157+
errorStatus: null,
158+
call: mockCall,
159+
});
160+
161+
renderWithRouter(<Leaderboard />);
162+
163+
expect(screen.getByText("VALIDATED")).toBeInTheDocument();
164+
expect(screen.getByText("6/8 VALIDATED")).toBeInTheDocument();
165+
});
166+
111167
it("shows loading state", () => {
112168
(apiHook.fetcherApiCallback as ReturnType<typeof vi.fn>).mockReturnValue({
113169
data: null,

frontend/src/pages/leaderboard/components/RankingLists.tsx

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import { useState } from "react";
22
import {
33
Box,
44
Button,
5+
Chip,
56
Grid,
67
Stack,
8+
Tooltip,
79
type SxProps,
810
type Theme,
911
Typography,
@@ -30,6 +32,13 @@ interface RankingItem {
3032
submission_count?: number;
3133
submission_time?: string;
3234
line_count?: number;
35+
validation_status?: "completed" | "failed" | null;
36+
validation_shapes_passed?: number | null;
37+
validation_shapes_total?: number | null;
38+
validation_fully_validated?: boolean | null;
39+
validation_geomean_speedup?: number | null;
40+
validation_contract_version?: string | null;
41+
validation_checked_at?: string | null;
3342
}
3443

3544
interface RankingsListProps {
@@ -97,6 +106,58 @@ const styles: Record<string, SxProps<Theme>> = {
97106
},
98107
};
99108

109+
function ValidationBadge({ item }: { item: RankingItem }) {
110+
if (!item.validation_status) return null;
111+
112+
const passed = item.validation_shapes_passed ?? 0;
113+
const total = item.validation_shapes_total ?? 0;
114+
const fullyValidated =
115+
item.validation_status === "completed" &&
116+
item.validation_fully_validated === true &&
117+
total > 0 &&
118+
passed === total;
119+
const failed = item.validation_status === "failed";
120+
const label = fullyValidated
121+
? "VALIDATED"
122+
: failed
123+
? "VALIDATION ERROR"
124+
: `${passed}/${total} VALIDATED`;
125+
const speedup =
126+
typeof item.validation_geomean_speedup === "number"
127+
? ` Geomean synchronized-wall speedup across measured shapes: ${item.validation_geomean_speedup.toFixed(2)}×.`
128+
: "";
129+
const contract = item.validation_contract_version
130+
? ` Contract: ${item.validation_contract_version}.`
131+
: "";
132+
const checked = item.validation_checked_at
133+
? ` Checked ${new Date(item.validation_checked_at).toLocaleString()}.`
134+
: "";
135+
const tooltip = fullyValidated
136+
? `All ${passed}/${total} training shapes passed the convergence, numerical, fallback, and speed gates.${speedup}${contract}${checked}`
137+
: failed
138+
? `The validation job failed before it could complete.${contract}${checked}`
139+
: `${passed}/${total} training shapes passed the convergence, numerical, fallback, and speed gates.${speedup}${contract}${checked}`;
140+
141+
return (
142+
<Tooltip title={tooltip}>
143+
<Chip
144+
label={label}
145+
color={fullyValidated ? "success" : failed ? "error" : "warning"}
146+
size="small"
147+
variant={fullyValidated ? "filled" : "outlined"}
148+
data-testid={`validation-badge-${item.submission_id}`}
149+
sx={{
150+
height: 20,
151+
fontSize: "0.65rem",
152+
fontWeight: 800,
153+
letterSpacing: "0.03em",
154+
flexShrink: 0,
155+
}}
156+
/>
157+
</Tooltip>
158+
);
159+
}
160+
100161
export default function RankingsList({
101162
rankings,
102163
leaderboardId,
@@ -205,9 +266,19 @@ export default function RankingsList({
205266
<Grid size={3}>
206267
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
207268
<Typography sx={styles.rank}>{item.rank}. </Typography>
208-
<Typography sx={styles.name}>
209-
{item.user_name} {getMedalIcon(item.rank)}
210-
</Typography>
269+
<Box
270+
sx={{
271+
display: "flex",
272+
alignItems: "center",
273+
gap: 0.75,
274+
minWidth: 0,
275+
}}
276+
>
277+
<Typography sx={styles.name}>
278+
{item.user_name} {getMedalIcon(item.rank)}
279+
</Typography>
280+
<ValidationBadge item={item} />
281+
</Box>
211282
</Box>
212283
</Grid>
213284
<Grid size={scoreSize}>

kernelboard/api/leaderboard.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,38 @@ def _get_query():
265265
s.file_name AS file_name,
266266
r.submission_id AS submission_id,
267267
COALESCE(sc.submission_count, 0) AS submission_count,
268+
validation.status AS validation_status,
269+
validation.passed_shapes AS validation_shapes_passed,
270+
validation.total_shapes AS validation_shapes_total,
271+
validation.fully_validated AS validation_fully_validated,
272+
validation.geomean_sync_wall_speedup AS validation_geomean_speedup,
273+
validation.contract_version AS validation_contract_version,
274+
validation.checked_at AS validation_checked_at,
268275
RANK() OVER (PARTITION BY r.runner, u.id ORDER BY r.score ASC) AS rank
269276
FROM leaderboard.runs r
270277
JOIN leaderboard.submission s ON r.submission_id = s.id
271278
LEFT JOIN leaderboard.user_info u ON s.user_id = u.id
272279
LEFT JOIN submission_counts sc ON s.user_id = sc.user_id AND r.runner = sc.runner
280+
LEFT JOIN LATERAL (
281+
SELECT
282+
status,
283+
passed_shapes,
284+
total_shapes,
285+
fully_validated,
286+
geomean_sync_wall_speedup,
287+
contract_version,
288+
checked_at
289+
FROM leaderboard.submission_validation
290+
WHERE submission_id = s.id
291+
AND gpu_type = r.runner
292+
AND contract_version = (
293+
SELECT task->'validation'->>'version'
294+
FROM leaderboard.leaderboard
295+
WHERE id = %(leaderboard_id)s
296+
)
297+
ORDER BY checked_at DESC
298+
LIMIT 1
299+
) validation ON TRUE
273300
WHERE NOT r.secret
274301
AND r.score IS NOT NULL
275302
AND r.passed
@@ -312,7 +339,14 @@ def _get_query():
312339
'file_name', r.file_name,
313340
'submission_id', r.submission_id,
314341
'submission_count', r.submission_count,
315-
'submission_time', r.submission_time
342+
'submission_time', r.submission_time,
343+
'validation_status', r.validation_status,
344+
'validation_shapes_passed', r.validation_shapes_passed,
345+
'validation_shapes_total', r.validation_shapes_total,
346+
'validation_fully_validated', r.validation_fully_validated,
347+
'validation_geomean_speedup', r.validation_geomean_speedup,
348+
'validation_contract_version', r.validation_contract_version,
349+
'validation_checked_at', r.validation_checked_at
316350
)
317351
ORDER BY r.score ASC
318352
)

tests/api/test_leaderboard_api.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,54 @@ def test_active_leaderboard_omits_line_counts(client, app):
4949
assert all("line_count" not in item for item in ranked_items)
5050

5151

52+
def test_leaderboard_includes_latest_validation_summary(client, app):
53+
initial = client.get("/api/leaderboard/339").get_json()
54+
gpu_type, rankings = next(iter(initial["data"]["rankings"].items()))
55+
submission_id = rankings[0]["submission_id"]
56+
57+
with app.app_context():
58+
conn = get_db_connection()
59+
with conn.cursor() as cur:
60+
cur.execute(
61+
"""
62+
UPDATE leaderboard.leaderboard
63+
SET task = jsonb_set(
64+
task,
65+
'{validation}',
66+
'{"version": "v1"}'::jsonb
67+
)
68+
WHERE id = 339
69+
"""
70+
)
71+
cur.execute(
72+
"""
73+
INSERT INTO leaderboard.submission_validation (
74+
submission_id, gpu_type, contract_name, contract_version,
75+
status, passed_shapes, total_shapes, fully_validated,
76+
geomean_sync_wall_speedup, result
77+
)
78+
VALUES (%s, %s, 'natural-gradient-training', 'v1',
79+
'completed', 8, 8, TRUE, 1.25, '{}')
80+
""",
81+
(submission_id, gpu_type),
82+
)
83+
conn.commit()
84+
85+
response = client.get("/api/leaderboard/339")
86+
assert response.status_code == 200
87+
validated = next(
88+
item
89+
for item in response.get_json()["data"]["rankings"][gpu_type]
90+
if item["submission_id"] == submission_id
91+
)
92+
assert validated["validation_status"] == "completed"
93+
assert validated["validation_shapes_passed"] == 8
94+
assert validated["validation_shapes_total"] == 8
95+
assert validated["validation_fully_validated"] is True
96+
assert validated["validation_geomean_speedup"] == 1.25
97+
assert validated["validation_contract_version"] == "v1"
98+
99+
52100
def test_leaderboard_line_counts_support_bytea_code_storage(client, app):
53101
with app.app_context():
54102
conn = get_db_connection()

tests/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import random
23
import secrets
34
import string
@@ -131,7 +132,7 @@ def db_server():
131132
"-f",
132133
"tests/data.sql",
133134
],
134-
env={"PGPASSWORD": password},
135+
env={**os.environ, "PGPASSWORD": password},
135136
)
136137

137138
if result.returncode != 0:

tests/data.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9219,6 +9219,24 @@ CREATE TABLE IF NOT EXISTS leaderboard.submission_job_status (
92199219
CONSTRAINT uq_submission_job_status_submission_id
92209220
UNIQUE (submission_id) -- one-to-one with submission
92219221
);
9222+
9223+
CREATE TABLE IF NOT EXISTS leaderboard.submission_validation (
9224+
id BIGSERIAL PRIMARY KEY,
9225+
submission_id INTEGER NOT NULL
9226+
REFERENCES leaderboard.submission(id) ON DELETE CASCADE,
9227+
gpu_type TEXT NOT NULL,
9228+
contract_name TEXT NOT NULL,
9229+
contract_version TEXT NOT NULL,
9230+
status TEXT NOT NULL CHECK (status IN ('completed', 'failed')),
9231+
passed_shapes INTEGER NOT NULL DEFAULT 0,
9232+
total_shapes INTEGER NOT NULL DEFAULT 0,
9233+
fully_validated BOOLEAN NOT NULL DEFAULT FALSE,
9234+
geomean_sync_wall_speedup DOUBLE PRECISION,
9235+
result JSONB NOT NULL DEFAULT '{}'::jsonb,
9236+
error TEXT,
9237+
checked_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
9238+
UNIQUE (submission_id, gpu_type, contract_version)
9239+
);
92229240
--
92239241
-- PostgreSQL database dump complete
92249242
--

0 commit comments

Comments
 (0)