Driver check: every card of the vendor stops for the install (0.3.22; PC 2's Arc in the Razer Core X V2 read kind=discrete on 0.3.21, so the external-kind hold alone missed the card that crashed the box at 16:27Z)
drivertable::install_hold_keys holds every enabled card of the vendor being installed (the other vendors' cards keep mining; a card already off has nothing to stop); the row says so before the click and while it runs, with the enclosure warning kept on an external row; the toast and the engine's event name the vendor. The x1 gen1 link signature is not on the card state and was not added. Test known-failed first (the 5090 inside the case was not held for an NVIDIA install; red on build-2, then green); box gate 259 + 33 + 8; UI 51. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
382b441a64
commit
8b2c53e48d
5 changed files with 40 additions and 29 deletions
|
|
@ -244,20 +244,21 @@ pub fn authenticode_verdict(text: &str, signer: &str) -> Result<String, String>
|
|||
Ok(subject)
|
||||
}
|
||||
|
||||
/// The cards whose worker stops before a vendor's driver installer starts: that vendor's cards the app reads as
|
||||
/// external (the eGPU kind: a USB4 or Thunderbolt router in the device's parent chain). PC 2, 7 October 2026, 16:26Z:
|
||||
/// the Intel installer's display reset took the machine down while the app's own worker mined on the Arc in the Razer
|
||||
/// Core X V2; the machine needed a power cycle. The other cards keep mining through the install. Each item is
|
||||
/// (key, vendor, kind, enabled); a card already off has nothing to stop.
|
||||
/// The cards whose worker stops before a vendor's driver installer starts: every enabled card of that vendor. PC 2,
|
||||
/// 7 October 2026, 16:26Z: the Intel installer took the kernel down (bugcheck 0x3B) with the app's worker mining on the
|
||||
/// Arc B580 in a Razer Core X V2; at 19:14 BST the same card read kind=discrete on 0.3.21 (no USB4 or Thunderbolt
|
||||
/// router in its parent chain on that board), so a hold keyed on the external kind alone would have missed the card
|
||||
/// that crashed the box. The rule since 0.3.22 (the shipper's word, 19:1x BST): the vendor's cards all stop, the other
|
||||
/// vendors' cards keep mining, a card already off has nothing to stop. Each item is (key, vendor, kind, enabled).
|
||||
pub fn install_hold_keys<'a>(cards: impl IntoIterator<Item = (&'a str, &'a str, &'a str, bool)>, vendor: &str) -> Vec<String> {
|
||||
cards.into_iter().filter(|(_, v, kind, enabled)| *v == vendor && *kind == "external" && *enabled).map(|(key, _, _, _)| key.to_string()).collect()
|
||||
cards.into_iter().filter(|(_, v, _, enabled)| *v == vendor && *enabled).map(|(key, _, _, _)| key.to_string()).collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn an_install_on_an_egpu_card_stops_that_cards_worker_first_and_leaves_the_other_cards_mining() {
|
||||
fn a_driver_install_stops_every_card_of_its_vendor_first_and_leaves_the_other_vendors_mining() {
|
||||
// PC 2, 7 October 2026: the Arc B580 in the Razer Core X V2 was mining when the Intel installer's display
|
||||
// reset took the machine down. The rule: the vendor's external cards stop, nothing else does.
|
||||
let cards = [
|
||||
|
|
@ -267,11 +268,16 @@ mod tests {
|
|||
("intel::Intel UHD 770", "other", "integrated", false),
|
||||
];
|
||||
assert_eq!(install_hold_keys(cards, "intel"), vec!["intel:Intel(R) Arc(TM) B580 Graphics".to_string()], "the Arc in the enclosure stops; the NVIDIA cards and the iGPU keep mining");
|
||||
assert_eq!(install_hold_keys(cards, "nvidia"), vec!["nvidia:1:NVIDIA GeForce RTX 5060 Ti".to_string()], "the 5060 Ti in the enclosure stops; the 5090 inside the case keeps mining");
|
||||
assert_eq!(install_hold_keys(cards, "nvidia"), vec!["nvidia:0:NVIDIA GeForce RTX 5090".to_string(), "nvidia:1:NVIDIA GeForce RTX 5060 Ti".to_string()], "every NVIDIA card stops for the NVIDIA install, inside the case or not");
|
||||
assert!(install_hold_keys(cards, "amd").is_empty(), "no AMD card: nothing stops");
|
||||
// an external card already off has nothing to stop; a discrete card of the vendor is not held
|
||||
// a card already off has nothing to stop; a discrete card of the vendor IS held (PC 2, 19:14 BST: the Arc in the
|
||||
// Razer Core X V2 read kind=discrete on 0.3.21, so the kind alone would have missed the card that crashed the box)
|
||||
let off = [("intel:Intel(R) Arc(TM) B580 Graphics", "intel", "external", false), ("intel:Intel(R) Arc(TM) A770 Graphics", "intel", "discrete", true)];
|
||||
assert!(install_hold_keys(off, "intel").is_empty());
|
||||
assert_eq!(install_hold_keys(off, "intel"), vec!["intel:Intel(R) Arc(TM) A770 Graphics".to_string()]);
|
||||
// the iGPU carries vendor "other" on PC 2 (an AMD Radeon(TM) Graphics as amd:gfx1036 on another read): the install's
|
||||
// vendor word decides, and a card off stays untouched
|
||||
let igpu = [("amd:gfx1036", "amd", "integrated", false), ("amd:gfx1201", "amd", "discrete", true)];
|
||||
assert_eq!(install_hold_keys(igpu, "amd"), vec!["amd:gfx1201".to_string()]);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1718,7 +1718,7 @@ impl Engine {
|
|||
self.shared.event("info", &format!("driver install started: {} {} ({} MB) from the vendor's server{}", vendor.to_ascii_uppercase(), e.version, (e.size + 512 * 1024) / (1024 * 1024), if dry { ", dry run" } else { "" }));
|
||||
// PC 2, 7 October 2026, 16:26Z: the Intel installer's display reset took the machine down while the app's own
|
||||
// worker mined on the Arc in the Razer Core X V2 (a power cycle). The vendor's cards the app reads as external
|
||||
// (drivertable::install_hold_keys) stop before the installer starts; the other cards keep mining; each held card
|
||||
// (drivertable::install_hold_keys: since 0.3.22 every card of the vendor) stop before the installer starts; the other vendors' cards keep mining; each held card
|
||||
// comes back as it was when the installer ends, or when the card itself returns if the install took it away.
|
||||
let (off, restore): (Vec<CardChoice>, Vec<CardChoice>) = {
|
||||
let st = self.st();
|
||||
|
|
@ -1727,7 +1727,7 @@ impl Engine {
|
|||
crate::jobrun::cards_off_choices(&keys, &live)
|
||||
};
|
||||
if !off.is_empty() {
|
||||
self.shared.event("info", &format!("driver install: the worker on {} stops for the install (a card in an external enclosure; the display reset can take the machine for a minute); the other cards keep mining", off.iter().map(|c| c.key.as_str()).collect::<Vec<_>>().join(", ")));
|
||||
self.shared.event("info", &format!("driver install: the worker on {} stops for the install (every {} card; the display resets, and a card in an external enclosure can take the machine for a minute); the other vendors' cards keep mining", off.iter().map(|c| c.key.as_str()).collect::<Vec<_>>().join(", "), vendor.to_ascii_uppercase()));
|
||||
self.apply_cards(off);
|
||||
}
|
||||
self.driver_held = restore;
|
||||
|
|
|
|||
|
|
@ -413,9 +413,10 @@ var View = (function () {
|
|||
var o = cd.driver_offer, d = (s && s.drivers) || {};
|
||||
if (!o) return { kind: 'none', text: '' };
|
||||
var mine = d.vendor && d.vendor === o.vendor, ext = cd.kind === 'external';
|
||||
// PC 2, 7 October 2026: a card in an external enclosure (the eGPU kind) has its worker stopped for the install, and the
|
||||
// installer's display reset can take the machine; the row says both before the click and while it runs
|
||||
var extRun = ext ? '. This card\u2019s worker is stopped until the installer ends; the display reset can take the machine for a minute.' : '';
|
||||
// PC 2, 7 October 2026: every card of the vendor has its worker stopped for the install (0.3.22; the Arc in the Razer
|
||||
// Core X V2 read as discrete, so the kind alone missed it), and the installer's display reset can take a machine with an
|
||||
// enclosure; the row says both before the click and while it runs
|
||||
var extRun = '. The ' + vendorWord(o.vendor) + ' workers are stopped until the installer ends; the display may reset' + (ext ? ', and this card\u2019s enclosure can take the machine for a minute' : '') + '.';
|
||||
if (mine && (d.status === 'downloading' || d.status === 'verifying' || d.status === 'installing')) {
|
||||
var pct = d.status === 'downloading' ? Math.round((d.progress || 0) * 100) + '%' : '';
|
||||
return { kind: 'running', text: (d.status === 'downloading' ? 'Downloading the ' : d.status === 'verifying' ? 'Checking the ' : 'Installing the ') + vendorWord(o.vendor) + ' driver ' + d.version + (pct ? ' · ' + pct : ''), sub: (d.message || '') + extRun, progress: d.progress || 0, dry: !!d.dry_run, external: ext };
|
||||
|
|
@ -426,7 +427,7 @@ var View = (function () {
|
|||
if (o.status === 'none') return { kind: 'note', text: o.text };
|
||||
if (!o.installable) return { kind: 'note', text: o.text };
|
||||
var sub = 'Downloaded from ' + hostOf(o.url) + ', checked against the vendor\u2019s published hash and signature, then installed with one administrator prompt. ';
|
||||
sub += ext ? 'This card\u2019s worker stops for the install and comes back after it; the other cards keep mining. The display reset can take the machine for a minute and may need a restart: save your work first.' : 'Mining continues.';
|
||||
sub += 'The worker on every ' + vendorWord(o.vendor) + ' card stops for the install and comes back after it; the other cards keep mining. The display resets during the install' + (ext ? ', and a card in an external enclosure can take the machine for a minute and may need a restart' : '') + ': save your work first.';
|
||||
return { kind: 'offer', text: o.text, button: 'install', sub: sub, external: ext };
|
||||
}
|
||||
function vendorWord(v) { return v === 'nvidia' ? 'NVIDIA' : v === 'amd' ? 'AMD' : v === 'intel' ? 'Intel Arc' : v === 'apple' ? 'Apple' : v; }
|
||||
|
|
@ -1577,7 +1578,7 @@ if (typeof document !== 'undefined') (function () {
|
|||
else if (b.dataset.d) { var inp = b.parentNode.querySelector('input'), v = parseInt(inp.value, 10) || 1; inp.value = Math.max(1, Math.min(64, v + parseInt(b.dataset.d, 10))); sendCards('Identities set; that card’s worker restarts'); }
|
||||
else if (b.dataset.pin !== undefined) api('api/sweep/pin', { key: key, pinned: b.dataset.pin === '1' }).then(function () { toast(b.dataset.pin === '1' ? 'Cap pinned' : 'Default: Ember chooses the cap again'); });
|
||||
else if (b.dataset.powerRetry !== undefined) api('api/power/apply', {}).then(function () { toast('Allow the administrator prompt to set the cap'); });
|
||||
else if (b.dataset.driverInstall !== undefined) api('api/drivers/install', { vendor: b.dataset.driverInstall }).then(function (r) { toast(r && r.ok === false ? (r.error || 'could not start the driver install') : 'Driver download started. Windows asks for permission once before the install. Mining continues.'); });
|
||||
else if (b.dataset.driverInstall !== undefined) api('api/drivers/install', { vendor: b.dataset.driverInstall }).then(function (r) { toast(r && r.ok === false ? (r.error || 'could not start the driver install') : 'Driver download started. Windows asks for permission once before the install; the workers on this vendor\u2019s cards stop for it and come back after.'); });
|
||||
else if (b.dataset.driverRestart !== undefined) { if (window.confirm('Restart Windows now to finish the driver install? Mining stops until the app is back.')) api('api/drivers/restart', {}).then(function () { toast('Restarting in 20 seconds'); }); }
|
||||
else if (b.dataset.price !== undefined) { showPage('settings'); $('s-price').focus(); }
|
||||
else if (b.closest('[data-card-goal]') && b.dataset.goal !== undefined) {
|
||||
|
|
|
|||
|
|
@ -112,25 +112,29 @@ test('driver-check: the row\'s driver strip per state (offer, running, reboot, e
|
|||
assert.equal(V.vendorWord('amd'), 'AMD');
|
||||
});
|
||||
|
||||
test('driver-check: an install offer on an eGPU card warns that its worker stops and the display reset can take the machine (PC 2, 7 October 2026)', () => {
|
||||
test('driver-check: an install offer says every card of the vendor stops, and an eGPU card adds the machine warning (PC 2, 7 October 2026; every-card rule 0.3.22)', () => {
|
||||
const offer = { vendor: 'intel', status: 'old', installed: '32.0.101.6733', wanted: '32.0.101.9034', min_version: '32.0.101.9034', size: 932631144, url: 'https://downloadmirror.intel.com/929959/gfx_win_101.9034.exe', hash_source: 'https://www.intel.com/content/www/us/en/download/785597/', text: 'Install the Intel Arc driver 32.0.101.9034, 889 MB (the worker needs 32.0.101.9034 or newer; 32.0.101.6733 is installed)', installable: true };
|
||||
const idle = { drivers: { status: 'idle', vendor: '', version: '', progress: 0, message: '', error: '', reboot_required: false, dry_run: false } };
|
||||
const egpu = card({ key: 'intel:Intel(R) Arc(TM) B580 Graphics', name: 'Intel(R) Arc(TM) B580 Graphics', vendor: 'intel', kind: 'external', worker: 'OpenCL', enabled: true, state: 'mining', driver_offer: offer });
|
||||
let w = V.driverWords(egpu, idle);
|
||||
assert.equal(w.kind, 'offer');
|
||||
assert.equal(w.external, true);
|
||||
assert.ok(w.sub.includes('This card\u2019s worker stops for the install and comes back after it; the other cards keep mining.'), w.sub);
|
||||
assert.ok(w.sub.includes('The display reset can take the machine for a minute and may need a restart'), w.sub);
|
||||
// the same card inside the case: no stop, the plain sentence
|
||||
assert.ok(w.sub.includes('The worker on every Intel Arc card stops for the install and comes back after it; the other cards keep mining.'), w.sub);
|
||||
assert.ok(w.sub.includes('a card in an external enclosure can take the machine for a minute and may need a restart'), w.sub);
|
||||
// the same card read as inside the case (PC 2's Arc on 0.3.21 read discrete in its enclosure): the stop sentence stays,
|
||||
// the enclosure warning goes
|
||||
const inside = card({ ...egpu, kind: 'discrete' });
|
||||
w = V.driverWords(inside, idle);
|
||||
assert.equal(w.external, false);
|
||||
assert.ok(w.sub.endsWith('Mining continues.'), w.sub);
|
||||
assert.ok(!w.sub.includes('display reset'));
|
||||
// while it installs on the eGPU card, the running line says the worker is stopped
|
||||
assert.ok(w.sub.includes('The worker on every Intel Arc card stops for the install'), w.sub);
|
||||
assert.ok(w.sub.endsWith('The display resets during the install: save your work first.'), w.sub);
|
||||
assert.ok(!w.sub.includes('Mining continues.'));
|
||||
// while it installs, the running line says the vendor's workers are stopped; the eGPU row adds its enclosure
|
||||
w = V.driverWords(egpu, { drivers: { status: 'installing', vendor: 'intel', version: '32.0.101.9034', progress: 0.7, message: 'installing INTEL 32.0.101.9034: Windows asks for permission once', dry_run: false } });
|
||||
assert.equal(w.kind, 'running');
|
||||
assert.ok(w.sub.includes('This card\u2019s worker is stopped until the installer ends'), w.sub);
|
||||
assert.ok(w.sub.includes('The Intel Arc workers are stopped until the installer ends; the display may reset, and this card\u2019s enclosure can take the machine'), w.sub);
|
||||
w = V.driverWords(inside, { drivers: { status: 'installing', vendor: 'intel', version: '32.0.101.9034', progress: 0.7, message: 'x', dry_run: false } });
|
||||
assert.ok(w.sub.endsWith('The Intel Arc workers are stopped until the installer ends; the display may reset.'), w.sub);
|
||||
});
|
||||
|
||||
test('a card behind a USB4 or Thunderbolt router is an eGPU on the Cards page (PC 2, 7 October 2026)', () => {
|
||||
|
|
|
|||
|
|
@ -41,15 +41,15 @@ Apple: none. The exit codes: Intel 14 and 1014 (the bootstrapper's wrap, measure
|
|||
|
||||
Sizes: the installers are 889 MB to 1.0 GB each; the download lands in `<app data>/drivers/` and stays (a second click reuses it when its sha256 still matches). Time: the download at a home line of 50 Mbit/s is 2.5 to 3 minutes; the install 1 to 4 minutes; the prompt is the only wait on the user.
|
||||
|
||||
## 3b. A card in an external enclosure (7 October 2026, after PC 2)
|
||||
## 3b. The vendor's cards stop for the install (7 October 2026, after PC 2; every card of the vendor since 0.3.22)
|
||||
|
||||
PC 2 at 16:26Z: the Intel installer started with the app's own worker mining on the Arc B580 in the Razer Core X V2. The installer's display reset took the machine down at 16:27:14Z (every log stops together; a power cycle). The rule, on this branch:
|
||||
|
||||
- A driver install on a card the app reads as `external` (the eGPU kind: a USB4 or Thunderbolt router in the device's parent chain, update-return-21b) stops that card's worker before the installer starts (`drivertable::install_hold_keys`, through the cards path with the restore choice kept, the `--cards-off` shape). The vendor's cards inside the case and every other vendor's card keep mining.
|
||||
- The row says so before the click ("This card's worker stops for the install and comes back after it; the other cards keep mining. The display reset can take the machine for a minute and may need a restart: save your work first.") and while it runs ("This card's worker is stopped until the installer ends; the display reset can take the machine for a minute.").
|
||||
- A driver install stops the worker on every enabled card of that vendor before the installer starts (0.3.22, the shipper's word 19:1x BST; the first cut held only the `external` kind, and at 19:14 BST PC 2's Arc in the Razer Core X V2 read `discrete` on 0.3.21, no USB4 or Thunderbolt router in its parent chain on that board, so the kind alone would have missed the card that crashed the box; the x1 gen1 link signature is not on the card state and was not added) (`drivertable::install_hold_keys`, through the cards path with the restore choice kept, the `--cards-off` shape). The vendor's cards inside the case and every other vendor's card keep mining.
|
||||
- The row says so before the click ("The worker on every Intel Arc card stops for the install and comes back after it; the other cards keep mining. The display resets during the install, and a card in an external enclosure can take the machine for a minute and may need a restart: save your work first."; the enclosure clause only on an `external` row) and while it runs ("The Intel Arc workers are stopped until the installer ends; the display may reset.").
|
||||
- When the installer ends the held card goes back as it was (enabled, identities, cap). A card the install took away (Windows re-enumerates an eGPU through the reset) comes back when the card does: the detection that lists it again restores it (`driver_release_held(true)`). The app never restarts the machine.
|
||||
|
||||
Per tier: a solo miner with one eGPU loses that card's rate for the install (3 to 8 minutes on a home line, the download dominating) and nothing else; a rig with the card inside the case sees no change; macOS and Linux have no install step. Tests: the known-failed rule test first (an install on an eGPU card with the worker still running held nothing: `an_install_on_an_egpu_card_stops_that_cards_worker_first_and_leaves_the_other_cards_mining`, red on build-2 at 17:1xZ, then green), the view test for the two sentences. Captures 13 to 16: the eGPU offer (13, 14) and the install running with the card's worker off (15, 16), mock scenarios `drivers-egpu` and `drivers-egpu-running`.
|
||||
Per tier: a miner loses the installing vendor's rate for the install (PC 2: the Arc's 11 of 173 MH/s for an Intel install; a one-vendor rig loses everything for those minutes, which is what the installer does to the driver anyway) (3 to 8 minutes on a home line, the download dominating) and nothing else; a rig with the card inside the case sees no change; macOS and Linux have no install step. Tests: the known-failed rule test first (an install on an eGPU card with the worker still running held nothing: `an_install_on_an_egpu_card_stops_that_cards_worker_first_and_leaves_the_other_cards_mining`, red on build-2 at 17:1xZ, then green), the view test for the two sentences. Captures 13 to 16: the eGPU offer (13, 14) and the install running with the card's worker off (15, 16), mock scenarios `drivers-egpu` and `drivers-egpu-running`.
|
||||
|
||||
## 4. Not done, and what follows
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue