Skip to content

Close the startup follow-ups' known limitations: driver-version reset, embedding worker, x64 payload, Linux raster - #53

Merged
iLevyTate merged 6 commits into
mainfrom
claude/gallant-babbage-mlfl4c
Oct 31, 2026
Merged

iLevyTate merged 6 commits into
mainfrom
claude/gallant-babbage-mlfl4c

Conversation

@iLevyTate

Copy link
Copy Markdown
Owner

Summary

Fixes the known limitations listed on #51, plus a timing-fragile test that failed #52's macOS run.

  • Driver version in the GPU backend record. GPUMonitor now asks nvidia-smi for name,memory.total,driver_version (Windows and Linux) and reads DriverVersion from Win32_VideoController on the WMI path, so gpu-backend-cache.json notices a driver update and the next launch re-runs the backend search. A missing or [N/A] third column leaves driverVersion out, so two-column output still parses. Linux without nvidia-smi (lspci) and macOS still report none.
  • Embedding worker uses the same backend selection. With STRATOSORT_ENABLE_EMBEDDING_WORKER=true the worker thread ran its own full ladder (no supported-backend filter, no remembered backend). workerPools now passes { userDataPath, appVersion } as Piscina workerData; the worker passes getLlamaGpuTypes and a read-only view of the record (createReadOnlyLlamaBackendCache). Only LlamaService in the main process saves or clears the record, so the two stacks never race on the file; a failed read-only attempt logs Cached Llama backend failed; record left to its owner.
  • No arm64 llama prebuilt in the x64 build (~11 MB). @node-llama-cpp/win-arm64 declares cpu: ["arm64", "x64"], so npm installs it on x64 runners. win.files now excludes !**/node_modules/@node-llama-cpp/win-!(${arch}|${arch}-*)/**; app-builder-lib expands ${arch} per packed arch (FileMatcher.normalizePattern), so x64 drops win-arm64 and arm64 (which inherits win.files via extends) drops any win-x64* package. Checked with app-builder-lib's own node_modules filter in electron-builder-config.test.js; verify-packaged-artifacts.js fails if a package for the other arch still holds files.
  • Linux keeps the raster switches. Windows startup follow-ups: zip build, payload trim, relaunch during shutdown, sticky GPU fallback, backend cache #51 stopped appending enable-gpu-rasterization and enable-zero-copy everywhere. That stays on Windows and macOS (GPU raster is already Chromium's default there for non-blocklisted drivers), but Linux goes back to what every earlier release did, since its default varies with Chromium version and driver and the AppImage was never measured without them. Software mode appends neither.
  • Deterministic health-check tests. healthCheckUtils.test.js › resets failures on successful check slept 20 ms on a real timer against a 30 ms interval and expected exactly one failure; on Explain why a zip copy cannot update instead of "Failed to check for updates" #52's macOS runner the sleep resolved after the first tick (count 2). It and calls onUnhealthy when check fails now use Jest fake timers.
  • Docs. CONFIG, ARCHITECTURE, DEBUGGING_GUIDE, RELEASING and CHANGELOG [Unreleased] describe the new behaviour instead of the limitations.

Scope

  • Area(s): GPU detection, LlamaService backend selection / embedding worker, Windows packaging, Chromium GPU switches, tests, docs
  • Risk Level: low to medium (packaging pattern and Linux GPU flags are only exercised by packaged builds)
  • Breaking Changes: none

Type of Change

  • Bug fix
  • Enhancement
  • New feature
  • Refactor
  • Documentation update
  • Breaking change

Test Plan

Automated

  • npm run format:check
  • npm run lint
  • npm test (as part of npm run ci on this branch: 774 suites, 11,218 passed, 26 skipped, coverage thresholds met; audit:production 0 vulnerabilities; build OK)
  • Additional tests added/updated when behavior changed: driver version parsing and query (GPUMonitor.test.js), read-only record and worker data (llamaBackendCache, llamaBackendSelector, workerPools.threadConfig), per-arch packaging (electron-builder-config, verifyPackagedArtifacts), per-platform raster switches (gpuConfig), fake-timer health checks (healthCheckUtils, 15 consecutive passes).

The affected suites also pass with the starting platform faked to darwin and win32 (14 suites / 420 tests, plus healthCheckUtils/gpuConfig/GPUMonitor after the rebase), so the macOS and Windows runners should not hit platform-only failures.

Manual QA

  • Manual checklist completed (see docs/TESTING.md)
  • Not applicable (explain below)

Manual QA notes:

  • The ${arch} exclusion and the Linux raster switches are only exercised by packaged builds; verify-packaged-artifacts.js now checks the former on every Windows release build. The SW-40 packaged smoke in docs/RELEASING.md still applies before the next release.

Checklist

  • I scoped this PR to one logical change
  • I self-reviewed code and naming for clarity
  • I updated docs/config references where needed
  • I called out follow-up work or known limitations

Not done here: macOS and Linux builds still carry better-sqlite3 prebuilds for other platforms (~13 MB each). The same ${arch}-style pattern could trim them, but it needs a packaged mac/Linux build to verify.


Generated by Claude Code

…after a driver update

GPUMonitor did not read a driver version, so the GPU backend record's
driverVersion field was always null and a driver update alone never made
the next launch re-run the backend search.

- nvidia-smi (Windows and Linux) now queries
  name,memory.total,driver_version; a missing or "[N/A]" third column
  leaves driverVersion out, so two-column output still parses.
- The Windows WMI path selects DriverVersion from Win32_VideoController.
- lspci (Linux without nvidia-smi) and macOS still report none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5Uo5hC58DRSh1qB489Sos
…e remembered backend

With STRATOSORT_ENABLE_EMBEDDING_WORKER=true the worker thread ran the
full GPU backend ladder on its own node-llama-cpp stack: no
supported-backend filter and no remembered backend, so it re-tested GPU
binaries the main process had already ruled out.

- workerPools passes { userDataPath, appVersion } as Piscina workerData
  (the worker cannot reach electron's app).
- The worker passes getLlamaGpuTypes and a read-only view of the record
  (createReadOnlyLlamaBackendCache) to initLlamaWithBackend. Only the
  main process's LlamaService saves or clears the record, so the two
  stacks never race on the file.
- When a read-only record's backend fails, the selector logs
  "Cached Llama backend failed; record left to its owner" instead of
  claiming it cleared the record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5Uo5hC58DRSh1qB489Sos
…ch Windows build

@node-llama-cpp/win-arm64 declares cpu ["arm64", "x64"], so npm installs
it on x64 runners and the x64 build shipped it (about 11 MB). It could
not be excluded from the shared `files` list because the arm64 config
inherits that list through `extends`.

win.files now excludes `@node-llama-cpp/win-!(${arch}|${arch}-*)/**`.
app-builder-lib expands ${arch} per packed arch (FileMatcher
normalizePattern), so the x64 build drops win-arm64 and the arm64 build
drops any win-x64* package, while each keeps its own (checked with
app-builder-lib's own node_modules filter in
electron-builder-config.test.js). verify-packaged-artifacts fails if a
package for the other arch still holds files.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5Uo5hC58DRSh1qB489Sos
The startup follow-ups stopped appending enable-gpu-rasterization and
enable-zero-copy on every platform. On Windows and macOS GPU raster is
already Chromium's default for drivers it does not blocklist, so
forcing it only overrode that blocklist. On Linux the default varies
with Chromium version and driver, and the AppImage was never measured
without the switches, so Linux goes back to what every earlier release
did. Software mode appends neither.

The raster-switch tests now set process.platform explicitly instead of
depending on the platform running the suite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5Uo5hC58DRSh1qB489Sos
"resets failures on successful check" started a 30 ms health-check
interval, slept 20 ms on a real timer and expected exactly one failure.
On a loaded macOS runner the sleep resolved after the first 30 ms tick
and the count was 2 (seen on PR #52's ci (macos-latest)).
"calls onUnhealthy when check fails" had the same shape with a 70 ms
margin. Both now use jest fake timers and advanceTimersByTimeAsync, so
the count no longer depends on runner load. The other tests in the file
only get more lenient when timers fire late and keep real timers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5Uo5hC58DRSh1qB489Sos
… raster switches

CONFIG, ARCHITECTURE and DEBUGGING_GUIDE describe the backend record's
driver version, the embedding worker's read-only use of it, and the
Linux-only raster switches; CHANGELOG [Unreleased] lists the
user-visible changes (driver-version reset, embedding worker, smaller
Windows x64 build, raster switches left to Chromium on Windows/macOS).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5Uo5hC58DRSh1qB489Sos
@iLevyTate
iLevyTate merged commit 1268f74 into main Oct 31, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants