@@ -172,10 +172,11 @@ function collectGrpcWebEndpoints() {
172172 } ) ;
173173 }
174174 // Remote Prover service
175- if ( service . details . RemoteProverStatus && service . details . RemoteProverStatus . url ) {
175+ const proverUrl = service . details . RemoteProverStatus ?. status ?. url ;
176+ if ( proverUrl ) {
176177 endpoints . push ( {
177- serviceKey : service . details . RemoteProverStatus . url ,
178- baseUrl : service . details . RemoteProverStatus . url ,
178+ serviceKey : proverUrl ,
179+ baseUrl : proverUrl ,
179180 grpcPath : '/remote_prover.ProxyStatusApi/Status' ,
180181 } ) ;
181182 }
@@ -303,55 +304,6 @@ async function fetchStatus() {
303304 }
304305}
305306
306- // Merge Remote Prover status and test entries into a single card per prover.
307- function mergeProverStatusAndTests ( services ) {
308- const testsByName = new Map ( ) ;
309- const merged = [ ] ;
310- const usedTests = new Set ( ) ;
311-
312- services . forEach ( service => {
313- if ( service . details && service . details . RemoteProverTest ) {
314- testsByName . set ( service . name , service ) ;
315- }
316- } ) ;
317-
318- services . forEach ( service => {
319- if ( service . details && service . details . RemoteProverStatus ) {
320- const test = testsByName . get ( service . name ) ;
321- if ( test ) {
322- usedTests . add ( service . name ) ;
323- }
324- merged . push ( {
325- ...service ,
326- testDetails : test ?. details ?. RemoteProverTest ?? null ,
327- testStatus : test ?. status ?? null ,
328- testError : test ?. error ?? null
329- } ) ;
330- } else if ( ! ( service . details && service . details . RemoteProverTest ) ) {
331- // Non-prover entries pass through unchanged
332- merged . push ( service ) ;
333- }
334- } ) ;
335-
336- // Add orphaned tests (in case a test arrives before a status)
337- testsByName . forEach ( ( test , name ) => {
338- if ( ! usedTests . has ( name ) ) {
339- merged . push ( {
340- name,
341- status : test . status ,
342- last_checked : test . last_checked ,
343- error : test . error ,
344- details : null ,
345- testDetails : test . details . RemoteProverTest ,
346- testStatus : test . status ,
347- testError : test . error
348- } ) ;
349- }
350- } ) ;
351-
352- return merged ;
353- }
354-
355307function updateDisplay ( ) {
356308 if ( ! statusData ) return ;
357309
@@ -364,29 +316,28 @@ function updateDisplay() {
364316 const lastUpdateTime = new Date ( statusData . last_updated * 1000 ) ;
365317 lastUpdated . textContent = lastUpdateTime . toLocaleString ( ) ;
366318
367- // Group remote prover status + test into single cards
368- const processedServices = mergeProverStatusAndTests ( statusData . services ) ;
369- const rpcService = processedServices . find ( s => s . details && s . details . RpcStatus ) ;
319+ const services = statusData . services ;
320+ const rpcService = services . find ( s => s . details && s . details . RpcStatus ) ;
370321 const rpcChainTip =
371322 rpcService ?. details ?. RpcStatus ?. store_status ?. chain_tip ??
372323 rpcService ?. details ?. RpcStatus ?. block_producer_status ?. chain_tip ??
373324 null ;
374325
375- // Compute effective health for a service, considering all signals for remote provers.
326+ // Compute effective health
376327 const isServiceHealthy = ( s ) => {
377- if ( s . details && s . details . RemoteProverStatus ) {
378- const statusOk = s . status === 'Healthy' ;
379- const testOk = s . testStatus == null || s . testStatus === 'Healthy' ;
380- const probeResult = grpcWebProbeResults . get ( s . details . RemoteProverStatus . url ) ;
381- const probeOk = ! probeResult || probeResult . ok ;
382- return statusOk && testOk && probeOk ;
328+ if ( s . status !== 'Healthy' ) return false ;
329+ const probeUrl = s . details ?. RemoteProverStatus ?. status ?. url
330+ ?? s . details ?. RpcStatus ?. url ;
331+ if ( probeUrl ) {
332+ const probe = grpcWebProbeResults . get ( probeUrl ) ;
333+ if ( probe && ! probe . ok ) return false ;
383334 }
384- return s . status === 'Healthy' ;
335+ return true ;
385336 } ;
386337
387338 // Count healthy vs unhealthy services
388- const healthyServices = processedServices . filter ( isServiceHealthy ) . length ;
389- const totalServices = processedServices . length ;
339+ const healthyServices = services . filter ( isServiceHealthy ) . length ;
340+ const totalServices = services . length ;
390341 const allHealthy = healthyServices === totalServices ;
391342
392343 // Update footer
@@ -404,7 +355,7 @@ function updateDisplay() {
404355 }
405356
406357 // Generate status cards
407- const serviceCardsHtml = processedServices . map ( service => {
358+ const serviceCardsHtml = services . map ( service => {
408359 const isHealthy = isServiceHealthy ( service ) ;
409360 const statusColor = isHealthy ? COLOR_HEALTHY : COLOR_UNHEALTHY ;
410361 const statusIcon = isHealthy ? '✓' : '✗' ;
@@ -499,24 +450,32 @@ function updateDisplay() {
499450 </div>
500451 ` : '' }
501452 ` : '' }
502- ${ details . RemoteProverStatus ? `
503- <div class="detail-item"><strong>URL:</strong> ${ details . RemoteProverStatus . url } ${ renderCopyButton ( details . RemoteProverStatus . url , 'URL' ) } </div>
504- <div class="detail-item"><strong>Version:</strong> ${ details . RemoteProverStatus . version } </div>
505- <div class="detail-item"><strong>Proof Type:</strong> ${ details . RemoteProverStatus . supported_proof_type } </div>
506- ${ renderGrpcWebProbeSection ( details . RemoteProverStatus . url ) }
507- ${ details . RemoteProverStatus . workers && details . RemoteProverStatus . workers . length > 0 ? `
508- <div class="nested-status">
509- <strong>Workers (${ details . RemoteProverStatus . workers . length } ):</strong>
510- ${ details . RemoteProverStatus . workers . map ( worker => `
511- <div class="worker-status">
512- <span class="worker-name">${ worker . name } </span> -
513- <span class="worker-version">${ worker . version } </span> -
514- <span class="worker-status-badge ${ worker . status === 'Healthy' ? 'healthy' : worker . status === 'Unhealthy' ? 'unhealthy' : 'unknown' } ">${ worker . status } </span>
515- </div>
516- ` ) . join ( '' ) }
517- </div>
518- ` : '' }
519- ` : '' }
453+ ${ details . RemoteProverStatus ? ( ( ) => {
454+ const p = details . RemoteProverStatus . status ;
455+ return `
456+ <div class="detail-item"><strong>URL:</strong> ${ p . url } ${ renderCopyButton ( p . url , 'URL' ) } </div>
457+ <div class="detail-item"><strong>Version:</strong> ${ p . version } </div>
458+ <div class="detail-item"><strong>Proof Type:</strong> ${ p . supported_proof_type } </div>
459+ ${ renderGrpcWebProbeSection ( p . url ) }
460+ ${ p . workers && p . workers . length > 0 ? `
461+ <div class="nested-status">
462+ <strong>Workers (${ p . workers . length } ):</strong>
463+ ${ p . workers . map ( worker => {
464+ const nameDisplay = worker . name . length > 20
465+ ? `${ worker . name . substring ( 0 , 20 ) } ...${ renderCopyButton ( worker . name , 'worker name' ) } `
466+ : worker . name ;
467+ return `
468+ <div class="worker-status">
469+ <span class="worker-name">${ nameDisplay } </span>
470+ <span class="worker-version">${ worker . version } </span>
471+ <span class="worker-status-badge ${ worker . status === 'Healthy' ? 'healthy' : worker . status === 'Unhealthy' ? 'unhealthy' : 'unknown' } ">${ worker . status } </span>
472+ </div>
473+ ` ;
474+ } ) . join ( '' ) }
475+ </div>
476+ ` : '' }
477+ ` ;
478+ } ) ( ) : '' }
520479 ${ details . FaucetTest ? `
521480 <div class="nested-status">
522481 <strong>Faucet:</strong>
@@ -683,25 +642,29 @@ function updateDisplay() {
683642 </div>
684643 </div>
685644 ` : '' }
686- ${ service . testDetails ? `
687- <div class="nested-status">
688- <strong>Proof Generation Testing (${ service . testDetails . proof_type } ):</strong>
689- <div class="test-metrics ${ service . testStatus === 'Healthy' ? 'healthy' : 'unhealthy' } ">
690- <div class="metric-row">
691- <span class="metric-label">Success Rate:</span>
692- <span class="metric-value">${ formatSuccessRate ( service . testDetails . success_count , service . testDetails . failure_count ) } </span>
693- </div>
694- <div class="metric-row">
695- <span class="metric-label">Last Response Time:</span>
696- <span class="metric-value">${ service . testDetails . test_duration_ms } ms</span>
697- </div>
698- <div class="metric-row">
699- <span class="metric-label">Last Proof Size:</span>
700- <span class="metric-value">${ ( service . testDetails . proof_size_bytes / 1024 ) . toFixed ( 2 ) } KB</span>
645+ ${ details . RemoteProverStatus ?. test ? ( ( ) => {
646+ const t = details . RemoteProverStatus . test . details ;
647+ const ts = details . RemoteProverStatus . test . status ;
648+ return `
649+ <div class="nested-status">
650+ <strong>Proof Generation Testing (${ t . proof_type } ):</strong>
651+ <div class="test-metrics ${ ts === 'Healthy' ? 'healthy' : 'unhealthy' } ">
652+ <div class="metric-row">
653+ <span class="metric-label">Success Rate:</span>
654+ <span class="metric-value">${ formatSuccessRate ( t . success_count , t . failure_count ) } </span>
655+ </div>
656+ <div class="metric-row">
657+ <span class="metric-label">Last Response Time:</span>
658+ <span class="metric-value">${ t . test_duration_ms } ms</span>
659+ </div>
660+ <div class="metric-row">
661+ <span class="metric-label">Last Proof Size:</span>
662+ <span class="metric-value">${ ( t . proof_size_bytes / 1024 ) . toFixed ( 2 ) } KB</span>
663+ </div>
701664 </div>
702665 </div>
703- </div>
704- ` : '' }
666+ ` ;
667+ } ) ( ) : '' }
705668 </div>
706669 ` ;
707670 }
@@ -864,4 +827,3 @@ window.addEventListener('beforeunload', () => {
864827 clearInterval ( grpcWebProbeInterval ) ;
865828 }
866829} ) ;
867-
0 commit comments