From b9c70528fafca3d3a77ba5e5625e349867ee10c4 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Wed, 7 Oct 2026 11:40:53 +0000 Subject: [PATCH] reliability injector: reads the fake cards by name and switches a box's real GPU off through the app's own card path Co-Authored-By: Claude Fable 5.1 --- tools/reliability/app-run.mjs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/tools/reliability/app-run.mjs b/tools/reliability/app-run.mjs index 03b2cd6ec..5e557cacb 100755 --- a/tools/reliability/app-run.mjs +++ b/tools/reliability/app-run.mjs @@ -91,12 +91,27 @@ if (!url) { log('no app.url'); process.exit(1); } async function state() { try { const r = await fetch(url + 'api/state'); return await r.json(); } catch { return null; } } -const card = (st) => (st && st.mining && st.mining.cards && st.mining.cards[0]) || {}; +// the fake cards only: a pod or a PC also lists its real GPU, which is switched off at start (through the app's own +// card path) and never read by a step +const fakes = (st) => ((st && st.mining && st.mining.cards) || []).filter(c => /^Fake GPU/.test(c.name || '')); +const card = (st) => fakes(st)[0] || {}; +let realOff = false; +async function switchRealCardsOff(st) { + if (realOff || !st || !st.mining) return; + const real = (st.mining.cards || []).filter(c => !/^Fake GPU/.test(c.name || '') && c.enabled); + if (!real.length) { realOff = true; return; } + try { + await fetch(url + 'api/cards', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ cards: real.map(c => ({ key: c.key, enabled: false, identities: c.identities || 1 })) }) }); + log(`real card(s) switched off for the run: ${real.map(c => c.name).join(', ')}`); + realOff = true; + } catch (e) { log(`api/cards: ${e}`); } +} const events = []; let last = ''; async function poll() { const st = await state(); if (!st) return null; + await switchRealCardsOff(st); const c = card(st); const key = [c.state, c.message, c.pid, c.restarts, c.faults, st.node.state, st.node.starts, c.hash_now > 0 ? '>0' : '0'].join('|'); if (key !== last) { last = key; events.push({ t: Date.now(), key }); log(`card ${c.state || '(none)'} pid ${c.pid} restarts ${c.restarts} faults ${c.faults} hash ${Number(c.hash_now || 0).toFixed(1)} node ${st.node.state} starts ${st.node.starts} ${c.message ? '"' + c.message + '"' : ''}`); } @@ -285,15 +300,15 @@ S['one-card-fails'] = async () => { const exportsBefore = engineLogLines(/export-pack: /).length; writeFileSync(CTL, 'ok\ndevices 3\ndev 2 selftest\n'); log('fake worker: 3 devices, device 2 fails its self-test'); const tInject = Date.now(); - const listed = await until((st) => st.mining.cards.length >= 3, 200000, 'three cards listed'); + const listed = await until((st) => fakes(st).length >= 3, 200000, 'three fake cards listed'); const tListed = Date.now(); - const twoMine = await until((st) => st.mining.cards.filter(c => c.state === 'mining' && c.hash_now > 0).length >= 2, 300000, 'two healthy cards mining'); + const twoMine = await until((st) => fakes(st).filter(c => c.state === 'mining' && c.hash_now > 0).length >= 2, 300000, 'two healthy cards mining'); const tTwo = Date.now(); - const held = await until((st) => st.mining.cards.some(c => /not usable on this driver/.test(c.message || '')), 120000, 'the failing card held with the reason'); + const held = await until((st) => fakes(st).some(c => /not usable on this driver/.test(c.message || '')), 120000, 'the failing card held with the reason'); await steady(90000); const st1 = await poll(); - const bad = st1 ? st1.mining.cards.find(c => /not usable on this driver/.test(c.message || '')) : null; - const good = st1 ? st1.mining.cards.filter(c => !/not usable/.test(c.message || '')) : []; + const bad = st1 ? fakes(st1).find(c => /not usable on this driver/.test(c.message || '')) : null; + const good = st1 ? fakes(st1).filter(c => !/not usable/.test(c.message || '')) : []; const exportsAfter = engineLogLines(/export-pack: /).length - exportsBefore; const reused = engineLogLines(/export-pack: reusing/).length; verdict('one-card-fails', [