From 2c15edac94feb5e0abc632d32948e95f1f2e1982 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:35:21 +0000 Subject: [PATCH] workers page: render from the merged workers.json only (the hardcoded per-box feed map of build-1 to 3 dropped), the mini card (igneum-mini, the Mac build box, M6; no report yet until its collector pushes), the MacBook copy; read back on build-2 in Playwright: ten server cards and the crew row (8 Oct 2026) Co-Authored-By: Claude Fable 5.1 --- tools/workers/page/workers.html | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/tools/workers/page/workers.html b/tools/workers/page/workers.html index c8cd83335..3b27f5be5 100644 --- a/tools/workers/page/workers.html +++ b/tools/workers/page/workers.html @@ -191,7 +191,7 @@ function arc(pct, cls) { } const tone = (pct, warn = 70, bad = 90) => pct >= bad ? 'bad' : pct >= warn ? 'warn' : ''; -const FEEDS = { 'igneum-build-1': 'https://build.igneum.network/workers.json', 'igneum-build-2': 'https://build-2.igneum.network/workers.json', 'igneum-build-3': 'https://build-3.igneum.network/workers.json' }; +// the merged workers.json from build-1 (merge-workers.mjs, every 20 s) is the one source for every card; no per-box feed map (8 Oct 2026) const buildHeld = b => (b.slots && b.slots.held || []).filter(h => /^build-\d+$/.test(h.slot)).length; const boxesOf = d => (Array.isArray(d.boxes) && d.boxes.length ? d.boxes : d.box ? [{ ...d.box, source: d.sources && d.sources.box, headline: d.headline }] : []); function serverSection(b, i) { @@ -215,7 +215,12 @@ function serverSection(b, i) {
${arc(b.slots ? (buildHeld(b) / Math.max(1, b.slots.count)) * 100 : 0, 'good')}
Build slots
${b.slots ? `${buildHeld(b)}/${b.slots.count}` : '–'}
${b.queue && b.queue.length ? `${b.queue.length} waiting${b.queue.some(q => q.priority === 'gate') ? ', a gate first' : ''}` : 'nobody waiting'}
`; } -function renderServers() { const bx = boxesOf(D); $('servers').innerHTML = bx.length ? bx.map(serverSection).join('') : serverSection(null, 0); } +function miniSection() { + const m = D && D.mini; const name = 'igneum-mini'; const label = 'the Mac build box, M6'; + if (!m || !m.source || !m.source.ok) return `
${name}${label}
no report yet (its collector pushes every 20 s once it runs)
`; + return serverSection({ ...m, name: `${name} (${label})` }, 99); +} +function renderServers() { const bx = boxesOf(D); $('servers').innerHTML = (bx.length ? bx.map(serverSection).join('') : serverSection(null, 0)) + miniSection(); } function slotBar(slots, count) { const held = new Map((slots && slots.held || []).map(h => [h.slot, h])); @@ -233,7 +238,7 @@ function renderCrew() { const held = mac.slots.held || [], runs = held.filter(h => /^run-/.test(h.slot)), builds = held.filter(h => /^build-/.test(h.slot)), meas = held.filter(h => h.slot === 'measure'); const doing = held.length ? held.map(h => `${esc(h.slot)}: ${esc((h.worktree ? h.worktree + ' ' : '') + (h.command || h.label || ''))}`.slice(0, 140)).join('
') : 'Nothing under with-lock.sh. macOS binaries and the DMG build here; everything else goes to the box or the PCs.'; cards.push(`
${esc(mac.name)}
this Mac, ${mac.build_slots} build slot${mac.build_slots === 1 ? '' : 's'} open, 3 run slots
${pill(meas.length ? 'measuring' : builds.length ? 'building' : runs.length ? 'running' : 'idle', held.length ? 'running' : '')}
${doing}
${['build-0', 'build-1', 'build-2', 'run-0', 'run-1', 'run-2', 'measure'].map(nm => { const h = held.find(x => x.slot === nm); return ``; }).join('')}
${mac.queue.length ? mac.queue.length + ' waiting for a slot' : 'nobody waiting'}${esc(ago(mac.collected_at))}
`); - } else cards.push(`
MacBook-Pro
this Mac
${pill('no push', 'error')}
${esc(D.sources && D.sources.mac && D.sources.mac.error || 'the Mac pusher has not written yet (launchd com.igneum.workers-push, every 60 s)')}
`); + } else cards.push(`
MacBook (nothing builds here except the one DMG)-Pro
this Mac
${pill('no push', 'error')}
${esc(D.sources && D.sources.mac && D.sources.mac.error || 'the Mac pusher has not written yet (launchd com.igneum.workers-push, every 60 s)')}
`); for (const pc of pcs) { const r = pc.running; cards.push(`
${esc(pc.name)}
${esc(pc.machine || pc.id)} · ${esc(pc.role)}
${pill(r ? 'running' : pc.queue.length ? 'queued' : 'idle', r ? 'running' : pc.queue.length ? 'queued' : '')}
${r ? `${esc(r.kind)} ${esc(r.job)}${r.title ? '
' + esc(r.title) : ''}${r.stage ? `
stage ${esc(r.stage)}` : ''}` : pc.queue.length ? `Next: ${esc(pc.queue[0].kind)} ${esc(pc.queue[0].job)}${pc.queue[0].title ? ', ' + esc(pc.queue[0].title) : ''}` : esc(pc.note || 'idle on jobs; the relay polls every 10 min')}
${pc.recent.length} reports kept${pc.last_report_at ? 'last report ' + esc(ago(pc.last_report_at)) : 'no report in 7 days'}
`); @@ -378,18 +383,7 @@ async function load() { try { const file = demo ? 'workers.demo.json' : 'workers.json'; edge = await fetchJson(`${base}/${file}`, 8000); } catch (e) { if (!D && (demo || skipLive > 0)) { $('live').className = 'live down'; $('stamp').textContent = `workers.json not reachable (${e && e.message || e})`; } } if (demo) { d = edge; feed = 'demo document'; } - else if (skipLive <= 0) { - // the boxes the edge copy knows (or build-1 alone before the first push), each from its own Caddy feed, 4 s each, in parallel - const names = edge ? boxesOf(edge).map(b => b.name).filter(Boolean) : ['igneum-build-1']; - const results = await Promise.all(names.map(n => FEEDS[n] ? fetchJson(FEEDS[n], 4000).then(j => ({ n, j })).catch(() => ({ n, j: null })) : Promise.resolve({ n, j: null }))); - const liveOnes = results.filter(r => r.j); - if (liveOnes.length) { - const first = liveOnes[0].j; - const boxes = results.map(r => r.j ? { ...r.j.box, headline: r.j.headline, source: { ok: true, at: r.j.generated_at } } : (edge && boxesOf(edge).find(b => b.name === r.n)) || { name: r.n, source: { ok: false, error: 'no live feed and no edge copy for this box' } }); - d = { ...first, boxes, mac: first.mac || (edge && edge.mac), pcs: first.pcs || (edge && edge.pcs), baselines: first.baselines || (edge && edge.baselines), sources: { ...(first.sources || {}), box: boxes[0].source } }; - feed = liveOnes.length === results.length ? `live from ${liveOnes.length === 1 ? 'the box' : liveOnes.length + ' boxes'}` : `live from ${liveOnes.map(r => r.n).join(', ')}, edge copy for the rest`; - } else skipLive = 4; // nothing answered: use the edge copy for the next minute before trying again - } else skipLive--; + else { d = edge; feed = edge ? 'the merged copy from build-1' : feed; } if (!d) { d = edge; feed = 'edge copy, up to 5 min behind the box'; } if (!d) { if (!D) { $('now').innerHTML = $('queue').innerHTML = `
No workers.json next to this page yet and no box answers. The Mac pusher writes the copy every 60 s and the fleet deploy carries it within 5 min.
`; } return; } d._feed = feed; apply(d);