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','health_only','repair_success','repair_failed','succeeded','waiting_manual_action','blocked','stale','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'; } function isSuccessStatus(status){ const s=String(status||'').toLowerCase(); return s.includes('success')||s.includes('succeed')||s.includes('passed')||s==='done'||s==='completed'||s==='health_only'||s==='repair_success'||s==='full_inference_candidate_health_passed'||s==='full_inference_success'; } 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(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 compactReasonText(value,max=190){ const text=String(value||'').replace(/\s+/g,' ').trim(); if(!text)return ''; 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 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==='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'].includes(overall); if(status==='failed'||status==='error'||status==='failure')return'status-failed'; if(status==='fallback')return'status-fallback'; 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 eventMessage(event){ return event?.message||event?.step||'Waiting for worker events.'; } 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):stepKey.replace(/"/g,'\\"'); const target=root.querySelector(`[data-step="${safeStep}"]`); if(!target)return; const margin=22; const bounds=timelineStepBounds(root,target); const fullyVisible=bounds.targetLeft>=bounds.rootLeft+margin&&bounds.targetRight<=bounds.rootRight-margin; if(fullyVisible){ root.dataset.visibleStep=stepKey; return; } const maxScroll=Math.max(0,root.scrollWidth-root.clientWidth); let nextLeft=root.scrollLeft; // Keep-visible behavior: do not center. Only move the minimum amount needed // to reveal the current step with a small readable margin. // Equivalent old condition: targetRight>visibleRight-margin. if(bounds.targetLeftbounds.rootRight-margin){ nextLeft=root.scrollLeft+(bounds.targetRight-(bounds.rootRight-margin)); } nextLeft=Math.max(0,Math.min(maxScroll,Math.round(nextLeft))); if(Math.abs(nextLeft-root.scrollLeft)>2){ const behavior='auto'; 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','full_inference_candidate_health_passed','health_only','repair_success'].includes(String(overallStatus||'').toLowerCase()); const firstFailedIdx=firstFailedGroupIndex(overallStatus); const visibleGroups=visibleCompactTimelineGroups(items,overallStatus); return visibleGroups.map((group,groupIndex)=>{ const groupItems=group.steps.map(step=>byStep.get(step)).filter(Boolean); 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'&&firstFailedIdx>=0&&groupIndex>firstFailedIdx&&groupItems.length)status='after_fail'; 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):(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==='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); return { step:group.id, id:group.id, label:group.display_label||group.label, status, full_steps:group.steps, done_count:doneCount, total_count:group.steps.length, percent:clampedPercent, ring_progress:clampedPercent, active_substep:activeSubstep, active_substep_label:substepLabel, grouped:group.steps.length>1, progress_label:group.steps.length>1?`${Math.min(group.steps.length,Math.max(doneCount,clampedPercent>=100?group.steps.length:Math.ceil((clampedPercent/100)*group.steps.length)))}/${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 renderTimeline(items,overallStatus=''){ const root=$('timeline'); if(!root)return; if(!root.dataset.scrollBound){root.dataset.scrollBound='1';root.addEventListener('scroll',()=>{if(root.dataset.autoScrolling==='1')return;root.dataset.userScrolled='1'},{passive:true});} 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: 721px)').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 friendlySubstep=x.active_substep_label||workerStepDisplayLabel(x.active_substep); const meta=x.total_count>1?(x.status==='done'?'complete':(friendlySubstep?friendlySubstep:label)):label; const traceClass=traceClassForStep(trace,i); const reason=reasonForTimelineItem(x); const reasonLine=reason?`${escapeHtml(reason)}`:''; const titleParts=[x.label||`Step ${i+1}`,meta,x.total_count>1?`${x.done_count||0}/${x.total_count} substeps`: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';ensureTimelineStepVisible(currentKey,{instant:!root.dataset.visibleStep,force:previousKey!==currentKey});setTimeout(()=>{if(root)root.dataset.autoScrolling=''},180);} } 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 6V3m-6 8a6 6 0 0 1 12 0v5a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3v-5Zm3 1h2a2 2 0 0 1 2 2v2m-14 0V9a2 2 0 0 1 2-2h2m0 6h.01M15 13h.01M9 17h6', 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 19c2-1 3-2 4-4m-4 4c-1 1-2 1-3 1 0-1 0-2 1-3m2 2-2-2m13-8-4 4m0 0-3 7-5-5 7-3 4-4c2-2 5-3 8-3 0 3-1 6-3 8Z', 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:'M15 4l5 5m-7-3 5 5M4 20 16 8m-3-3 6 6M5 5h.01M9 3h.01M3 9h.01M19 19h.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=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 st=$('spaceTestStatus'); if(st){ st.textContent=badgeLabel(s.status||'pending'); st.className='badge '+statusClass(s.status); } setText('spaceTestOutput',s.output_artifact||s.endpoint||'Waiting for API test'); setText('spaceTestVerdict',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-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 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','full_inference_candidate_health_passed'].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.scrollLeft=0;}const note=$('timelineTraceNote');if(note){note.hidden=true;note.innerHTML='';note.className='timeline-trace-note';} } 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 stable=stabilizeProgressPayload(p,view); const progress=Number(stable.progress??(header.status==='succeeded'?100:0)); const runStatus=p.status||header.status; const visualRunStatus=p.visual_status||runStatus; animateProgressBar(progress,visualRunStatus,stable.currentStep); setText('progressPercent',`${Math.round(progress)}%`); setText('progressTitle',header.title||view.run_id||'Live job progress'); const statusEl=$('progressStatus'); if(statusEl){ statusEl.textContent=badgeLabel(runStatus||'Running'); statusEl.className='badge '+statusClass(visualRunStatus); animateStatusBadge(visualRunStatus); } const latestEvent=stableEvents[stableEvents.length-1]; setText('currentStep',stable.currentStepLabel||p.current_step_label||'—'); setText('lastEvent',eventMessage(latestEvent)||p.last_event||'Waiting for worker events.'); setElapsedClock(p.elapsed_seconds??header.elapsed_seconds,runStatus); setText('lastPolled',new Date().toLocaleTimeString()); setText('detailSpace',header.space||'—'); setText('detailJobStatus',header.raw_status||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(); cancel.disabled=!(state.runId&&view.links?.job_url&&!TERMINAL_STATUSES.has(s)); } renderTimeline(stable.timeline,runStatus); renderActivityFeed(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)}%`); 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()); renderTimeline(stable.timeline,p.status); if(typeof renderAgentRecovery==='function')renderAgentRecovery(p); } // 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)}"