Files
searchi/docs/LINUX-DESKTOP-VALIDATION.md
T

13 KiB
Raw Blame History

Native Linux desktop validation

Executed 2026-10-13 on Ubuntu 24.04 x86-64 in WSL inside the CPU-only Windows VM. This is native Linux compilation and an isolated virtual-display interaction check, not a Linux installer, physical desktop, GPU, or clean-machine certificate.

Native Linux searchi showing a real Google CPU supplier-agreement result

Actual embedded desktop at 657de3d, with a three-file fixture and real Google embeddings. The unrelated lower results illustrate the relevance gate that remains open. The displayed times are single observations, not percentiles.

Source and build

  • Baseline 6b78c8b: embedded-frontend Release build passed in 25m 49s.
  • Validated snapshot 99748bd: embedded-frontend Release build passed in 4m 17s after refreshing copied source mtimes. An earlier attempt reused stale Cargo path-dependency artifacts because Git archive preserved old mtimes; it failed with missing new service exports. The corrected build recompiled all shared searchi crates. No Rust implementation change was needed for this failure.
  • Frontend index-DUwy7lJE.js, SHA-256 614562a0804df91452d9d6be0210b543dd035ff7defe99e779cc448488026132.
  • Executable SHA-256 c08b208d1cc3225d9c6a9a7581920eb5cf4fd9105a5620bd2dc57eaac33d671a.
  • Rust/Cargo 1.99.0; two logical CPUs, 2.8 GiB memory and 1 GiB swap; Cargo jobs limited to one. WebKitGTK 4.1 development package 2.52.6-0ubuntu0.24.04.1, GTK 3 3.24.41-4ubuntu1.3.
  • Normal verified Linux CPU/Vulkan worker and pinned Linux FFmpeg resources were staged in an isolated ext4 source tree. Windows resources were not modified. ldd found no missing executable libraries on this provisioned Ubuntu host.

The build uses cargo build --manifest-path apps/desktop/src-tauri/Cargo.toml --release --features custom-protocol --locked -j1. Build logs are retained under /home/karl/.cache/searchi-validation/desktop-{baseline,final-99748bd}-build.log.

Strict CPU rendering and inference

The initial Xvfb attempt failed because WSLg's /tmp/.X11-unix socket directory was not writable. The working session verified a distinct mount namespace, made mounts private, and bound a QA-owned socket directory inside that namespace. It masked /dev/dxg with /dev/null and masked /dev/dri if present. It changed no persistent WSLg mounts or user configuration. The app ran as karl, with an owned session/process group and separate settings/index directories.

Xvfb disabled GLX; the app used GDK_BACKEND=x11, LIBGL_ALWAYS_SOFTWARE=1, GALLIUM_DRIVER=llvmpipe, MESA_LOADER_DRIVER_OVERRIDE=llvmpipe, WEBKIT_DISABLE_DMABUF_RENDERER=1, WEBKIT_DISABLE_COMPOSITING_MODE=1, and SEARCHI_FORCE_CPU=1. Model setup reused verified cached Google assets. Explicit worker/media helper overrides were used, so this session does not prove installed resource discovery. Process inspection of Xvfb, the app, WebKit processes, and the Google worker found no GPU device descriptors or Vulkan/D3D provider mappings; their /dev/dxg was the null device (major 1, minor 3).

Actual UI interactions

On the 99748bd snapshot, the native embedded app:

  • Rendered the branded light theme and reported Google CPU readiness.
  • Opened its folder form and an actual GTK Browse dialog. Synthetic per-key path entry in GTK produced completion/tree-model warnings; cancel worked. Pasting the absolute fixture path in the app's folder form successfully indexed three real document/code files, then automatically built three Google segments.
  • Searched cancel the supplier partnership and placed the supplier agreement first, with its real termination passage and literal match highlights.
  • Preserved a collapsed Why this result? detail; expanding it showed a concise explanation and reopening/collapsing did not change the selected passage.
  • Accepted Ctrl+K and arrow navigation, changing the selected result and preview to retry.rs, then back to the agreement.
  • Applied an rs extension restriction and returned only the source file.
  • Enabled Performance details, showed granular local traces, and copied a 12,917-byte timing report. Inspection found no source paths or remembered query text in the copied JSON.

