function timelineIcon(status){status=String(status||'pending');if(status==='done'||status==='completed')return'✓';if(status==='running')return'•';if(status==='failed'||status==='blocked')return'!';if(status==='skipped')return'↷';return'○'}
function timelineStatus(status){status=String(status||'pending');if(status==='done'||status==='completed')return'completed';if(status==='running')return'running';if(status==='failed')return'failed';if(status==='blocked')return'blocked';return'pending'}
function renderTimeline(items){const root=$('timeline');if(!root)return;root.innerHTML=(items||[]).map((x,i)=>{const st=timelineStatus(x.status);return `
${timelineIcon(x.status)}
${escapeHtml(x.label||`Step ${i+1}`)}${st}
`}).join('')}
function renderActivityFeed(items){const root=$('activityFeed');if(!root)return;if(!items.length){root.innerHTML='
No activity yet. Waiting for the first worker event.
`).join('')}
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=>`