@@ -2,8 +2,10 @@ import { useState } from "react";
22import {
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
3544interface 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+
100161export 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 } >
0 commit comments