@@ -714,6 +714,12 @@ nix develop .#android -c bash tools/android/build.sh
714714
715715That runs the three cached stages -- ` build-dependencies.sh ` , ` build-qt6.sh ` ,
716716` build-apks.sh ` -- which can also be invoked on their own.
717+ Android's libmpv cache includes the actual source revision, tracked/untracked
718+ source changes, NDK/API/ABI, build recipe and feature manifests as well as its
719+ static dependency stamps. ` MPV_SRC ` can select another verified source checkout;
720+ the default remains the repository's ` mpv ` submodule. A matching revision alone
721+ never admits stale dirty source bytes.
722+
717723
718724Entering the Android shell may build native Qt host tools before the Android
719725cross-build starts. These must match the pinned Qt version: ` moc ` , QML generators,
@@ -839,6 +845,11 @@ Android's host import scanner uses the same pinned recursive-exclusion patch as
839845tvOS/webOS. This keeps vendored Qt's intentionally malformed test QML outside the
840846application/test targets' source-root scan while their exact resource QML and
841847real plugin dependencies remain scanned and packaged.
848+ Windows QML selectors direct QtTest's ordinary text logger to their retained
849+ stdout/stderr pipe instead of the debugger-only OutputDebugString sink. Explicit
850+ CLI logging choices remain available. Retry checks compare the original native
851+ failure bytes before/after retry, independent of the host's text newline encoding.
852+
842853
843854The additional ` linux-sanitizers ` CI job uses ` SPOOL_SANITIZERS=ON ` to instrument
844855the actual production core, official upstream libzstd static decoder, and unified
@@ -856,6 +867,14 @@ The traditional binary is `spool-tests`; the GUI binary is `spool-e2e-tests`.
856867Each contains a selector registry and supervises fresh executions of ** itself** .
857868The binary CLI exposes ` --list ` , ` --child SELECTOR ` , and
858869` --run-all --workers N --results FILE ` , with ` --resume ` /` --retry-failed ` .
870+ Device adapters also pass ` --log ABSOLUTE_PRIVATE_PATH ` so Activity/UIKit native
871+ stdout/stderr conditions survive even when the OS does not expose a console.
872+ Those raw native diagnostics stay owner-private; safe exports remain allowlisted.
873+ Each device attempt has a fresh private directory nonce, so a new invocation
874+ cannot overwrite earlier fault evidence or collide with its private capability
875+ files. Kernel-wide CPU and memory availability are checked independently; denied
876+ CPU proc access does not discard readable Android memory counters.
877+
859878Separate selectors isolate QApplication ownership, mutable environments,
860879explicit exits and crashes without creating an executable for every test.
861880All traditional selectors finish before GUI e2e starts, and either phase's
@@ -882,7 +901,14 @@ See `tools/patches/mesa-wayland-fifo-presentation-clock.patch` for the exact
882901upstream source, introducing commit and protocol references.
883902
884903macOS uses its real graphics device and bundled/Nix MoltenVK, not a software
885- scenegraph. Windows deliberately tests the supported OpenGL embedding path with
904+ scenegraph. Hosted Apple paravirtualized GPUs use MoltenVK's documented
905+ ` MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0 ` discrete-binding configuration, avoiding
906+ an unsupported Metal argument-encoder probe while retaining every real Vulkan
907+ selector. This is the [ upstream-recommended VM configuration] ( https://github.com/KhronosGroup/MoltenVK/issues/2373 ) ,
908+ not a Metal implementation fork or a change to users' default graphics backend.
909+ QtTest QML/plugin paths come from the configured matching-version Qt package
910+ prefixes, including split Nix modules and macOS frameworks.
911+ Windows deliberately tests the supported OpenGL embedding path with
886912SHA-256-pinned Mesa WGL llvmpipe: Qt and real libmpv share OpenGL, not D3D WARP or
887913Qt's software scenegraph. This Windows configuration is not proof of Vulkan or
888914D3D playback. The real host app journey additionally needs Tesseract English OCR
@@ -900,6 +926,9 @@ native launcher and stages the product's shipped fonts. Failed journeys retain
900926owner-private screenshots, logs and isolated data under ` test-artifacts `
901927(` SPOOL_E2E_ARTIFACT_DIR ` can select its parent); raw logs and credentials are
902928never printed. Successful journeys remove their temporary data.
929+ Screenshot requests use the public Qt Quick repaint API, await a real swapped
930+ frame, then perform GUI-thread framebuffer readback. This remains an actual
931+ graphics capture, not a software scenegraph substitute or screenshot-only test.
903932The loopback Jellyfin fixture supplies a quiet real event WebSocket. During the
904933offline-download scenario it rejects every new authenticated HTTP request or
905934WebSocket handshake, including playback negotiation and media requests; the
@@ -913,6 +942,38 @@ Android and tvOS simulator adapters launch each selector in the same installed
913942phase APK/bundle and require a fresh native nonce receipt. Then the same host GUI
914943binary drives the actual mobile application; ` native-spool-e2e-path.txt ` in the
915944host build directory supplies its generated target path without bundle guesses.
945+ ` native-spoolet-path.txt ` supplies the matching public CLI consumer for cleanup
946+ regressions. Both native phase bundles include the same filesystem fixture
947+ loader and real shipped OSD fonts; host-only fork/process-supervisor code is not
948+ compiled into UIKit/Activity bundles.
949+ Android receipt/file operations use shell-v2 without a PTY, preserving actual
950+ remote exit codes and binary bytes. Mobile screenshot checks match the real
951+ window's logical size times device-pixel ratio and the returned framebuffer
952+ dimensions, rather than imposing a desktop-width threshold on small phones.
953+ Mobile consumer tests retain real persistence, audio-policy, decoded-media,
954+ download-byte and font-loader checks; extracted fixture paths are canonicalized
955+ and downloads use the platform's actual allowed destination choice.
956+
957+
958+ The host adapter owns each production mobile launch and its exact Android
959+ forward/reverse mappings. A private nonce-bound capability file lets the
960+ controller request those operations; adapter cleanup still runs if the controller
961+ crashes or times out, without relying on C++ destructors or removing unrelated
962+ device resources. Request framing has an absolute deadline, including before
963+ authentication. CI enables ` SPOOL_TEST_DEVICE_CLEANUP_REGRESSIONS=1 ` to inject
964+ real controller timeout/crash after public ` spoolet ` readiness, test an
965+ unauthenticated slow client, verify process/mapping retirement, and exercise
966+ another actual consumer. The inner controller fault remains crashed/timed-out;
967+ only the independent cleanup assertion can pass.
968+
969+ Mobile attempts receive their own ` SPOOL_E2E_ARTIFACT_DIR ` . CI uploads only the
970+ adapter's ` safe-export ` subtree: schema-generated native/controller results,
971+ sanitized journals and attempt diagnostics, and named screenshots. Capability
972+ files, control descriptors, credentials, raw product logs and isolated data roots
973+ remain private. Standalone fault checks use `tools/run-device-tests.py --phase
974+ e2e --cleanup-regression timeout|crash` with the actual isolated device and host
975+ controller/CLI paths supplied by the platform driver.
976+
916977Device phases run serially because one installed activity/application cannot
917978host parallel native processes safely. Native traditional coverage includes
918979the package consumer's compressed, corrupt, truncated and checksummed inputs
0 commit comments