# Validation report — Fileworkbench source release 0.2.2 Date: 2026-09-24. **Folder-listing source hotfix; not a verified new Android APK.** The user reported a successful local build of the preceding source, then a runtime failure when adding a folder: "The storage provider did not return a folder listing." The local device, provider and Android version have not been inspected here. ## Reproduced cause `SafBrowserStore.list` used `query(...)?.use { ... } ?: throw ...`. The final expression inside `use` was a nullable read of `DocumentsContract.EXTRA_ERROR`. When the provider returned a valid cursor without that optional message, the block returned null and the trailing Elvis operator raised the no-listing exception, even after successfully reading all rows. Empty directories had the same issue. The fix checks the query result for null **before** entering `use`. A genuinely missing cursor still raises the original exception. Cursor closure, row limits, loading/info/error messages, URI checks and permission handling are unchanged. Only `SafBrowserStore.kt` needs to change to apply the runtime correction. ## Executed checks | Check | Result | Boundary | |---|---|---| | Extracted original production listing block | **9 failures / 14 checks** | Reproduces the exact reported exception on valid cursors without EXTRA_ERROR | | Extracted fixed production listing block | **14/14 passed** | JVM control-flow/resource checks using real common models and Android test doubles | | Shared-core/JVM adapter suite | **112/112 passed** | Local Kotlin/JVM compiler, not the Android/Gradle toolchain | | Kotlin PSI syntax | **44 files, zero parse errors** | Syntax only; no Android/Compose type resolution | | XML and existing source invariants | Passed | No new storage permissions or dependencies | | One-file patch | Applies to both shipped 0.2.0 and 0.2.1 source | Exact checked archive baselines, not an unseen locally modified checkout | | New Android instrumentation tests | **5 added; not run here** | Empty, info-only, loading with/without cached rows, and provider-error listings | | Android APK/test-APK build attempt | **Blocked before compilation** | Gradle-wrapper bootstrap cannot resolve raw.githubusercontent.com; exit 6 | | Phone/emulator/iOS checks | Not performed here | No APK or device-test result supplied | The host harness copies the cursor-reading block directly out of the selected production source and compiles it with the real common models. The resolver, cursor, extras, cancellation signal and URI builder are lightweight test doubles. It does **not** test Android API compatibility, Binder, real permissions, provider behaviour, asynchronous scheduling, or the screen. It is not a substitute for the instrumentation tests or the local Android build. Raw logs are in `validation/0.2.2/`. The preceding report is preserved as `VALIDATION-0.2.1.md`; older logs retain their original provenance. ## Reproduce the host checks With a local Kotlin compiler, Java and Python 3: ```sh python3 scripts/test-folder-listing.py bash scripts/test-core.sh bash scripts/check-kotlin-syntax.sh python3 scripts/check-project.py ``` To demonstrate the regression against the preceding file, pass its actual local path to `python3 scripts/test-folder-listing.py --source /path/to/old/SafBrowserStore.kt`. That command should fail on the old implementation; the failure is expected. ## Local Android acceptance Keep the local Gradle/JDK configuration that already builds. Apply the one-file fix, then rebuild and install over the existing debug app using the same signing key: ```powershell .\gradlew.bat :androidApp:assembleDebug :androidApp:assembleDebugAndroidTest adb install -r .\androidApp\build\outputs\apk\debug\androidApp-debug.apk ``` Open the saved folder and refresh, or select it again if its grant was temporary. Check a normal folder, an empty folder, a nested folder and a document preview. With the complete updated source and a device/emulator, run `:androidApp:connectedDebugAndroidTest` to exercise the Android regression cases. The separate broader browser checklist remains in `BROWSER_ACCEPTANCE.md`.