const timelineRenderState={}; const activityFeedState={lastItems:[],runId:null}; const PROGRESS_TERMINAL_STATUSES=new Set(['done','success','failed','full_inference_success','full_inference_candidate_health_passed','manual_hardware_required','generated_needs_manual_hardware','technical_blocker','technical_blocker_boot_only','health_only','partial','partial_validation','completed_with_warnings','demo_usable_full_promise_not_verified','interactive_app_available_smoke_failed','manual_test_required_smoke_failed','validated','validated_after_space_test','validated_after_manual_space_test','manual_validation_passed','repair_success','repair_failed','succeeded','waiting_manual_action','blocked','stale','cancelled','canceled','stopped','auth_refresh_required']); const PROGRESS_BLOCKING_TERMINAL_STATUSES=new Set(['failed','failure','error','technical_blocker','technical_blocker_boot_only','blocked','manual_hardware_required','generated_needs_manual_hardware','waiting_manual_action','auth_refresh_required','stale','stopped','cancelled','canceled']); const WORKER_STEP_ORDER=[ 'bootstrap','dependencies','auth','model_analysis','workspace','node','pi_install','pi_config','pi_run','pi_model_resolution','pi_verification', 'metadata_sanitize','requirements_sanitize','hardware_strategy','create_space_hardware','create_space','failure_detected','failure_diagnosis','pi_diagnosis','repair_decision','wait_for_logs','factory_rebuild','repair','repair_diagnosis','repair_brief','repair_plan','repair_patch','repair_upload','repair_validation','technical_blocker','manual_hardware_required','upload_files', 'space_runtime','space_logs','api_validation','live_wait','generation_smoke','inference_gate','report_write','done','failure' ]; const COMPACT_TIMELINE_GROUPS=[ {id:'bootstrap',label:'Bootstrap',display_label:'Start',steps:['bootstrap']}, {id:'dependencies',label:'Dependencies',display_label:'Dependencies',steps:['dependencies']}, {id:'auth_model',label:'Auth + model',display_label:'Model access',steps:['auth','model_analysis']}, {id:'workspace_node',label:'Workspace/node',display_label:'Workspace',steps:['workspace','node']}, {id:'pi_setup',label:'Pi setup',display_label:'Agent setup',steps:['pi_install','pi_config']}, {id:'pi_run',label:'Pi run',display_label:'Agent build',steps:['pi_run']}, {id:'pi_verify',label:'Pi verify',display_label:'Agent review',steps:['pi_model_resolution','pi_verification','metadata_sanitize','requirements_sanitize']}, {id:'hardware',label:'Hardware',display_label:'Hardware',steps:['hardware_strategy','create_space_hardware']}, {id:'create_space',label:'Create Space',display_label:'Space',steps:['create_space']}, {id:'upload_runtime',label:'Upload/runtime',display_label:'Deploy',steps:['upload_files','space_runtime','space_logs','live_wait']}, {id:'validation',label:'Validation',display_label:'Live test',steps:['api_validation','generation_smoke','inference_gate']}, {id:'repair',label:'Repair recovery',display_label:'Recovery',steps:['failure_detected','failure_diagnosis','pi_diagnosis','repair_decision','wait_for_logs','factory_rebuild','repair','repair_diagnosis','repair_brief','repair_plan','repair_patch','repair_upload','repair_validation','technical_blocker','manual_hardware_required']}, {id:'report',label:'Report',display_label:'Report',steps:['report_write','done']}, {id:'failure',label:'Failure',display_label:'Failure',terminal_only:true,steps:['failure']} ]; const progressMotionState={lastProgress:null,lastStatus:null,lastStep:null}; const WORKER_STEP_DISPLAY_LABELS={ bootstrap:'start',dependencies:'dependencies',auth:'auth',model_analysis:'model card',workspace:'workspace',node:'node setup', pi_install:'agent install',pi_config:'agent config',pi_run:'agent building',pi_model_resolution:'model routing',pi_verification:'agent check', metadata_sanitize:'metadata check',requirements_sanitize:'requirements check',hardware_strategy:'hardware plan',create_space_hardware:'hardware request', create_space:'space created',upload_files:'files uploaded',space_runtime:'runtime check',space_logs:'logs checked',live_wait:'space live', api_validation:'API check',generation_smoke:'live generation',inference_gate:'inference verdict',failure_detected:'failure detected', failure_diagnosis:'diagnosis',pi_diagnosis:'agent diagnosis',repair_decision:'decision',wait_for_logs:'waiting for logs', factory_rebuild:'same-code rebuild',repair:'repair started',repair_diagnosis:'patch allowed',repair_brief:'repair brief',repair_plan:'repair plan', repair_patch:'patching',repair_upload:'repair uploaded',repair_validation:'repair test',technical_blocker:'blocker',manual_hardware_required:'manual hardware', report_write:'report written',done:'done',failure:'failed' }; function workerStepDisplayLabel(step){return WORKER_STEP_DISPLAY_LABELS[String(step||'')]||String(step||'').replace(/_/g,' ')} const progressStability={runId:null,progress:0,timeline:null,furthestIndex:-1,status:'',currentStep:null}; const elapsedClock={baseSeconds:0,baseAt:0,isRunning:false}; function isFailureStatus(status){ const s=String(status||'').toLowerCase(); return s.includes('failed')||s.includes('error')||s==='failure'||s==='technical_blocker'||s==='technical_blocker_boot_only'||s==='blocked'; } function isSuccessStatus(status){ const s=String(status||'').toLowerCase(); if(PROGRESS_BLOCKING_TERMINAL_STATUSES.has(s)||s.includes('technical_blocker')||s.includes('blocked')||s.includes('failed')||s.includes('error'))return false; return s.includes('success')||s.includes('succeed')||s.includes('passed')||s==='done'||s==='completed'||s==='repair_success'||s==='full_inference_success'; } function isPartialStatus(status){ const s=String(status||'').toLowerCase(); return s==='full_inference_candidate_health_passed'||s==='health_only'||s==='partial'||s==='partial_validation'||s==='completed_with_warnings'||s==='demo_usable_full_promise_not_verified'||s==='interactive_app_available_smoke_failed'||s==='manual_test_required_smoke_failed'; } function isStoppedStatus(status){ const s=String(status||'').toLowerCase(); return s==='cancelled'||s==='canceled'||s==='stopped'||s==='blocked'||s==='stale'; } function visualStatusClass(status){ if(isFailureStatus(status))return'error'; if(isPartialStatus(status))return'warn'; if(isStoppedStatus(status))return'stopped'; if(isSuccessStatus(status))return'success'; const s=String(status||'').toLowerCase(); if(s.includes('running')||s.includes('queued')||s.includes('pending')||s.includes('waiting')||s.includes('building'))return'running'; return'neutral'; } function groupForWorkerStep(step){ return COMPACT_TIMELINE_GROUPS.find(g=>g.steps.includes(String(step||'')))||null; } function latestEventIndexForGroup(group){ if(!group)return -1; let idx=-1; (activityFeedState.lastItems||[]).forEach((event,i)=>{ if(group.steps.includes(String(event.step||'')))idx=i; }); return idx; } function failedEventInfoForGroup(group){ if(!group)return null; let info=null; (activityFeedState.lastItems||[]).forEach((event,i)=>{ if(group.steps.includes(String(event.step||''))&&isFailureStatus(event.status)){ info={event,index:i}; } }); return info; } function failedItemInfoForGroup(group,byStep){ if(!group||!byStep)return null; let info=null; group.steps.forEach((step,i)=>{ const item=byStep.get(step); if(item&&isFailureStatus(item.status))info={event:item,index:i,fromTimeline:true}; }); return info; } function textOfEvent(event={}){ return `${event.step||''} ${event.status||''} ${event.message||''} ${event.hardware||''} ${event.selected_hardware||''} ${event.fallback_hardware||''}`.toLowerCase(); } function isHardwareFallbackEvent(event={}){ const text=textOfEvent(event); return text.includes('fallback')||text.includes('zerogpu')||text.includes('zero gpu')||text.includes('zero-a10g')||text.includes('hardware_fallback')||text.includes('a10g')||text.includes('l40')||text.includes('h200'); } function groupHasHardwareFallback(group){ if(!group||group.id!=='hardware')return false; return (activityFeedState.lastItems||[]).some(event=>group.steps.includes(String(event.step||''))&&isHardwareFallbackEvent(event)); } function isExpectedFallbackFailure(group,failed){ return Boolean(group&&group.id==='hardware'&&failed&&isHardwareFallbackEvent(failed.event)); } function humanizeHardwareReason(text){ const raw=String(text||'').replace(/\s+/g,' ').trim(); const zero=raw.match(/ZeroGPU Spaces are currently limited to\s*(\d+)\s*per user,?\s*and there are already\s*(\d+)\s*Spaces running on ZeroGPU/i); if(zero){ return `ZeroGPU unavailable: namespace limit reached. ${zero[2]} ZeroGPU Spaces are already running; current limit is ${zero[1]}.`; } return raw; } function compactReasonText(value,max=190){ let text=String(value||'').replace(/\s+/g,' ').trim(); if(!text)return ''; if(text.startsWith('{')){ try{ const parsed=JSON.parse(text); text=parsed.server_message||parsed.hf_error_message||parsed.error||parsed.message||text; }catch(_){} } text=text.replace(/^Bad request:\s*/i,'').trim(); text=text.replace(/^\(Request ID:[^)]+\)\s*/i,'').trim(); text=humanizeHardwareReason(text); return text.length>max?text.slice(0,max-1)+'…':text; } function eventReason(event={}){ const data=event.data||{}; const raw= event.reason|| event.error|| event.error_message|| event.exception|| event.details|| data.reason|| data.hf_error_detail|| data.hf_error_message|| data.error_detail|| data.response_text|| data.response_body|| data.error|| data.exception|| data.details|| event.message|| ''; return compactReasonText(typeof raw==='string'?raw:JSON.stringify(raw)); } function zeroGpuReason(event={}){ const reason=eventReason(event); const lower=reason.toLowerCase(); if(lower.includes('quota')||lower.includes('limit')||lower.includes('capacity')||lower.includes('usage')||lower.includes('exceeded')){ return reason; } if(isHardwareFallbackEvent(event)){ return reason||'ZeroGPU was unavailable for this user/session, so the fallback GPU was used.'; } return reason; } function failureReasonForGroup(group){ const failed=failedEventInfoForGroup(group); if(failed)return eventReason(failed.event); return ''; } function fallbackReasonForGroup(group){ if(!group||group.id!=='hardware')return ''; const failed=failedEventInfoForGroup(group); if(failed&&isExpectedFallbackFailure(group,failed))return zeroGpuReason(failed.event); const event=(activityFeedState.lastItems||[]).find(e=>group.steps.includes(String(e.step||''))&&isHardwareFallbackEvent(e)); return event?zeroGpuReason(event):''; } function reasonForTimelineItem(item={}){ if(item.status==='fallback')return item.reason||'Fallback GPU route was used.'; if(item.status==='failed'||item.status==='recovered')return item.reason||''; return ''; } function failedTimelineStatusForGroup(group,overallStatus){ const failed=failedEventInfoForGroup(group); if(!failed)return ''; const latestIdx=latestEventIndexForGroup(group); const overall=visualStatusClass(overallStatus); const superseded=latestIdx>failed.index; if(isExpectedFallbackFailure(group,failed)&&superseded)return 'fallback'; if(overall==='error')return 'failed'; return superseded?'recovered':'failed'; } function firstFailedGroupIndex(overallStatus){ const overall=visualStatusClass(overallStatus); let first=-1; COMPACT_TIMELINE_GROUPS.forEach((group,idx)=>{ const failed=failedEventInfoForGroup(group); if(!failed)return; const historical=failedTimelineStatusForGroup(group,overallStatus); if(historical==='fallback')return;if((overall==='error'||historical==='failed')&&(first<0||idx=0)return COMPACT_TIMELINE_GROUPS[first]?.id||''; const byStep=new Map((items||[]).map(item=>[String(item.step||item.id||item.label||''),item])); const groups=visibleCompactTimelineGroups(items,overallStatus); const failedFromTimeline=groups.find(group=>group.steps.some(step=>isFailureStatus(byStep.get(step)?.status))); if(failedFromTimeline)return failedFromTimeline.id||''; if(visualStatusClass(overallStatus)==='error'){ const lastNonPending=[...groups].reverse().find(group=>group.steps.some(step=>byStep.get(step)&&String(byStep.get(step).status||'').toLowerCase()!=='pending')); return lastNonPending?.id||'repair'; } const recovered=COMPACT_TIMELINE_GROUPS.find(group=>failedTimelineStatusForGroup(group,overallStatus)==='recovered'); if(recovered)return recovered.id||''; const fallback=COMPACT_TIMELINE_GROUPS.find(group=>failedTimelineStatusForGroup(group,overallStatus)==='fallback'||groupHasHardwareFallback(group)); return fallback?.id||''; } function terminalFailureAnchorGroupIndex(items=[],overallStatus=''){ if(visualStatusClass(overallStatus)!=='error')return -1; const events=activityFeedState.lastItems||[]; const groups=visibleCompactTimelineGroups(items,overallStatus).filter(g=>g.id!=='failure'&&g.id!=='report'); const groupIndexById=new Map(groups.map((g,i)=>[g.id,i])); // Prefer the latest explicit failed worker step that belongs to a product milestone. for(const event of [...events].reverse()){ const step=String(event.step||''); if(!step||step==='failure'||!isFailureStatus(event.status))continue; const group=COMPACT_TIMELINE_GROUPS.find(g=>g.id!=='failure'&&g.steps.includes(step)); if(group&&groupIndexById.has(group.id))return groupIndexById.get(group.id); } // If the terminal failure event is generic, anchor the failure to the latest // meaningful non-terminal event before it. This prevents backend-completed // future milestones from all turning green after a worker exception. for(const event of [...events].reverse()){ const step=String(event.step||''); if(!step||step==='failure'||step==='done'||step==='report_write')continue; const group=COMPACT_TIMELINE_GROUPS.find(g=>g.id!=='failure'&&g.id!=='report'&&g.steps.includes(step)); if(group&&groupIndexById.has(group.id))return groupIndexById.get(group.id); } const byStep=new Map((items||[]).map(item=>[String(item.step||item.id||item.label||''),item])); for(let i=groups.length-1;i>=0;i--){ const group=groups[i]; if(group.steps.some(step=>byStep.has(step)&&String(byStep.get(step).status||'').toLowerCase()!=='pending'))return i; } return -1; } function terminalFailureReason(){ const events=activityFeedState.lastItems||[]; const failed=[...events].reverse().find(event=>isFailureStatus(event.status)||String(event.step||'')==='failure'); return failed?eventReason(failed):''; } function stepOrderIndex(step){ const idx=WORKER_STEP_ORDER.indexOf(String(step||'')); return idx<0?-1:idx; } function normalizeTimelineOverallStatus(status){ const s=String(status||'').toLowerCase(); if(PROGRESS_TERMINAL_STATUSES.has(s))return s; return s; } function timelineIcon(status){ status=String(status||'pending'); if(status==='done'||status==='completed')return'✓'; if(status==='running')return'•'; if(status==='failed')return'!'; if(status==='warning'||status==='warn')return'!'; if(status==='fallback')return'⇄'; if(status==='recovered'||status==='superseded')return'↺'; if(status==='blocked'||status==='cancelled'||status==='stopped'||status==='after_fail')return'■'; if(status==='skipped')return'↷'; return'○'; } function timelineStatus(status,overallStatus=''){ status=String(status||'pending').toLowerCase(); const overall=normalizeTimelineOverallStatus(overallStatus); const stopped=overall&&PROGRESS_TERMINAL_STATUSES.has(overall)&&!['success','succeeded','done','full_inference_success','full_inference_candidate_health_passed','health_only','partial','partial_validation','completed_with_warnings'].includes(overall); if(status==='failed'||status==='error'||status==='failure')return'status-failed'; if(status==='fallback')return'status-fallback'; if(status==='warning'||status==='warn')return'status-warn'; if(status==='recovered'||status==='superseded')return'status-warn'; if(status==='after_fail'||status==='post_failure')return'status-after-fail'; if(status==='blocked'||status==='cancelled'||status==='canceled'||status==='stopped')return'status-stopped'; if(status==='done'||status==='completed'||status==='success')return'status-done'; if(status==='running'||status==='waiting')return stopped?'status-stopped':'status-running'; if(status==='skipped')return'status-skipped'; return stopped?'status-muted':'status-pending'; } function timelineStepKey(x,i){ return String(x.step||x.id||x.label||`step-${i}`); } function animateClass(el,klass,duration=900){ if(!el)return; el.classList.remove(klass); void el.offsetWidth; el.classList.add(klass); window.setTimeout(()=>el.classList.remove(klass),duration); } function eventStableKey(event={}){ return `${event.ts||''}|${event.step||''}|${event.status||''}|${event.message||''}`; } function mergeStableEvents(runId,items){ const incoming=(items||[]).filter(Boolean); if(activityFeedState.runId!==runId){ activityFeedState.runId=runId; activityFeedState.lastItems=[]; } const byKey=new Map(); [...activityFeedState.lastItems,...incoming].forEach(event=>{ const key=eventStableKey(event); if(key.trim()!=='|||')byKey.set(key,event); }); const merged=[...byKey.values()].sort((a,b)=>String(a.ts||'').localeCompare(String(b.ts||''))); activityFeedState.lastItems=merged; return merged; } function activeTimelineStepKey(items=[]){ const active=(items||[]).find(x=>['running','stopped','failed','blocked','cancelled','canceled'].includes(String(x.status||'').toLowerCase())); if(active)return String(active.step||active.id||active.label||''); const done=[...(items||[])].reverse().find(x=>['done','completed','success'].includes(String(x.status||'').toLowerCase())); return done?String(done.step||done.id||done.label||''):''; } function activeTimelineItem(items=[]){ const key=activeTimelineStepKey(items); return (items||[]).find(x=>String(x.step||x.id||x.label||'')===key)||null; } function friendlyTerminalEventMessage(event={}){ const step=String(event.step||'').toLowerCase(); const status=String(event.status||'').toLowerCase(); const msg=String(event.message||'').trim(); if(step==='api_validation'&&(status==='waiting'||status==='started')&&(msg.toLowerCase().includes('not ready')||msg.toLowerCase().includes('waiting'))){ return 'Waiting for Space startup'; } if(step==='anonymous_eval'&&status==='success'){ return 'Wrote local eval record'; } if(step==='done'&&(status==='full_inference_candidate_health_passed'||status==='health_only'||status==='partial_validation')){ return 'Universal model-card builder completed · Partial validation'; } if(step==='inference_gate'&&(status==='full_inference_candidate_health_passed'||status==='health_only'||status==='partial_validation')){ return 'Partial validation · health passed, generation smoke failed'; } return msg||event.step||'Waiting for worker events.'; } function eventMessage(event){ return friendlyTerminalEventMessage(event||{}); } function hasCanonicalTimelineModel(model){ return Boolean(model&&model.schema_version==='run_timeline_model.v1'&&Array.isArray(model.phases)); } function normalizeTerminalUiStatus(value){ const s=String(value||'').trim().toLowerCase(); if(!s)return''; if(PROGRESS_BLOCKING_TERMINAL_STATUSES.has(s))return s==='cancelled'||s==='canceled'?'stopped':s; if(['success','succeeded','done','completed','passed','repair_success'].includes(s))return'full_inference_success'; if(['cancelled','canceled'].includes(s))return'stopped'; if(['partial','health_only','full_inference_candidate_health_passed','completed_with_warnings'].includes(s))return'partial_validation'; if(PROGRESS_TERMINAL_STATUSES.has(s))return s; return''; } function sourceHasBlockingTerminal(src={}){ const keys=['status','final_status','display_status','effective_status','effective_verdict','verdict','result_status','validation_status','ui_status','gate_status']; return keys.some(k=>PROGRESS_BLOCKING_TERMINAL_STATUSES.has(String(src?.[k]||'').trim().toLowerCase())); } function authoritativeTerminalUiStatus(payload={}){ const view=payload.view||{}; const summary=payload.summary||{}; const highPriority=[payload.final_status_reconciliation,view.final_status_reconciliation,summary,view.summary,view.effective_run_status,payload.effective_run_status,summary.effective_run_status].filter(x=>x&&typeof x==='object'); const lowPriority=[view.timeline_model?.progress,payload.timeline_model?.progress,payload.inference_gate,payload.generation_smoke].filter(x=>x&&typeof x==='object'); const keys=['status','final_status','display_status','effective_status','effective_verdict','verdict','result_status','validation_status']; let sawBlocking=false; for(const src of highPriority){ if(sourceHasBlockingTerminal(src))sawBlocking=true; for(const key of keys){ const normalized=normalizeTerminalUiStatus(src[key]); if(normalized){ if(PROGRESS_BLOCKING_TERMINAL_STATUSES.has(normalized))return normalized; if(normalized==='full_inference_success'&&sawBlocking)continue; return normalized; } } } for(const src of lowPriority){ if(sourceHasBlockingTerminal(src))return normalizeTerminalUiStatus(src.status||src.final_status||src.display_status||src.effective_status||src.verdict)||'technical_blocker'; for(const key of keys){ const normalized=normalizeTerminalUiStatus(src[key]); if(normalized){ if(PROGRESS_BLOCKING_TERMINAL_STATUSES.has(normalized))return normalized; if(normalized==='full_inference_success'&&sawBlocking)continue; return normalized; } } if(!sawBlocking&&(src.ok===true||src.generation_smoke_passed===true||src.implementation_signals?.generation_smoke_passed===true))return'full_inference_success'; } return''; } function canonicalRunUiState(payload={}){ const view=payload.view||{}; const summary=payload.summary||{}; const statePayload=payload.state||{}; const header=view.header||{}; const statusModel=view.status_model||payload.status_model||{}; const modelProgress=(view.timeline_model&&view.timeline_model.progress)||payload.timeline_model?.progress||{}; const effectiveRunStatus=view.effective_run_status||payload.effective_run_status||summary.effective_run_status||{}; const authoritativeStatus=authoritativeTerminalUiStatus(payload); const effectiveStatusLower=String(authoritativeStatus||effectiveRunStatus.display_status||effectiveRunStatus.effective_status||'').toLowerCase(); const effectiveTerminalStatuses=new Set(['full_inference_success','partial_validation','manual_hardware_required','technical_blocker','technical_blocker_boot_only','failed','failure','error','stale','stopped','cancelled','canceled','auth_refresh_required','validated_after_space_test','validated_after_manual_space_test','recovered_by_space_test','recovered_by_manual_validation','manual_validated','manual_validation_passed']); const terminal=Boolean(authoritativeStatus||modelProgress.terminal===true||statusModel.is_terminal===true||effectiveTerminalStatuses.has(effectiveStatusLower)); const statusCandidates=[ authoritativeStatus, terminal?effectiveRunStatus.display_status:'', terminal?modelProgress.verdict:'', terminal?statusModel.effective_status:'', terminal?statusModel.verdict:'', terminal?statusModel.status:'', terminal?header.display_status:'', terminal?header.status:'', payload.effective_status,summary.effective_status, payload.validation_status,payload.result_status,summary.validation_status,summary.result_status, payload.inference_gate?.status,summary.gate_status, header.status,header.raw_status, payload.status,summary.status,statePayload.status, ]; let status=statusCandidates.map(x=>String(x||'').trim()).find(Boolean)||'running'; const lower=status.toLowerCase(); const visual=String(modelProgress.visual_status||statusModel.visual_status||payload.visual_status||'').toLowerCase() || (['partial','partial_validation','full_inference_candidate_health_passed','health_only','manual_hardware_required','completed_with_warnings','demo_usable_full_promise_not_verified','interactive_app_available_smoke_failed','manual_test_required_smoke_failed'].includes(lower)?'warn': (lower.includes('fail')||lower.includes('error')||lower.includes('block')?'error': (lower.includes('success')||lower==='succeeded'||lower==='done'?'success':lower))); let label=effectiveRunStatus.display_label||modelProgress.label||header.display_label||header.status_label||badgeLabel(status); if(terminal&&String(label||'').toLowerCase()==='running')label=badgeLabel(status); return {status, statusLower:lower, label, visual_status:visual, isTerminal:terminal||PROGRESS_TERMINAL_STATUSES.has(lower)}; } function visibleCanonicalTimelinePhases(model={}){ const phases=Array.isArray(model.phases)?model.phases:[]; const terminal=model.progress?.terminal===true||PROGRESS_TERMINAL_STATUSES.has(String(model.progress?.verdict||'').toLowerCase()); // v198.26.7: keep the terminal Done marker visible once a final verdict // exists. Active Run must explicitly reassure users that final reconciliation // reached success/partial/fail instead of stopping at an intermediate phase. return phases.filter(p=>terminal||String(p.id||'').toLowerCase()!=='done').map(p=>{ if(String(p.id||'').toLowerCase()==='hardware')return {...p,label:'GPU'}; return p; }); } function compactPhaseSublabel(phase={}){ const id=String(phase.id||'').toLowerCase(); const s=String(phase.status||'pending').toLowerCase(); if(s==='complete'||s==='done'||s==='success')return id==='archive'?'Published':'Done'; if(s==='warning'||s==='warn')return id==='hardware'?'Fallback':'Needs attention'; if(s==='running'||s==='waiting')return 'Running'; if(s==='failed'||s==='error')return 'Failed'; if(s==='stopped'||s==='cancelled'||s==='blocked')return 'Stopped'; if(s==='not_needed'||s==='skipped')return 'Not needed'; return 'Pending'; } function compactTimelineSublabel(status='',groupId=''){ const s=String(status||'pending').toLowerCase(); const id=String(groupId||'').toLowerCase(); if(s==='done'||s==='complete'||s==='success')return id==='archive'?'Published':'Done'; if(s==='fallback')return 'Fallback'; if(s==='recovered')return 'Recovered'; if(s==='warning'||s==='warn')return 'Needs attention'; if(s==='running'||s==='waiting')return 'Running'; if(s==='failed'||s==='error')return 'Failed'; if(s==='stopped'||s==='cancelled'||s==='blocked')return 'Stopped'; if(s==='skipped'||s==='not_needed')return 'Not needed'; return 'Pending'; } function hideEventReason(item={}){ const step=String(item.step||'').toLowerCase(); const status=String(item.status||'').toLowerCase(); if(step==='api_validation'&&(status==='waiting'||status==='started'||status==='running'))return true; return false; } function canonicalPhaseToTimelineItem(phase={}){ const raw=String(phase.status||'pending').toLowerCase(); let status=raw; if(raw==='complete')status='done'; if(raw==='warning')status='warning'; if(raw==='failed')status='failed'; if(raw==='stopped')status='stopped'; if(raw==='not_needed'||raw==='skipped')status='skipped'; const details=Array.isArray(phase.details)?phase.details:[]; return { id:phase.id||phase.label, step:phase.id||phase.label, label:phase.label||phase.id||'Phase', status, summary:phase.summary||'', sublabel:compactPhaseSublabel(phase), details, percent:status==='done'||status==='warning'||status==='skipped'?100:(status==='running'?50:0), ring_progress:status==='done'||status==='warning'||status==='skipped'?100:(status==='running'?50:0), }; } function timelinePhaseById(phases=[],id=''){ return phases.find(p=>String(p.id||'')===id)||null; } function firstPhaseWithStatus(phases=[],statuses=[]){ const wanted=new Set(statuses.map(s=>String(s||'').toLowerCase())); return phases.find(p=>wanted.has(String(p.status||'').toLowerCase()))||null; } function firstPhaseWithIdsAndStatus(phases=[],ids=[],statuses=[]){ const wantedIds=new Set(ids); const wantedStatuses=new Set(statuses.map(s=>String(s||'').toLowerCase())); return phases.find(p=>wantedIds.has(String(p.id||''))&&wantedStatuses.has(String(p.status||'').toLowerCase()))||null; } function timelineModelActivePhase(model={}){ const phases=visibleCanonicalTimelinePhases(model); if(!phases.length)return null; const progress=model.progress||{}; const visual=String(progress.visual_status||'').toLowerCase(); const verdict=String(progress.verdict||'').toLowerCase(); const terminal=progress.terminal===true||['success','warn','warning','error','stopped'].includes(visual)||PROGRESS_TERMINAL_STATUSES.has(verdict); const failed=firstPhaseWithStatus(phases,['failed','stopped']); if(failed)return failed; const attention=firstPhaseWithIdsAndStatus(phases,['live_validation','archive','recovery','done'],['warning','failed'])||firstPhaseWithStatus(phases,['warning']); if(terminal&&attention)return attention; if(terminal&&['partial','partial_validation','full_inference_candidate_health_passed','health_only','completed_with_warnings','demo_usable_full_promise_not_verified','interactive_app_available_smoke_failed','manual_test_required_smoke_failed'].includes(verdict)){ return firstPhaseWithIdsAndStatus(phases,['live_validation','archive','done'],['complete','warning'])||attention||[...phases].reverse().find(p=>String(p.status||'').toLowerCase()!=='pending')||phases[0]; } if(terminal&&visual==='success'){ return firstPhaseWithIdsAndStatus(phases,['live_validation'],['complete','warning'])|| firstPhaseWithIdsAndStatus(phases,['archive'],['complete','warning'])|| timelinePhaseById(phases,'done')|| [...phases].reverse().find(p=>String(p.status||'').toLowerCase()!=='pending')||phases[0]; } if(terminal&&(visual==='warn'||visual==='warning')){ return attention||firstPhaseWithIdsAndStatus(phases,['live_validation','archive','done'],['complete'])|| [...phases].reverse().find(p=>String(p.status||'').toLowerCase()!=='pending')||phases[0]; } const recoveryRunning=firstPhaseWithIdsAndStatus(phases,['recovery'],['running']); if(recoveryRunning)return recoveryRunning; const liveRunning=firstPhaseWithIdsAndStatus(phases,['live_validation'],['running']); if(liveRunning)return liveRunning; const agentRunning=firstPhaseWithIdsAndStatus(phases,['agent'],['running']); if(agentRunning)return agentRunning; const running=firstPhaseWithStatus(phases,['running']); if(running)return running; const actionableWarning=phases.find(p=>['live_validation','recovery','archive','done'].includes(String(p.id||''))&&String(p.status||'').toLowerCase()==='warning'); if(actionableWarning)return actionableWarning; return [...phases].reverse().find(p=>String(p.status||'').toLowerCase()!=='pending')||phases[0]||null; } function renderTimelineModelWarnings(model={}){ const note=$('timelineTraceNote'); if(!note)return; const warnings=Array.isArray(model.warnings)?model.warnings:[]; if(!warnings.length){note.hidden=true;note.innerHTML='';note.className='timeline-trace-note';return;} const rows=warnings.slice(0,4).map(w=>{ const code=String(w.code||''); const label=escapeHtml(code==='pi_model_changed'?'Pi assistant mismatch':code==='hardware_fallback_used'?'GPU fallback':(w.label||'Run note')); const detail=escapeHtml(w.detail||''); return `
  • ${label}${detail?`${detail}`:''}
  • `; }).join(''); note.hidden=false; note.className='timeline-trace-note fallback canonical-warning run-notes'; note.innerHTML=`Run notes`; } function timelineDetailStatusLabel(status=''){ const s=String(status||'').toLowerCase(); if(s==='complete'||s==='done'||s==='success')return'Complete'; if(s==='selected')return'Selected'; if(s==='uploaded')return'Uploaded'; if(s==='ready')return'Ready'; if(s==='verified')return'Verified'; if(s==='fallback')return'Fallback'; if(s==='building')return'Building'; if(s==='queued')return'Queued'; if(s==='blocked')return'Blocked'; if(s==='warning'||s==='warn')return'Needs attention'; if(s==='running'||s==='waiting')return'In progress'; if(s==='not_needed'||s==='skipped')return'Not needed'; if(s==='failed'||s==='error')return'Failed'; if(s==='stopped'||s==='cancelled'||s==='blocked')return'Stopped'; return badgeLabel(s||'pending'); } function timelinePhaseDetailRows(phase={}){ const details=Array.isArray(phase.details)?phase.details.filter(Boolean):[]; if(details.length){ return details.slice(0,6).map(d=>{ const label=escapeHtml(d.label||d.title||'Detail'); const value=escapeHtml(d.value||d.detail||d.summary||d.status||''); const status=String(d.status||'').toLowerCase(); const cls=status?` ${statusClass(status)}`:''; return `
  • ${label}${value?`${value}`:''}
  • `; }).join(''); } const summary=String(phase.summary||'').trim(); return summary?`
  • Summary${escapeHtml(summary)}
  • `:''; } function renderTimelineModelDetails(model={},activePhase=null){ const root=$('timelinePhaseDetails'); if(!root)return; if(!hasCanonicalTimelineModel(model)){root.hidden=true;root.innerHTML='';root.className='timeline-phase-details';return;} const phase=activePhase||timelineModelActivePhase(model)||{}; if(!phase||!(phase.id||phase.label)){root.hidden=true;root.innerHTML='';return;} const status=String(phase.status||'pending').toLowerCase(); const tone=timelineStatus(status).replace(/^status-/,''); const warnings=Array.isArray(model.warnings)?model.warnings:[]; const details=Array.isArray(phase.details)?phase.details:[]; const phaseId=String(phase.id||''); const isRecovery=String(phase.id||'')==='recovery'; const actionable=status.includes('fail')||status.includes('error')||status.includes('warn')||status.includes('manual')||isRecovery||warnings.length>0||details.some(d=>{const st=String(d?.status||'').toLowerCase();return st.includes('fail')||st.includes('warn')||st.includes('manual')||st==='info';}); if(!actionable){root.hidden=true;root.innerHTML='';root.className='timeline-phase-details';return;} let rows=timelinePhaseDetailRows(phase); let summary=phase.summary||''; if(String(phase.id||'')==='recovery'){ // Recovery has its own dedicated Agent recovery panel below the timeline. // Keep the phase details as a compact pointer instead of duplicating // Diagnose / Decide / Patch / Revalidate rows here. summary=summary||'Recovery status is available below.'; // See Agent recovery below. rows=''; } root.hidden=false; root.className=`timeline-phase-details ${tone}${isRecovery?' recovery-compact':''}`; const compactPointer=isRecovery?`

    See Agent recovery below for diagnosis, patch and blocker details.

    `:''; root.innerHTML=`
    ${escapeHtml(isRecovery?'Current focus':(phase.label||'Phase'))}${escapeHtml(timelineDetailStatusLabel(status))}
    ${summary?`

    ${escapeHtml(summary)}

    `:''}${compactPointer}${rows?``:''}`; } function renderTimelineModel(model={},overallStatus=''){ const root=$('timeline'); if(!root)return false; if(!hasCanonicalTimelineModel(model))return false; if(!root.dataset.scrollBound){root.dataset.scrollBound='1';root.addEventListener('scroll',()=>{if(root.dataset.autoScrolling==='1')return;root.dataset.userScrolled='1'},{passive:true});} const list=visibleCanonicalTimelinePhases(model).map(canonicalPhaseToTimelineItem); const wideTimeline=typeof window==='undefined'||!window.matchMedia||window.matchMedia('(min-width: 521px)').matches; root.style.gridTemplateColumns=wideTimeline&&list.length?`repeat(${list.length}, minmax(0, 1fr))`:''; root.style.setProperty('--timeline-phase-count', String(Math.max(1,list.length||8))); root.classList.add('timeline-canonical'); root.classList.remove('trace-failed','trace-recovered','trace-fallback'); renderTimelineModelWarnings(model); const active=timelineModelActivePhase(model)||{}; renderTimelineModelDetails(model,active); const currentKey=String(active.id||active.label||''); const signature=list.map((x,i)=>`${timelineStepKey(x,i)}:${x.status}:${x.label}:${x.summary}:${overallStatus}`).join('|'); if(root.dataset.signature===signature){ if(root.dataset.visibleStep!==currentKey&&root.dataset.userScrolled!=='1')ensureTimelineStepVisible(currentKey); return true; } const previousKey=root.dataset.currentStep||''; if(previousKey!==currentKey)root.dataset.userScrolled=''; root.dataset.signature=signature; root.dataset.currentStep=currentKey||''; const nextState={}; root.innerHTML=list.map((x,i)=>{ const key=timelineStepKey(x,i); const st=timelineStatus(x.status,overallStatus); const prev=timelineRenderState[key]; const changed=prev&&prev!==st; nextState[key]=st; const label=st.replace(/^status-/,''); const summary=x.summary||label; const sublabel=x.sublabel||label; const details=(x.details||[]).map(d=>d&&d.label).filter(Boolean); const detailTitle=details.length?details.join(' · '):summary; const title=` title="${escapeHtml([x.label,summary,detailTitle].filter(Boolean).join(' · '))}"`; const aria=`${x.label}: ${label}${summary?`, ${summary}`:''}`; return `
    ${timelineIcon(x.status)}
    ${escapeHtml(x.label)}${escapeHtml(sublabel)}
    `; }).join(''); Object.keys(timelineRenderState).forEach(k=>delete timelineRenderState[k]); Object.assign(timelineRenderState,nextState); root.querySelectorAll('.step.status-changed').forEach(step=>{animateClass(step,'status-flash',1000);animateClass(step.querySelector('.step-dot'),'dot-pop',700);}); if(!root.dataset.userScrolled||previousKey!==currentKey){root.dataset.autoScrolling='1';const scrollOpts={instant:!root.dataset.visibleStep,force:previousKey!==currentKey};(typeof requestAnimationFrame==='function'?requestAnimationFrame:(fn)=>setTimeout(fn,0))(()=>(typeof requestAnimationFrame==='function'?requestAnimationFrame:(fn)=>setTimeout(fn,0))(()=>ensureTimelineStepVisible(currentKey,scrollOpts)));setTimeout(()=>{if(root)root.dataset.autoScrolling=''},360);} return true; } function timelineStepBounds(root,target){ const rootBox=root.getBoundingClientRect?root.getBoundingClientRect():{left:0,right:root.clientWidth,width:root.clientWidth}; const targetBox=target.getBoundingClientRect?target.getBoundingClientRect():{left:target.offsetLeft-root.scrollLeft,right:target.offsetLeft-root.scrollLeft+target.offsetWidth,width:target.offsetWidth}; return { rootLeft:rootBox.left, rootRight:rootBox.right, targetLeft:targetBox.left, targetRight:targetBox.right, targetWidth:targetBox.width||target.offsetWidth||0, }; } function ensureTimelineStepVisible(stepKey,opts={}){ const early=new Set(['bootstrap','dependencies','auth_model']); const root=$('timeline'); if(!root||!stepKey)return; const safeStep=(typeof CSS!=='undefined'&&CSS.escape)?CSS.escape(stepKey):String(stepKey).replace(/"/g,'\"'); const target=root.querySelector(`[data-step="${safeStep}"]`); if(!target)return; const margin=28; // Keep-visible behavior: do not center. Only move the minimum amount needed. const behavior='auto'; const visibleLeft=root.scrollLeft; const visibleRight=visibleLeft+root.clientWidth; const targetLeft=target.offsetLeft; const targetRight=targetLeft+target.offsetWidth; const fullyVisible=targetLeft>=visibleLeft+margin&&targetRight<=visibleRight-margin; if(fullyVisible){root.dataset.visibleStep=stepKey;return;} if(early.has(stepKey)&&root.scrollLeft<=1&&targetLeft>=0&&targetRight<=root.clientWidth){root.dataset.visibleStep=stepKey;return;} let nextLeft=visibleLeft; if(targetLeftvisibleRight-margin){ nextLeft=targetRight-root.clientWidth+margin; } const maxScroll=Math.max(0,root.scrollWidth-root.clientWidth); nextLeft=Math.max(0,Math.min(maxScroll,Math.round(nextLeft))); if(opts.force&&target.offsetWidthvisibleLeft&&targetLeftvisibleRight-margin*2)nextLeft=Math.min(maxScroll,Math.round(targetRight-root.clientWidth+margin*2)); if(center1){ const behavior=opts.instant?'auto':'smooth'; try{root.scrollTo({left:nextLeft,behavior});} catch(_){root.scrollLeft=nextLeft;} } root.dataset.visibleStep=stepKey; } function hasSpecificTimelineProblem(items=[],overallStatus=''){ const byStep=new Map((items||[]).map(item=>[String(item.step||item.id||item.label||''),item])); const overall=visualStatusClass(overallStatus); return COMPACT_TIMELINE_GROUPS.some(group=>{ if(group.id==='failure')return false; if(group.id==='repair')return group.steps.some(step=>byStep.has(step))&&overall==='error'; return group.steps.some(step=>isFailureStatus(byStep.get(step)?.status))||failedEventInfoForGroup(group); }); } function visibleCompactTimelineGroups(items=[],overallStatus=''){ const byStep=new Map((items||[]).map(item=>[String(item.step||item.id||item.label||''),item])); const overall=visualStatusClass(overallStatus); const specificProblem=hasSpecificTimelineProblem(items,overallStatus); return COMPACT_TIMELINE_GROUPS.filter(group=>{ const hasItem=group.steps.some(step=>byStep.has(step)); if(group.id==='repair')return hasItem; // Failure is a terminal fallback anchor, not a normal product milestone. // Prefer marking the precise stage that failed; only show Failure when the // run has no better failure/recovery context. if(group.id==='failure')return hasItem&&!specificProblem; return true; }); } function compactTimelineItems(items=[],overallStatus=''){ const byStep=new Map((items||[]).map(item=>[String(item.step||item.id||item.label||''),item])); const terminalRaw=new Set(['failed','blocked','stopped','cancelled','canceled','recovered','fallback','after_fail','post_failure']); const overall=visualStatusClass(overallStatus); const terminalSuccess=overall==='success'||['success','succeeded','done','completed','full_inference_success','repair_success'].includes(String(overallStatus||'').toLowerCase()); let firstFailedIdx=firstFailedGroupIndex(overallStatus); const visibleGroups=visibleCompactTimelineGroups(items,overallStatus); const terminalAnchorIdx=firstFailedIdx>=0?firstFailedIdx:terminalFailureAnchorGroupIndex(items,overallStatus); if(overall==='error'&&firstFailedIdx<0)firstFailedIdx=terminalAnchorIdx; return visibleGroups.map((group,groupIndex)=>{ const groupItems=group.steps.map(step=>byStep.get(step)).filter(Boolean); const explicitItems=groupItems.filter(item=>String(item.step||item.id||item.label||'')); const doneCount=groupItems.filter(item=>['done','completed','success'].includes(String(item.status||'').toLowerCase())).length; const active=groupItems.find(item=>['running','waiting','stopped','failed','blocked','cancelled','canceled'].includes(String(item.status||'').toLowerCase())); const itemFailure=failedItemInfoForGroup(group,byStep); const historicalFailure=failedTimelineStatusForGroup(group,overallStatus)||(itemFailure?(groupHasHardwareFallback(group)?'fallback':(overall==='error'?'failed':'recovered')):''); let status='pending'; if(historicalFailure)status=historicalFailure; else if(overall==='error'&&terminalAnchorIdx>=0&&groupIndex>terminalAnchorIdx)status='pending'; else if(overall==='error'&&terminalAnchorIdx>=0&&groupIndex===terminalAnchorIdx)status='failed'; else if(active)status=String(active.status||'running').toLowerCase(); else if(groupItems.length&&doneCount>=group.steps.length)status='done'; else if(doneCount>0)status=terminalSuccess?'done':'running'; if(overall==='error'&&status==='done'&&group.steps.includes('failure'))status='failed'; const failedInfo=failedEventInfoForGroup(group)||itemFailure; const reason=historicalFailure==='fallback'?fallbackReasonForGroup(group):(status==='failed'?(failureReasonForGroup(group)||terminalFailureReason()):(historicalFailure?failureReasonForGroup(group):'')); const activeSubstep=historicalFailure==='fallback'?'fallback GPU':failedInfo&&historicalFailure?(failedInfo.event.step||failedInfo.event.message||'failed'):active?.step||active?.id||active?.label||groupItems[groupItems.length-1]?.step||''; const activeIndex=activeSubstep?Math.max(0,group.steps.indexOf(activeSubstep)):-1; let percent=0; if(status==='done')percent=100; else if(status==='pending')percent=0; else if(status==='after_fail')percent=doneCount?Math.round((doneCount/group.steps.length)*100):0; else if(activeIndex>=0)percent=Math.round(((activeIndex+0.45)/group.steps.length)*100); else if(doneCount>0)percent=Math.round((doneCount/group.steps.length)*100); if(terminalRaw.has(status))percent=Math.max(percent,doneCount?Math.round((doneCount/group.steps.length)*100):8); const clampedPercent=Math.max(0,Math.min(100,percent)); const substepLabel=workerStepDisplayLabel(activeSubstep); const progressDone=status==='done'?group.steps.length:Math.min(group.steps.length,Math.max(doneCount,clampedPercent>=100?group.steps.length:Math.ceil((clampedPercent/100)*group.steps.length))); const showProgressLabel=group.steps.length>1&&(groupItems.length>0||status!=='pending'); return { step:group.id, id:group.id, label:group.display_label||group.label, status, full_steps:group.steps, done_count:doneCount, total_count:showProgressLabel?group.steps.length:0, percent:clampedPercent, ring_progress:clampedPercent, active_substep:activeSubstep, active_substep_label:substepLabel, grouped:group.steps.length>1, progress_label:showProgressLabel?`${progressDone}/${group.steps.length}`:'', reason }; }); } function currentCompactGroupKey(fullItems=[],overallStatus=''){ const problem=firstProblemGroupKey(fullItems,overallStatus); if(problem)return problem; const activeKey=activeTimelineStepKey(fullItems); const group=COMPACT_TIMELINE_GROUPS.find(g=>g.steps.includes(activeKey)); return group?.id||activeKey; } function timelineTraceModel(list=[],overallStatus=''){ const overall=visualStatusClass(overallStatus); const failedIndex=list.findIndex(item=>String(item.status||'').toLowerCase()==='failed'); const fallbackIndex=list.findIndex(item=>String(item.status||'').toLowerCase()==='fallback'); const recoveredIndex=list.findIndex(item=>String(item.status||'').toLowerCase()==='recovered'); if(failedIndex>=0){ return {mode:'failed',index:failedIndex,key:list[failedIndex]?.step||'',label:list[failedIndex]?.label||'failed step',reason:reasonForTimelineItem(list[failedIndex]),message:`Failed at ${list[failedIndex]?.label||'this stage'}. Later steps are post-failure cleanup or reporting, not a successful build path.`}; } if(fallbackIndex>=0){ return {mode:'fallback',index:fallbackIndex,key:list[fallbackIndex]?.step||'',label:list[fallbackIndex]?.label||'hardware fallback',reason:reasonForTimelineItem(list[fallbackIndex]),message:`ZeroGPU was not used for this run. The factory switched to the fallback GPU and continued successfully.`}; } if(recoveredIndex>=0){ return {mode:'recovered',index:recoveredIndex,key:list[recoveredIndex]?.step||'',label:list[recoveredIndex]?.label||'recovered step',reason:reasonForTimelineItem(list[recoveredIndex]),message:`Recovered after an incident at ${list[recoveredIndex]?.label||'this stage'}. The trace continues after recovery.`}; } return {mode:'clean',index:-1,key:'',label:'',message:''}; } function renderTimelineTraceNote(trace){ const note=$('timelineTraceNote'); if(!note)return; if(!trace||trace.mode==='clean'){ note.hidden=true; note.className='timeline-trace-note'; note.innerHTML=''; return; } note.hidden=false; note.className=`timeline-trace-note ${trace.mode}`; const icon=trace.mode==='failed'?'✕':(trace.mode==='fallback'?'⇄':'↺'); const title=trace.mode==='failed'?'Failure trace':(trace.mode==='fallback'?'Hardware fallback':'Recovered incident'); const reason=trace.reason?`

    Reason: ${escapeHtml(trace.reason)}

    `:''; note.innerHTML=`${icon}${escapeHtml(title)}

    ${escapeHtml(trace.message)}

    ${reason}`; } function traceClassForStep(trace,index){ if(!trace||trace.mode==='clean')return''; if(index===trace.index)return trace.mode==='failed'?'trace-breakpoint':(trace.mode==='fallback'?'trace-fallback':'trace-recovered'); if(trace.mode==='failed'&&index>trace.index)return'trace-post-failure'; return''; } function renderTimelinePlaceholder(message='Waiting for canonical run timeline…'){ const root=$('timeline'); if(!root)return; root.dataset.signature='canonical-placeholder'; root.classList.remove('timeline-canonical','trace-failed','trace-recovered','trace-fallback'); root.classList.add('timeline-placeholder'); root.style.gridTemplateColumns=''; root.innerHTML=`
    ${escapeHtml(message)}
    `; const note=$('timelineTraceNote'); if(note){note.hidden=true;note.innerHTML='';note.className='timeline-trace-note';} const details=$('timelinePhaseDetails'); if(details){details.hidden=true;details.innerHTML='';details.className='timeline-phase-details';} } function shouldSuppressLegacyTimeline(items=[]){ const list=Array.isArray(items)?items:[]; if(!list.length)return true; const labels=list.map(x=>String(x.label||'').toLowerCase()); const legacyNeedles=['bootstrap','dependencies','pi install','pi config','requirements sanitize','generation smoke','inference gate']; const legacyHits=legacyNeedles.filter(n=>labels.includes(n)).length; return legacyHits>=4&&list.length>=12; } function renderTimeline(items,overallStatus=''){ const root=$('timeline'); if(!root)return; if(shouldSuppressLegacyTimeline(items)){renderTimelinePlaceholder('Waiting for canonical run timeline…');return;} if(!root.dataset.scrollBound){root.dataset.scrollBound='1';root.addEventListener('scroll',()=>{if(root.dataset.autoScrolling==='1')return;root.dataset.userScrolled='1'},{passive:true});} root.classList.remove('timeline-canonical','timeline-placeholder'); const canonicalDetails=$('timelinePhaseDetails'); if(canonicalDetails){canonicalDetails.hidden=true;canonicalDetails.innerHTML='';canonicalDetails.className='timeline-phase-details';} const fullList=items||[]; const list=compactTimelineItems(fullList,overallStatus); // Keep the compact timeline on a single row. The number of visible groups is // dynamic (repair/failure groups appear only for recovery/failures), so a // fixed CSS repeat count can wrap dots onto a second line. Set the exact // column count at render time for desktop/tablet layouts and let mobile CSS // switch back to the vertical stacked timeline. const wideTimeline=typeof window==='undefined'||!window.matchMedia||window.matchMedia('(min-width: 521px)').matches; root.style.gridTemplateColumns=wideTimeline&&list.length?`repeat(${list.length}, minmax(96px, 1fr))`:''; const trace=timelineTraceModel(list,overallStatus); renderTimelineTraceNote(trace); root.classList.toggle('trace-failed',trace.mode==='failed'); root.classList.toggle('trace-recovered',trace.mode==='recovered'); root.classList.toggle('trace-fallback',trace.mode==='fallback'); const currentKey=trace.key||currentCompactGroupKey(fullList,overallStatus); const signature=list.map((x,i)=>`${timelineStepKey(x,i)}:${timelineStatus(x.status,overallStatus)}:${x.label||''}:${overallStatus||''}:${trace.mode}:${trace.index}`).join('|'); // v68 legacy invariant reference: if(root.dataset.signature===signature){ensureTimelineStepVisible(currentKey);return;} if(root.dataset.signature===signature){ if(root.dataset.visibleStep!==currentKey&&root.dataset.userScrolled!=='1')ensureTimelineStepVisible(currentKey); return; } const previousKey=root.dataset.currentStep||''; if(previousKey!==currentKey)root.dataset.userScrolled=''; root.dataset.signature=signature; root.dataset.currentStep=currentKey||''; const nextState={}; root.innerHTML=list.map((x,i)=>{ const key=timelineStepKey(x,i); const st=timelineStatus(x.status,overallStatus); const rawStatus=String(x.status||'pending').toLowerCase(); const prev=timelineRenderState[key]; const changed=prev&&prev!==st; nextState[key]=st; const label=st.replace(/^status-/,''); const percent=Number(x.percent||0); const meta=compactTimelineSublabel(rawStatus,x.id||x.step||''); const traceClass=traceClassForStep(trace,i); const reason=reasonForTimelineItem(x); const reasonLine=''; const titleParts=[x.label||`Step ${i+1}`,meta,reason].filter(Boolean); const title=` title="${escapeHtml(titleParts.join(' · '))}"`; const groupBadge=x.total_count>1?`${escapeHtml(x.progress_label||'')}`:''; const aria=`${x.label||`Step ${i+1}`}: ${label}${x.total_count>1?`, ${x.done_count||0} of ${x.total_count} substeps`:''}`; return `
    ${timelineIcon(rawStatus)}${groupBadge}
    ${escapeHtml(x.label||`Step ${i+1}`)}${escapeHtml(meta)}${reasonLine}
    `; }).join(''); Object.keys(timelineRenderState).forEach(k=>delete timelineRenderState[k]); Object.assign(timelineRenderState,nextState); root.querySelectorAll('.step.status-changed').forEach(step=>{ animateClass(step,'status-flash',1000); const dot=step.querySelector('.step-dot'); animateClass(dot,'dot-pop',700); }); if(!root.dataset.userScrolled||previousKey!==currentKey){root.dataset.autoScrolling='1';const scrollOpts={instant:!root.dataset.visibleStep,force:previousKey!==currentKey};(typeof requestAnimationFrame==='function'?requestAnimationFrame:(fn)=>setTimeout(fn,0))(()=>(typeof requestAnimationFrame==='function'?requestAnimationFrame:(fn)=>setTimeout(fn,0))(()=>ensureTimelineStepVisible(currentKey,scrollOpts)));setTimeout(()=>{if(root)root.dataset.autoScrolling=''},360);} } function contextualEventClass(item={},furthestIdx=-1){ const raw=String(item.status||'').toLowerCase(); const idx=stepOrderIndex(item.step); if(isFailureStatus(raw)&&isHardwareFallbackEvent(item))return'hardware-fallback'; if(isFailureStatus(raw)&&idx>=0&&furthestIdx>idx)return'warn recovered'; if(isFailureStatus(raw))return'error'; if(isStoppedStatus(raw))return'warn'; if(isSuccessStatus(raw))return'success'; if(raw.includes('running')||raw.includes('started')||raw.includes('waiting')||raw.includes('pending'))return'running'; return statusClass(raw); } function contextualEventLabel(item={},klass=''){ const raw=String(item.status||'').toLowerCase(); if(klass.includes('hardware-fallback'))return`${raw||'fallback'} · fallback route`; if(klass.includes('recovered'))return`${raw||'failed'} · superseded`; return raw; } function eventIconFor(item={},klass=''){ const step=String(item.step||'').toLowerCase(); const status=String(item.status||'').toLowerCase(); if(klass.includes('error')||status.includes('fail')||status.includes('error'))return'alert'; if(klass.includes('hardware-fallback')||step.includes('hardware'))return'chip'; if(step.includes('repair_decision')||step.includes('pi_diagnosis')||step.includes('failure_diagnosis'))return'search'; if(step.includes('factory_rebuild'))return'rocket'; if(step.includes('repair')||step.includes('blocker'))return'wand'; if(step.includes('upload'))return'upload'; if(step.includes('trace'))return'files'; if(step.includes('report'))return'document'; if(step.includes('auth'))return'shield'; if(step.includes('model')||step.includes('analysis'))return'search'; if(step.includes('space')||step.includes('create'))return'rocket'; if(step.includes('api')||step.includes('smoke')||step.includes('inference')||step.includes('validation'))return'bolt'; if(step.includes('pi_')||step.includes('pi'))return'bot'; if(status.includes('running')||status.includes('started')||status.includes('waiting')||status.includes('pending'))return'clock'; if(status.includes('success')||status==='done')return'check'; return'circle'; } const EVENT_ICON_PATHS={ alert:'M12 9v4m0 4h.01M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z', bolt:'M13 2 4 14h7l-1 8 10-13h-7l0-7Z', bot:'M12 5V3m-7 8a5 5 0 0 1 5-5h4a5 5 0 0 1 5 5v5a3 3 0 0 1-3 3H8a3 3 0 0 1-3-3v-5Zm4 1h2m-8 0h2m-2 4h4', check:'m5 13 4 4L19 7', chip:'M9 3v3m6-3v3M9 18v3m6-3v3M3 9h3m-3 6h3m12-6h3m-3 6h3M8 6h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2Zm2 4h4v4h-4v-4Z', circle:'M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Z', clock:'M12 8v5l3 2m6-3a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z', document:'M14 2H7a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7l-5-5Zm0 0v5h5M8 13h8M8 17h6', files:'M9 7h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H9a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2Zm0 0V5a2 2 0 0 1 2-2h4l4 4v2M11 11h4M11 15h5', rocket:'M5 19c1.5-.5 2.8-1.5 4-3m-4 3c-.8.8-1.8 1.1-3 1 .1-1.2.5-2.2 1.2-3M13 7l4 4m-6 6-4-4 4-7c2-2 5-3 8-3 0 3-1 6-3 8l-5 6Z', search:'M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 1 1 0-15 7.5 7.5 0 0 1 0 15Z', shield:'M12 3 5 6v6c0 4.4 3 7.4 7 9 4-1.6 7-4.6 7-9V6l-7-3Zm-3 9 2 2 4-5', upload:'M12 16V4m0 0 4 4m-4-4-4 4M4 16v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3', wand:'M4 20 20 4m-3 0 3 3m-6-1 4 4M5 6h.01M9 3h.01M3 10h.01M18 18h.01' }; function renderEventIcon(name){ const key=EVENT_ICON_PATHS[name]?name:'circle'; return ``; } // v105 keeps v64 compact-list invariant: const visible=[...list].reverse() function eventOriginFor(item={}){ const step=String(item.step||'').toLowerCase(); const message=String(item.message||'').toLowerCase(); if(['pi_install','pi_config','pi_run','pi_model_resolution','pi_verification','pi_diagnosis','repair_plan','repair_patch'].some(s=>step.includes(s)))return'pi'; if(['bootstrap','token_context','dependencies','node'].some(s=>step.includes(s))||message.includes('worker started'))return'job'; if(['create_space','create_space_hardware','hardware_strategy','upload_files'].some(s=>step.includes(s)))return'hub'; if(['space_runtime','space_logs','live_wait'].some(s=>step.includes(s))||message.includes('runtime_error')||message.includes('app_starting'))return'space'; if(['api_validation','generation_smoke','inference_gate','repair_validation'].some(s=>step.includes(s))||message.includes('gradio'))return'gradio'; if(['failure_diagnosis','repair_decision','technical_blocker','failure','done','report_write'].some(s=>step.includes(s)))return'factory'; return'factory'; } function renderActivityFeed(items){ const root=$('activityFeed'); if(!root)return; const list=mergeStableEvents(String(state.runId||''),items||[]); const visible=[...list].slice(-30).reverse(); const signature=visible.map(item=>`${item.ts||''}:${item.step||''}:${item.status||''}:${item.message||''}`).join('|'); if(root.dataset.signature===signature)return; const shouldKeepLatestVisible=root.scrollTop<24||!root.dataset.signature; root.dataset.signature=signature; root.classList.add('show-all'); if(!list.length){ root.innerHTML='
    No activity yet. Waiting for the first worker event.
    '; return; } const furthestIdx=timelineFurthestIndex(progressStability.timeline||[]); root.innerHTML=visible.map(item=>{ const klass=contextualEventClass(item,furthestIdx); const label=contextualEventLabel(item,klass); const reason=eventReason(item); const reasonHtml=!hideEventReason(item)&&reason&&reason!==String(item.message||'').trim()?`

    ${escapeHtml(reason)}

    `:''; const icon=eventIconFor(item,klass); const step=String(item.step||'event').replace(/_/g,' '); const origin=eventOriginFor(item); return `
    ${renderEventIcon(icon)}
    ${escapeHtml(item.message||'Event received')}

    ${escapeHtml(step)}${escapeHtml(label||'')}

    ${reasonHtml}
    ${escapeHtml(origin)}
    `; }).join(''); if(shouldKeepLatestVisible)root.scrollTop=0; } function renderDiagnostics(d={},header={}){ setText('diagBuildStatus',badgeLabel(d.build_status||'pending')); setText('diagBuildStep',header.current_phase_label||'Waiting for run data'); const chips=$('statusChips'); if(chips){ const data=[['Build',d.build_status],['API',d.api_status],['Tests',d.tests_status],['Verdict',d.verdict_status]]; chips.innerHTML=data.map(([k,v])=>`${escapeHtml(k)}${escapeHtml(badgeLabel(v||'pending'))}`).join(''); } const issue=$('issueCard'); if(issue){ const has=Boolean(d.issue&&d.issue.title); issue.hidden=!has; if(has){ issue.className='issue-card '+statusClass(d.issue.status||d.issue.title); setText('issueTitle',d.issue.title); setText('issueDetail',d.issue.detail||d.issue.status||'Review logs.'); } } const rules=$('zeroGpuChecklist'); if(rules)rules.innerHTML=(d.zerogpu_rules||[]).map(r=>`
  • ${escapeHtml(r.label)}${escapeHtml(r.status||'pending')}
  • `).join(''); } function renderSpaceTestPreview(s={}){ const policy=s.policy||s.space_test_policy||{}; const metrics=s.validation_metrics||{}; const status=policy.mode||s.status||'pending'; const st=$('spaceTestStatus'); if(st){ st.textContent=policy.label||badgeLabel(status); st.className='badge '+(policy.enabled?statusClass(status):'neutral'); } const endpointLabel=policy.requires_endpoint_discovery?'Discovery first':(s.endpoint||policy.endpoint||metrics.api_name||s.output_artifact||'—'); setText('spaceTestEndpoint',endpointLabel); setText('spaceTestOutput',metrics.output_artifact||s.output_artifact||'Not launched'); const latency=metrics.latency_seconds||metrics.observed_latency_seconds||policy.smoke_latency_seconds||s.smoke_latency_seconds||s.latency_seconds||''; if(latency)setText('spaceTestLatency',`${formatLatencySeconds(latency)} from ${metrics.source||'automatic smoke'}`); setText('spaceTestVerdict',policy.message||s.verdict||'pending'); } function animateProgressBar(progress,status,currentStep){ const fill=$('progressFill'); if(!fill)return; const value=Math.max(0,Math.min(100,Number(progress||0))); const previous=progressMotionState.lastProgress; let klass=visualStatusClass(status);if(value>=100&&klass==='neutral')klass='success'; fill.style.setProperty('--progress-target',`${value}%`); fill.style.width=`${value}%`; fill.classList.remove('is-success','is-warn','is-error','is-running-state','is-stopped','is-neutral'); fill.classList.add(`is-${klass==='running'?'running-state':klass}`); const s=String(status||'').toLowerCase();fill.classList.toggle('is-running',klass==='running'||s==='pending'||s==='scheduled'||s==='waiting'); if(previous!==null&&Math.round(previous)!==Math.round(value)){ animateClass(fill,'progress-bump',650); const pct=$('progressPercent'); animateClass(pct,'value-bump',650); } progressMotionState.lastProgress=value; progressMotionState.lastStep=currentStep||progressMotionState.lastStep; } function animateStatusBadge(status){ const el=$('progressStatus'); if(!el)return; const next=String(status||'').toLowerCase(); if(progressMotionState.lastStatus&&progressMotionState.lastStatus!==next){ animateClass(el,'status-bump',800); } progressMotionState.lastStatus=next; } function progressProcessLabel(progress={},percent=0){ const terminal=Boolean(progress.terminal); const status=String(progress.process_status||'').toLowerCase(); if(terminal||Number(percent)>=100)return'Completed'; if(status.includes('running')||status.includes('waiting')||status.includes('pending'))return'In progress'; return status?badgeLabel(status):'In progress'; } function progressVerdictLabel(progress={},visualStatus=''){ const label=String(progress.label||'').trim(); const verdict=String(progress.verdict||visualStatus||'').trim(); if(label&&!(progress.terminal===true&&label.toLowerCase()==='running'))return label; return verdict?badgeLabel(verdict):'Pending verdict'; } function renderSemanticProgressSummary(progress={},percent=0,visualStatus=''){ const root=$('progressSemantics'); const caption=$('progressCaptionLabel'); const bar=$('progressBar'); if(caption)caption.textContent=progress&&progress.verdict?'Process progress':'Overall progress'; if(bar){ const value=Math.max(0,Math.min(100,Number(percent||0))); bar.setAttribute('aria-valuenow',String(Math.round(value))); bar.setAttribute('aria-label',progress&&progress.verdict?`Process progress ${Math.round(value)} percent, result ${progressVerdictLabel(progress,visualStatus)}`:`Overall progress ${Math.round(value)} percent`); } if(!root)return; if(!progress||!progress.verdict){root.hidden=true;root.innerHTML='';return;} const process=progressProcessLabel(progress,percent); const verdict=progressVerdictLabel(progress,visualStatus); const tone=visualStatusClass(visualStatus||progress.visual_status||progress.verdict); const subtitle=String(progress.subtitle||'').trim(); root.hidden=false; root.className=`progress-semantics ${tone}`; root.innerHTML=`Process ${escapeHtml(process)}Result ${escapeHtml(verdict)}${subtitle?`${escapeHtml(subtitle)}`:''}`; } function setElapsedClock(seconds,status){ const s=String(status||'').toLowerCase(); elapsedClock.baseSeconds=Math.max(0,Number(seconds||0)); elapsedClock.baseAt=Date.now(); elapsedClock.isRunning=Boolean(state.runId)&&!TERMINAL_STATUSES.has(s); setText('elapsed',fmtSeconds(elapsedClock.baseSeconds)); } window.setInterval(()=>{ if(!elapsedClock.isRunning)return; const live=elapsedClock.baseSeconds+Math.floor((Date.now()-elapsedClock.baseAt)/1000); setText('elapsed',fmtSeconds(live)); },1000); function progressIsSuccessStatus(status){ const s=String(status||'').toLowerCase(); return ['success','succeeded','done','full_inference_success'].includes(s); } function progressIsTerminalStatus(status){ const s=String(status||'').toLowerCase(); return PROGRESS_TERMINAL_STATUSES.has(s); } function timelineFurthestIndex(items){ const list=items||[]; let max=-1; list.forEach((item,i)=>{ const st=String(item.status||'pending').toLowerCase(); if(!['pending','status-pending','muted','status-muted'].includes(st))max=i; }); return max; } function cloneTimeline(items){ return (items||[]).map(x=>({...x})); } function resetProgressStability(runId=null){ progressStability.runId=runId; progressStability.progress=0; progressStability.timeline=null; progressStability.furthestIndex=-1; progressStability.status=''; progressStability.currentStep=null; progressMotionState.lastProgress=null; progressMotionState.lastStatus=null; progressMotionState.lastStep=null; const timeline=$('timeline'); if(timeline){timeline.dataset.signature='';timeline.dataset.visibleStep='';timeline.dataset.userScrolled='';timeline.classList.remove('trace-failed','trace-recovered','trace-fallback','timeline-canonical');timeline.scrollLeft=0;}const note=$('timelineTraceNote');if(note){note.hidden=true;note.innerHTML='';note.className='timeline-trace-note';}const details=$('timelinePhaseDetails');if(details){details.hidden=true;details.innerHTML='';details.className='timeline-phase-details';} } function stabilizeProgressPayload(p={},view=null){ const runId=String(p.run_id||view?.run_id||state.runId||''); if(progressStability.runId!==runId)resetProgressStability(runId); const status=String(view?.header?.status||p.status||p.state?.status||'').toLowerCase(); const terminal=progressIsTerminalStatus(status); const success=progressIsSuccessStatus(status); let rawProgress=Number(p.progress||0); let rawTimeline=cloneTimeline(p.timeline||view?.pipeline||[]); const rawIndex=timelineFurthestIndex(rawTimeline); if(success){ progressStability.progress=100; progressStability.timeline=rawTimeline; progressStability.furthestIndex=Math.max(progressStability.furthestIndex,rawIndex); }else if(terminal){ progressStability.progress=Math.max(progressStability.progress,rawProgress); if(rawIndex>=progressStability.furthestIndex||!progressStability.timeline){ progressStability.timeline=rawTimeline; progressStability.furthestIndex=rawIndex; }else{ rawTimeline=cloneTimeline(progressStability.timeline); } }else{ if(rawProgress>=progressStability.progress){ progressStability.progress=rawProgress; }else{ rawProgress=progressStability.progress; } if(rawIndex>=progressStability.furthestIndex||!progressStability.timeline){ progressStability.timeline=rawTimeline; progressStability.furthestIndex=rawIndex; }else{ rawTimeline=cloneTimeline(progressStability.timeline); } } const activeItem=activeTimelineItem(rawTimeline); progressStability.currentStep=activeItem?.step||activeItem?.id||activeItem?.label||progressStability.currentStep; progressStability.status=status; return { progress:success?100:Math.max(rawProgress,progressStability.progress), timeline:rawTimeline, status, currentStep:activeItem?.step||activeItem?.id||activeItem?.label||'', currentStepLabel:workerStepDisplayLabel(activeItem?.step||activeItem?.id)||activeItem?.label||'' }; } function renderRunViewModel(view,p={}){ const header=view.header||{}; const sm=view.status_model||{}; const stableEvents=mergeStableEvents(String(p.run_id||view.run_id||state.runId||''),p.events||[]); const timelineModel=view.timeline_model||p.timeline_model||null; const modelProgress=hasCanonicalTimelineModel(timelineModel)?(timelineModel.progress||{}):null; const stable=stabilizeProgressPayload(p,view); const canonical=canonicalRunUiState({view,...p}); const progress=Number(modelProgress?.percent??stable.progress??(canonical.isTerminal?100:(header.status==='succeeded'?100:0))); const runStatus=canonical.status; const visualRunStatus=canonical.visual_status||runStatus; const activePhase=hasCanonicalTimelineModel(timelineModel)?timelineModelActivePhase(timelineModel):null; // Legacy invariant: animateProgressBar(progress,visualRunStatus,stable.currentStep) remains true for non-canonical payloads. animateProgressBar(progress,visualRunStatus,activePhase?.id||stable.currentStep); setText('progressPercent',`${Math.round(progress)}%`); renderSemanticProgressSummary(modelProgress,progress,visualRunStatus); setText('progressTitle',canonical.label||header.title||view.run_id||'Live job progress'); const statusEl=$('progressStatus'); if(statusEl){ statusEl.textContent=canonical.label||badgeLabel(runStatus||'Running'); statusEl.className='badge '+statusClass(visualRunStatus); animateStatusBadge(visualRunStatus); } const latestEvent=stableEvents[stableEvents.length-1]; // Legacy invariant: setText('currentStep',stable.currentStepLabel remains the fallback path when no canonical phase is available. setText('currentStep',activePhase?`${activePhase.label}: ${activePhase.summary||activePhase.status}`:(stable.currentStepLabel||p.current_step_label||'—')); setText('lastEvent',modelProgress?.subtitle||eventMessage(latestEvent)||p.last_event||'Waiting for worker events.'); setElapsedClock(p.elapsed_seconds??header.elapsed_seconds,canonical.statusLower||runStatus); setText('lastPolled',new Date().toLocaleTimeString()); setText('detailSpace',header.space||'—'); setText('detailJobStatus',canonical.label||badgeLabel(runStatus||'—')); setText('detailGateStatus',sm.verdict||'—'); setText('detailTraces',Array.isArray(p.events)?`${p.events.length} events`:'—'); const cancel=$('cancelRun'); if(cancel){ const s=String(runStatus||'').toLowerCase(); const terminal=TERMINAL_STATUSES.has(s)||progressIsTerminalStatus(s); cancel.hidden=Boolean(terminal); cancel.disabled=!(state.runId&&view.links?.job_url&&!terminal); } if(!renderTimelineModel(timelineModel,runStatus))renderTimelinePlaceholder('Waiting for canonical run timeline…'); renderActivityFeed(Array.isArray(view.activity)&&view.activity.length?view.activity:stableEvents); renderDiagnostics(view.diagnostics||{},header); renderSpaceTestPreview(view.space_test||{}); renderManualAction({view,...p}); if(typeof renderAgentRecovery==='function')renderAgentRecovery(p); if(typeof renderRunDocuments==='function')renderRunDocuments(p); } function renderProgress(p){ if(p.view){ renderRunViewModel(p.view,p); return; } const stableEvents=mergeStableEvents(String(p.run_id||state.runId||''),p.events||[]); const stable=stabilizeProgressPayload(p,null); const progress=Number(stable.progress||0); animateProgressBar(progress,p.visual_status||p.status,stable.currentStep); setText('progressPercent',`${Math.round(progress)}%`); renderSemanticProgressSummary(null,progress,p.visual_status||p.status); const latestEvent=stableEvents[stableEvents.length-1]; setText('currentStep',stable.currentStepLabel||p.current_step_label||'—'); setText('lastEvent',eventMessage(latestEvent)||p.last_event||'—'); setElapsedClock(p.elapsed_seconds,p.status); setText('progressTitle',p.current_step_label||'Live job progress'); const statusEl=$('progressStatus'); if(statusEl){ statusEl.textContent=p.status||'running'; statusEl.className='badge '+statusClass(p.visual_status||p.status); animateStatusBadge(p.visual_status||p.status); } setText('lastPolled',new Date().toLocaleTimeString()); renderTimelinePlaceholder('Waiting for canonical run timeline…'); if(typeof renderAgentRecovery==='function')renderAgentRecovery(p); } // v189.2 compatibility anchors for older progress tests: // const visualRunStatus=p.visual_status||runStatus // setText('currentStep',stable.currentStepLabel // Legacy test anchors retained for timeline invariants: // currentStepLabel:activeItem?.label // x.done_count||0 // v164 compatibility anchors for older timeline tests: // display_label:'Model card' // active_substep_label:workerStepDisplayLabel(activeSubstep) // title="${escapeHtml(reason)}" // v165 compatibility anchors for historical timeline tests: // progress_label:group.steps.length>1 // total_count:group.steps.length // overall==='error'&&firstFailedIdx>=0&&groupIndex>firstFailedIdx // v165 historical scroll/test anchors kept as comments after the offset-math refactor: // requestAnimationFrame(()=>requestAnimationFrame(()=>ensureTimelineStepVisible // status='after_fail' // root.scrollLeft-(bounds.rootLeft+margin-bounds.targetLeft) // root.scrollLeft+(bounds.targetRight-(bounds.rootRight-margin)) // v189.3 semantic progress anchors: // renderSemanticProgressSummary(modelProgress,progress,visualRunStatus) // progressCaptionLabel = Process progress when timeline_model progress verdict is present // progress bar color follows visual_status, so 100% warn is not success // v190.18 compatibility anchor: Endpoint discovery required // v189.2 legacy anchor: if(!renderTimelineModel(timelineModel,runStatus))renderTimeline(stable.timeline,runStatus); // v189.2 compatibility anchors retained for string-based release tests: // const runStatus=modelProgress?.verdict||p.status||header.status; // setText('progressTitle',modelProgress?.label||header.title||view.run_id||'Live job progress'); // v189.2 compatibility anchors retained for string-based release tests: // const visualRunStatus=modelProgress?.visual_status||p.visual_status||runStatus; // statusEl.textContent=modelProgress?.label||badgeLabel(runStatus||'Running');