Captures came directly from pinned FFmpeg X11 capture, including fresh 1080-by-760 app-area captures with -draw_mouse 0; no screenshot pixels were edited. Raw captures and timing/GPU audits are local ignored QA evidence in .searchi/qa/linux-native-*.png and the native desktop-qa-99748bd directory. The remembered search displayed a basic backend sample of 236 ms and displayed response sample of 474 ms. A separate debug retry query showed 4,371 ms backend and 4,564 ms final displayed response. These single samples are not startup, first-input, paint, large-corpus, or warm p95 benchmarks.

Independent scheduling regression

The actual Google budget_google_cpu test passed on Linux in 129.60s, using the normal verified worker with CPU forced: total budget 2, foreground query thread 1, indexing thread 1, query sample 142.015 ms, admission sample 0.444 ms, six background document encoder calls. This proves the tested concurrent admission contract; it does not establish scale or native UI latency targets. Log: /home/karl/.cache/searchi-validation/budget-google-linux-99748bd.log.

Remaining scope

The 99748bd interaction evidence excludes the later watcher milestone. Installer/resource discovery, window-manager chrome, theme/contrast/accessibility coverage, media previews, physical GPU fallback/recovery, clean-machine ABI, upgrades/signing, macOS, and large-corpus performance remain separate gates.

Watcher milestone: 657de3d

The isolated source was refreshed from the committed snapshot and paired with the matching index-64het56E.js frontend. Source mtimes were refreshed before Cargo invocation. Executed checks:

  • Workspace: 124 passed, 19 ignored, zero failures; native compilation took 2m 25s. Ignored actual-model tests are not counted as executed here.
  • Desktop Release unit tests: 28 passed, including actual Linux inotify create/update/rename/delete, bounded-event retry/overflow and shutdown tests; compilation took 1m 49s and test execution 1.74s.
  • Actual Google mixed-media reuse regression: one passed in 67.95s, including same-stat media invalidation, revision tokens and reused vector publication. Normal verified worker, real models and pinned FFmpeg helpers; CPU forced.
  • Fresh embedded-frontend Release executable built in 1m 49s; SHA-256 746571a151cea5151b0ed9feef87db98f41cb62512a6bc9eb7b7b6404dd015a5.

Logs are retained as workspace-linux-657de3d.log, desktop-tests-linux-657de3d.log, media-google-linux-657de3d.log, and desktop-final-657de3d-build.log under the native validation cache.

The current native UI used a fresh settings/index directory and the same verified private CPU display setup. Captures targeted the actual X11 window ID, whose inspected geometry was x=0, y=0, width=1080, height=760. Its worker loaded libggml-cpu-zen4.so, one inference thread, zero process swap; no GPU mappings or descriptors were observed. After initial indexing, WSL reported 539 MiB used, 2.3 GiB available and zero swap. No validation compiler or independent model test was running during the following UI samples.

The first remembered query had inherited the previously enabled Performance details preference from WebKit local storage; SEARCHI_DATA_DIR isolates Rust settings/index, not that WebKit preference. Its debug sample was 70.852765 ms native, 68.644667 ms query embedding, 67.261 ms worker inference, 13 tokens and a query-vector cache miss. First displayed response was 70 ms; final displayed response was 273 ms. After disabling Performance details, the distinct query end the supplier agreement showed 89 ms native / 300 ms displayed. These different-query samples do not establish normal/debug overhead or p95. The earlier 4.371s sample remains valid evidence, with no inferred cause.

Actual UI filesystem lifecycle checks required no manual Reindex action:

  1. Changed sixty to seven while preserving exact file size and mtime. The live passage updated automatically; active generation moved 1 to 2, retaining three chunks. Recorded SHA-256 values differed despite matching metadata.
  2. Created orbit.txt. The app counted four files and immediately showed its actual orbital keyword passage while Google indexing was working: a single sample of 1.2 ms backend / 88 ms displayed. Generation 3 contained four chunks.
  3. Renamed it to satellite.txt. The UI preview and indexed path changed, the old path disappeared, and generation 4 retained four chunks.
  4. Deleted it. The path disappeared from both UI and index; generation 5 returned to three chunks.

