@@ -65,6 +65,20 @@ function rawRow(overrides: Record<string, unknown> = {}): Record<string, unknown
6565 } ;
6666}
6767
68+ /** Minimal valid agentic row: scenario_type triggers the agentic path; `users` → conc. */
69+ function rawAgenticRow ( overrides : Record < string , unknown > = { } ) : Record < string , unknown > {
70+ return {
71+ infmax_model_prefix : 'dsv4' ,
72+ hw : 'mi355x-amds' ,
73+ framework : 'vllm' ,
74+ precision : 'fp4' ,
75+ scenario_type : 'agentic-coding' ,
76+ users : 72 ,
77+ tput_per_gpu : 20000 ,
78+ ...overrides ,
79+ } ;
80+ }
81+
6882function rawEvalRow ( overrides : Record < string , unknown > = { } ) : Record < string , unknown > {
6983 return {
7084 hw : 'gb300-nv' ,
@@ -437,6 +451,158 @@ describe('GET /api/unofficial-run', () => {
437451 expect ( body . evaluations ) . toEqual ( [ ] ) ;
438452 } ) ;
439453
454+ it ( 'falls back to per-config bmk_* artifacts when results_bmk is missing (agentic-only sweeps)' , async ( ) => {
455+ // Run metadata
456+ mockFetch . mockResolvedValueOnce ( {
457+ ok : true ,
458+ json : ( ) =>
459+ Promise . resolve ( {
460+ id : 777 ,
461+ name : 'agentic-run' ,
462+ head_branch : 'amd/agentx' ,
463+ head_sha : 'ccc' ,
464+ created_at : '2026-07-07T00:00:00Z' ,
465+ html_url : 'http://github.com/run/777' ,
466+ conclusion : 'success' ,
467+ status : 'completed' ,
468+ } ) ,
469+ } ) ;
470+ // Artifacts: no results_bmk — only per-config agentic artifacts (plus the
471+ // big sibling `agentic_*` trace blobs the route must NOT download).
472+ mockFetch . mockResolvedValueOnce ( {
473+ ok : true ,
474+ json : ( ) =>
475+ Promise . resolve ( {
476+ artifacts : [
477+ { name : 'bmk_agentic_dsv4_conc72' , id : 30 , archive_download_url : 'http://dl-a' } ,
478+ { name : 'bmk_agentic_dsv4_conc56' , id : 31 , archive_download_url : 'http://dl-b' } ,
479+ { name : 'agentic_dsv4_conc72' , id : 32 , archive_download_url : 'http://dl-blob' } ,
480+ { name : 'server_logs_dsv4_conc72' , id : 33 , archive_download_url : 'http://dl-log' } ,
481+ ] ,
482+ } ) ,
483+ } ) ;
484+ // Two per-config downloads (Promise.all order matches artifact order)
485+ mockFetch . mockResolvedValueOnce ( {
486+ ok : true ,
487+ arrayBuffer : ( ) => Promise . resolve ( new ArrayBuffer ( 8 ) ) ,
488+ } ) ;
489+ mockFetch . mockResolvedValueOnce ( {
490+ ok : true ,
491+ arrayBuffer : ( ) => Promise . resolve ( new ArrayBuffer ( 8 ) ) ,
492+ } ) ;
493+ mockGetEntries
494+ . mockReturnValueOnce ( [
495+ {
496+ entryName : 'dsv4_conc72.json' ,
497+ getData : ( ) => Buffer . from ( JSON . stringify ( rawAgenticRow ( ) ) ) ,
498+ } ,
499+ ] )
500+ . mockReturnValueOnce ( [
501+ {
502+ entryName : 'dsv4_conc56.json' ,
503+ getData : ( ) => Buffer . from ( JSON . stringify ( rawAgenticRow ( { users : 56 } ) ) ) ,
504+ } ,
505+ ] ) ;
506+
507+ const res = await GET ( makeRequest ( 'runId=777' ) ) ;
508+ expect ( res . status ) . toBe ( 200 ) ;
509+ const body = await res . json ( ) ;
510+ expect ( body . benchmarks ) . toHaveLength ( 2 ) ;
511+ expect (
512+ body . benchmarks
513+ . map ( ( b : { conc : number } ) => b . conc )
514+ . toSorted ( ( a : number , b : number ) => a - b ) ,
515+ ) . toEqual ( [ 56 , 72 ] ) ;
516+ expect ( body . benchmarks [ 0 ] . benchmark_type ) . toBe ( 'agentic_traces' ) ;
517+ expect ( body . benchmarks [ 0 ] . hardware ) . toBe ( 'mi355x' ) ;
518+ expect ( body . benchmarks [ 0 ] . run_url ) . toBe ( 'http://github.com/run/777' ) ;
519+ // Only the two bmk_* artifacts were downloaded: run + artifacts + 2 downloads.
520+ expect ( mockFetch ) . toHaveBeenCalledTimes ( 4 ) ;
521+ } ) ;
522+
523+ it ( 'does not download per-config bmk_* artifacts when results_bmk exists' , async ( ) => {
524+ mockFetch . mockResolvedValueOnce ( {
525+ ok : true ,
526+ json : ( ) =>
527+ Promise . resolve ( {
528+ id : 888 ,
529+ head_branch : 'main' ,
530+ html_url : 'http://github.com/run/888' ,
531+ created_at : '2026-07-07T00:00:00Z' ,
532+ } ) ,
533+ } ) ;
534+ // Merged artifact alongside per-config ones (mixed fixed-seq + agentic
535+ // sweep) — the merged artifact already contains the per-config rows.
536+ mockFetch . mockResolvedValueOnce ( {
537+ ok : true ,
538+ json : ( ) =>
539+ Promise . resolve ( {
540+ artifacts : [
541+ { name : 'results_bmk' , id : 40 , archive_download_url : 'http://dl-merged' } ,
542+ { name : 'bmk_agentic_dsv4_conc72' , id : 41 , archive_download_url : 'http://dl-a' } ,
543+ ] ,
544+ } ) ,
545+ } ) ;
546+ mockFetch . mockResolvedValueOnce ( {
547+ ok : true ,
548+ arrayBuffer : ( ) => Promise . resolve ( new ArrayBuffer ( 8 ) ) ,
549+ } ) ;
550+ mockGetEntries . mockReturnValueOnce ( [
551+ {
552+ entryName : 'agg_bmk.json' ,
553+ getData : ( ) => Buffer . from ( JSON . stringify ( [ rawRow ( ) , rawAgenticRow ( ) ] ) ) ,
554+ } ,
555+ ] ) ;
556+
557+ const res = await GET ( makeRequest ( 'runId=888' ) ) ;
558+ expect ( res . status ) . toBe ( 200 ) ;
559+ const body = await res . json ( ) ;
560+ expect ( body . benchmarks ) . toHaveLength ( 2 ) ;
561+ // Exactly one download (the merged artifact) — per-config was skipped.
562+ expect ( mockFetch ) . toHaveBeenCalledTimes ( 3 ) ;
563+ } ) ;
564+
565+ it ( 'keeps only the newest per-config artifact when names repeat' , async ( ) => {
566+ mockFetch . mockResolvedValueOnce ( {
567+ ok : true ,
568+ json : ( ) =>
569+ Promise . resolve ( {
570+ id : 999 ,
571+ head_branch : 'feature/agentic' ,
572+ html_url : 'http://github.com/run/999' ,
573+ created_at : '2026-07-07T00:00:00Z' ,
574+ } ) ,
575+ } ) ;
576+ mockFetch . mockResolvedValueOnce ( {
577+ ok : true ,
578+ json : ( ) =>
579+ Promise . resolve ( {
580+ artifacts : [
581+ { name : 'bmk_agentic_dsv4_conc72' , id : 50 , archive_download_url : 'http://dl-old' } ,
582+ { name : 'bmk_agentic_dsv4_conc72' , id : 51 , archive_download_url : 'http://dl-new' } ,
583+ ] ,
584+ } ) ,
585+ } ) ;
586+ mockFetch . mockResolvedValueOnce ( {
587+ ok : true ,
588+ arrayBuffer : ( ) => Promise . resolve ( new ArrayBuffer ( 8 ) ) ,
589+ } ) ;
590+ mockGetEntries . mockReturnValueOnce ( [
591+ {
592+ entryName : 'dsv4_conc72.json' ,
593+ getData : ( ) => Buffer . from ( JSON . stringify ( rawAgenticRow ( ) ) ) ,
594+ } ,
595+ ] ) ;
596+
597+ const res = await GET ( makeRequest ( 'runId=999' ) ) ;
598+ expect ( res . status ) . toBe ( 200 ) ;
599+ const body = await res . json ( ) ;
600+ expect ( body . benchmarks ) . toHaveLength ( 1 ) ;
601+ // Three fetches total; the single download hit the newest artifact URL.
602+ expect ( mockFetch ) . toHaveBeenCalledTimes ( 3 ) ;
603+ expect ( mockFetch . mock . calls [ 2 ] [ 0 ] ) . toBe ( 'http://dl-new' ) ;
604+ } ) ;
605+
440606 it ( 'returns evaluations for eval-only runs' , async ( ) => {
441607 const evalData = [ rawEvalRow ( ) ] ;
442608
0 commit comments