The catalog, the sidecar cache and the export outbox were all landing in the
app's cache directory on Android, where the system deletes them without asking
under storage pressure.
`catalog_path` derived its base from `XDG_DATA_HOME` or `HOME`, and neither is
set on Android, so it fell through to `temp_dir()` — which resolves there to
`/data/user/0/<pkg>/cache`. Confirmed on the tablet: the app logs its catalog
under `cache/darkroom/...`.
What sits beside that catalog is not disposable. `sidecars/` is the commit
point for every rating and edit made with no connection — the whole mechanism
that makes offline culling safe — and `outbox/` holds exports the user has
already been told succeeded. A day of sorting on a train, evicted by an OS
housekeeping pass before it ever reached the server, is the worst failure this
application can have, and it would leave no error and no trace.
The fallback is now `SessionStore::data_dir()`, the persistent per-app
directory the Android entry point establishes before any store opens — the
same one credentials and sessions already use. Desktop is untouched: the XDG
data location is still preferred, so nobody's catalog moves.
Two tests. One asserts no durable path contains `/cache/` or `/tmp/`; the
other pins the outbox to the catalog's parent, because three call sites derive
their location that way and a change here moves all of them at once.
Found while verifying that offline browsing works on the tablet with wifi
disabled — which it does: the app cold-starts with no network, reports the
scan failure without crashing, and serves its grid from the local store.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>