Raw mutation snapshots are in native desktop-qa-657de3d/watch-mutations.jsonl; UI captures are local .searchi/qa/linux-current-*.png. The copied debug report is .searchi/qa/linux-current-timing-remembered-debug.json. Both UI sessions ended through their owned cleanup path: the app process group terminated, Xvfb exited successfully, and subsequent process inspection found no remaining app/WebKit/worker/Xvfb/DBus/clipboard helpers. The outer /dev/dxg remained the real device after private namespace teardown.

The interactions also exposed two unresolved product observations. Background filesystem refreshes displayed SHOWN 83537 MS / SHOWN 108592 MS despite roughly 1–2 ms backend samples, including idle time since the original input; these are not fresh search latency measurements. During replacement, selection advanced to another valid result and stayed there when the replaced passage returned. After deleting the only orbital file, three unrelated semantic neighbors remained: deleted-source suppression worked, but no-relevant-match calibration remains a separate search-quality gate.

Watcher UI corrections: 8b993b2

A fresh native embedded Release build paired this committed snapshot with index-Bi37oidC.js. Cargo completed successfully in 2m 40s with one build job. Executable SHA-256: 981dc04fb1e57e4c48bd1a12d64ec300ca73e7696d76aad25cd8153b780c8132. Frontend SHA-256: ee3b297dff382f2f14a87a88e345f1deb8dae0f77f6d70e0444d916b3cf197de. Build log: native desktop-postfix-8b993b2-build.log. An earlier command failed before Cargo because the inherited Windows PATH contained spaces; the corrected command used an explicit Linux-only PATH.

The executed post-fix session used separate XDG cache/config/data directories in addition to isolated Rust settings/index. Performance details started unchecked, confirming that prior WebKit preferences were not reused. It reused the verified private namespace, CPU software Xvfb and explicit native worker helper paths; no physical GPU or installer resource discovery was tested.

Actual native UI checks, without a manual Reindex action:

  1. The remembered query cancel the supplier partnership found the supplier passage. One basic sample showed 93 ms native / 296 ms displayed.
  2. After enabling Performance details, waiting more than 30 seconds, and changing sixty to seven with identical size and mtime, the preview updated and returned to the supplier selection. The copied report identified trigger: filesystem_refresh; its preserved original_input measured first response 20 ms and final response 140 ms. The independent refresh measured first response 31 ms and final response 4,164 ms, with 1.9 ms native search. The final displayed time includes actual background indexing/readiness and retry scheduling; it is not the idle interval or native inference cost. This corrects the earlier idle-clock defect without proving a warm p95 target.
  3. Moved the selected supplier file out of the indexed fixture. The UI showed two files and temporarily selected retry.rs. Restoring the same supplier path brought the selection and preview back automatically.
  4. Repeated the removal, explicitly clicked Garden notes.txt while the supplier was absent, then restored the supplier. The UI retained the explicit garden selection despite the supplier becoming the first result again.

The copied timing JSON contains neither remembered query text nor source paths. Local ignored evidence: .searchi/qa/linux-postfix-timing-refresh.json, linux-postfix-{update-ready,absent,restored,override-selected,override-restored2}.png, linux-postfix-cpu-audit.json, and linux-postfix-mutations.jsonl. Native desktop-qa-postfix retains the owned session logs and complete fixture. One capture caught a transient black rectangle over a hovered row; a fresh capture after moving the pointer away was clean. This isolated software-display check does not close native visual/accessibility or physical-desktop gates.

The CPU audit found no GPU descriptors or provider mappings in the app, WebKit, Xvfb or Google worker. The worker used libggml-cpu-zen4.so, one thread and zero process swap; their private /dev/dxg was the null device (1:3). Owned shutdown ended the app group with SIGTERM and Xvfb with status zero. Subsequent process inspection found no remaining app/worker/WebKit/Xvfb/DBus/clipboard helpers, and the outer /dev/dxg remained the real device (hex a:102).