Test the interface as a user sees it, and let a debug build tell on itself

Fifteen rendering tests across four files are the first tests in this project that compose a screen,
and they cover the claims that used to be prose only: the app bar's star exists where there is a folder
to star and says Add or Remove according to the state, the selection bar offers Rename to several files
and Details only to one, the batch dialog spells out the names it will produce and refuses a collision
with the file named, the shared name dialog refuses a slash while it is typed, and a favourite that has
gone says "Folder not found" rather than showing a path that is not there. They run on the JVM through
Robolectric - the Compose test artifacts plus the test manifest - so they belong to the same verify.sh
gate as everything else instead of needing a device: 386 tests in total.

Writing them turned up one behaviour worth recording. The batch dialog continues the folder's series by
default, so a collision cannot be shown unless the start number is forced back to 1 - which is precisely
why the feature works in practice, and now also why two of these tests set the field explicitly.

The debug build now enables StrictMode (disk reads and writes, network, leaked closables; logged, not
fatal) and attaches LeakCanary. A file manager is the worst possible app for a blocking disk read on the
main thread, and a debug build is the last place where noticing it is still cheap. Logging rather than a
crash is deliberate: turning a slow screen into a crash on someone's phone is the worse trade. The flag
is read from the manifest, not from BuildConfig, which this build does not generate.

Performance has a number for the first time, and it immediately paid for itself. tools/measure-startup.sh
takes cold start with `am start -W` - median of several runs, one warm-up discarded because the first
launch after an install pays for dexopt - and docs/PERFORMANCE.md records 1814 ms over five runs, in the
debug build, which is the slow case by construction. StrictMode's first run then produced five violations
against that number: 492 ms resolving `app.cacheDir` inside the view-model factory, 397 ms reading free
space with StatFs for every volume inside refresh(), 477 ms of the platform loading its own typefaces,
and two 54 ms OEM font hooks. That is about 1.5 s of main-thread disk I/O in a 1.8 s start, of which
~0.9 s is ours and mechanical to move. Neither of ours is fixed here on purpose: the numbers and the two
fixes are recorded in PERFORMANCE.md, and they are the first items of the speed work.

What is not measured is stated in the same file rather than left to be assumed: folder open at 1 000 /
5 000 / 20 000 files, thumbnail paint while scrolling, and keystroke-to-result all need a `:benchmark`
module and a profileable build under the release package id, and this device waits for a confirmation
dialog on the first install of a new package id. The module is deliberately absent instead of
half-configured: build wiring nobody can run is worse than a recorded gap.

Gate green (map current, detekt, 386 tests, lint), and CHANGELOG, README, AGENTS.md, ROADMAP,
PERFORMANCE.md, EDGE_CASE_TESTING and the regenerated map carry it.
This commit is contained in:
2026-10-17 09:23:11 +02:00
parent b1bc805af0
commit 0bbee25ab3
15 changed files with 637 additions and 8 deletions
+31
View File
@@ -158,6 +158,37 @@ upload needs a **higher `versionCode`** than every previous upload.
place. **371 JVM tests** still pass, lint is clean, the map is current, and the gate is green in
17 seconds.
- **The user interface is now tested as a user sees it, and a debug build tells on itself.** Fifteen
rendering tests across four files are the first tests in this project that compose a screen:
the app bar's star exists only where there is a folder to star and says *Add* or *Remove* according
to the state, the selection bar offers Rename for several files and Details only for one, the batch
rename dialog spells out the names it will produce and refuses a collision with the file named, the
shared name dialog refuses a slash as it is typed, and a favourite that has gone says *Folder not
found* instead of showing a path that is not there. They run on the JVM through Robolectric — the
Compose test artifacts plus the test manifest — so they belong to the same `tools/verify.sh` gate as
everything else instead of needing a device; **386 JVM tests** in total. Writing them turned up a
behaviour worth recording: the batch dialog's numbering continues the folder's series, so a
collision can only be *shown* by forcing the start number back, which is exactly why the feature
works in practice.
The debug build now enables **StrictMode** (disk reads and writes, network, leaked closables, logged
rather than fatal) and attaches **LeakCanary**. A file manager is the worst possible app for a
blocking disk read on the main thread — every listing, `stat` and thumbnail is one — and a debug
build is the last place where noticing it is still cheap. Logging rather than a crash is deliberate:
turning a slow screen into a crash on someone's device is a worse trade than a line in logcat. The
flag is read from the manifest rather than from `BuildConfig`, which this build does not generate.
**Performance has a number for the first time.** `tools/measure-startup.sh` takes cold start with
`am start -W` — median of several runs, one warm-up discarded because the first launch after an
install pays for dexopt — and [docs/PERFORMANCE.md](docs/PERFORMANCE.md) records the result: **1 814
ms** median over five runs on the phone, in the debug build, which is the slow case by construction
(StrictMode, LeakCanary, no R8). The same file states what is *not* measured — folder open at 1 000 /
5 000 / 20 000 files, thumbnail paint while scrolling, and keystroke-to-result — with the method each
would use and the honest reason they are missing: they need a `:benchmark` module and a profileable
build under the release package id, and this device waits for a confirmation dialog on the first
install of a new package id. The module is deliberately absent rather than half-configured: build
wiring nobody can run is worse than a recorded gap.
### Changed
- **File thumbnails are bigger.** The leading visual in a list row went from 28 dp to 48 dp and