# Driver check: the app detects a missing or old driver and installs it on one click (branch driver-check, 7 October 2026) the project lead: "can we package the drivers with the miner? for all cards? and the system knows which to install if not present". The answer given: not bundled (size, vendor licences, staleness), but detected and installed on one click. Built off the release-0.3.20 app tree (082f70fb) for 0.3.20's app or the next cut; every cargo build and test on the box. ## 1. What is built | Piece | Where | |---|---| | The per-vendor table, validated in the signer and the app alike (`Table::parse`): min_version (what the worker needs), version, the vendor's own URL, size, sha256, the page the hash was read from, the silent arguments, the exit codes that mean "restart required", the Authenticode subject word, the Linux and HiveOS package | `app/igneum-app/src/drivertable.rs` (pure, shared with `src/bin/ota-sign.rs`), `packaging/ota/drivers.json` (today's table) | | The table rides the manifest: `drivers` object, parsed and validated with the rest, written as is to `/drivers.json`, re-read on every change; the app never ships a driver | `src/manifest.rs` (`Manifest.drivers`), `src/ota.rs` (`write_drivers`, `take_drivers_change`, `drivers_table`), `packaging/ota/publish-manifest.sh --drivers | --no-drivers` (carried over like tuning) | | Each card's driver version: nvidia-smi's `driver_version` for NVIDIA, Windows' `DriverVersion` (the adapter row) for AMD and Intel; `CardState.driver_os` | `src/detect.rs` (the query, the `Adapter.driver` field, `assemble`) | | The check at first run and every detection, and on every table change: the offer per card (`CardState.driver_offer`: status missing, old, fine or none; the row's sentence; installable on Windows only) | `src/engine.rs` (`refresh_driver_offers`, called from the `Detected` arm and `tick_update`) | | The click: download from the vendor's server (curl with resume into `/drivers/`), size and sha256 against the table, the Authenticode signature (status Valid, subject carries the vendor), then the installer through ONE elevated prompt (`platform::elevated_command`, the PC 1 driver job's shape), the exit code read (0 installed, a table code = restart required, else an error), "Restart now" on the row; the app never restarts by itself; nothing else pauses (the miners keep mining) | `src/drivers.rs` (`start_install`, `download`, `exit_code_of`, `restart_now`), `src/engine.rs` (`driver_install`, `driver_event`), `src/server.rs` (`POST api/drivers/install {vendor}`, `POST api/drivers/restart`) | | The row: "Install the NVIDIA driver 581.57 (965 MB). Driver 566.36 is older than the 570.00 the worker needs." with the Install button on the dashboard's card row and on the first-run card list; the progress line; "installed, restart Windows to finish" with Restart now; the error with Install again; macOS "no driver step"; Linux and HiveOS the package line, no button | `ui/app.js` (`View.driverWords`, the `gl-driver` strip, `setupDriverHtml`, the click handlers), `ui/app.css` | | Dry run: `IGNEUM_DRIVER_DRY_RUN=1` or `dry_run: true` in the table: the download and every check run, the installer does not (the row says so) | `src/drivers.rs`, `src/engine.rs` | | Tests: version compare, the table's parse and refusals, the offers per tier (missing, old, fine, Apple, Linux, HiveOS), exit codes and Authenticode verdicts, the download against a mocked vendor server (a std TcpListener on 127.0.0.1: the right sha256 passes, a wrong one is refused with the part file gone, the file in place is kept), the manifest's `drivers` validation; the UI's strip per state | `src/drivertable.rs` tests, `src/drivers.rs` `download_tests`, `ui/view.test.mjs` | | The mock's scenarios for the captures: `drivers`, `drivers-running`, `drivers-reboot`, `drivers-error`, `drivers-mac` | `tools/ui-mock/server.mjs` | The captures (the installed Mac window's `--snapshot` on the mock, 1280 x 900, light and dark): `docs/plans/driver-check-shots/01` to `12`: the dashboard's Cards page with the offers (01, 02), the download running (03, 04), installed and Restart now (05, 06), the error (07, 08), macOS (09, 10), the first-run card list (11, 12). ## 2. The table today (`packaging/ota/drivers.json`) | Vendor | min_version | On offer | Source | State | |---|---|---|---|---| | Intel | 32.0.101.9034 (the Arc driver the worker's rotate rewrite is proven on) | 32.0.101.9034, 932,631,144 bytes, sha256 72ba7eea... | downloadmirror.intel.com/929959, Intel's page 785597 (SHA512 printed there; the sha256 read on PC 1 on 7 October) | measured, live | | NVIDIA | 570.00 (CUDA 12.8) | 581.57, approximate size, sha256 of zeros | us.download.nvidia.com, the driver page prints the sha256 | placeholder: the app refuses to install it (the download's sha256 never matches) until the hash is read from the page and written here | | AMD | 32.0.32000.0 (Adrenalin 25.x) | 26.9.2, approximate size, sha256 of zeros | drivers.amd.com, the download page prints the sha256 | placeholder, the same | Apple: none. The exit codes: Intel 14 and 1014 (the bootstrapper's wrap, measured on PC 1), NVIDIA 1 (approximate: NVIDIA's installer returns 1 for "restart required" in silent mode), AMD 3010 (the MSI code, approximate). A wrong code reads as an error on the row and the install is marked failed, never as a success; the table fixes it without an app cut. ## 3. Consequences per tier | Tier | What the user sees | |---|---| | A home miner with a new card and no driver (Windows) | the first-run card list says "Install the driver (). No driver was found, so this card cannot mine yet." with the button; one click, one administrator prompt, the restart line if the installer asks; the other cards mine through it | | An old driver (Windows) | the same row with "Driver X is older than the Y the worker needs"; mining on that card may already fail (the worker's self-test) and the row says why | | macOS | "Apple silicon: no driver step, macOS carries it." in the details; no button | | Linux, HiveOS | "Linux: install the package nvidia-driver-570 (the worker needs 570.00 or newer)." or the HiveOS line; no installer | | A rig | one install at a time (the engine refuses a second while one runs); each card's row carries its own offer | | A pool user | nothing changes | Sizes: the installers are 870 MB to 1 GB each; the download lands in `/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. ## 4. Not done, and what follows - The NVIDIA and AMD rows' hashes: read from the vendors' pages and written into `drivers.json`, then published with `publish-manifest.sh --drivers packaging/ota/drivers.json`. Until then those two rows are refused by the app's own check. - The Linux install path stays a line (the brief). - A PC 1 dry run of the Windows path (the installer not run, the download and the checks live) is one `IGNEUM_DRIVER_DRY_RUN=1` engine start away; not run today (PC 1 is the project lead's desk and mines).