The cache leg of a cache-first query had a hard 100 ms deadline that cancelled the read and reported it as a miss. That conflates "the cache has nothing" with "the cache was slow", and the two want opposite answers: offline the server leg fails too, so browsing surfaced a network error over cached content that was sitting on disk. It is not a rare race. The database is a single SQLite connection behind a single mutex, so a concurrent write — a sync drain, a bulk save_to_cache, a thumbnail write — blocks every read for its duration, and 100 ms is easily exceeded on phone storage. It also compounded: `spawn_blocking` work is not cancellable, so an abandoned query still ran and still held the mutex, making the next one slower. The deadline now bounds only the *fast path*. A cache query that misses it keeps running on its own task, and when the server leg fails the race waits that query out instead of discarding it. A cache that answers in time still short-circuits the server exactly as before, and when both sides genuinely fail the server's error is still what the caller sees. `parallel_race`/`race_with_refresh` no longer need `&self`, so they are associated functions and directly testable without constructing a repository. Not addressed here: one connection behind one mutex makes `PRAGMA journal_mode = WAL` inert, since reads and writes fully serialise regardless. A read pool is an architecture change and wants a spec.

JellyTau
A cross-platform Jellyfin client built with Tauri, SvelteKit, and TypeScript.
Business logic lives in a Rust backend; a UI-rich Svelte frontend handles presentation and talks to it over Tauri's IPC. Targets Linux (libmpv) and Android (ExoPlayer).
Getting Started
This project uses bun as its package manager.
# Activate the Rust environment (fish shell)
source "$HOME/.cargo/env.fish"
# Install dependencies
bun install
# Run in development
bun run tauri dev
# Type-check the frontend
bun run check
# Build for Linux
bun run tauri build
# Build for Android
bun run tauri android build
For the full set of build, test, and Android helper scripts, see scripts/README.md.
Documentation
| Topic | Location |
|---|---|
| Architecture overview & subsystem docs | docs/architecture/ |
| Requirements, traceability & technical debt | docs/requirements.md |
| Build & release process | docs/build/build-release.md |
| Docker builds | docs/build/docker.md |
| Traceability tooling & CI | docs/traceability.md, docs/traceability-ci.md |
| Release checklist | docs/release-checklist.md |
| UX flows | docs/ux-flows.md |
| CI operations (builder image, secrets, runner) | docs/build/ci-operations.md |
Contributing
CONTRIBUTING.md covers the setup, the gates a change has to pass, and the two rules that catch people out (bug fixes start with a failing test; Jellyfin's taxonomy stays in Rust). Please also read the Code of Conduct.
Found a security problem? Do not open an issue — see SECURITY.md.
Verifying a download
Every release publishes SHA256SUMS covering all of its artifacts, plus an SBOM
of what went into the build:
sha256sum -c SHA256SUMS
Desktop builds update themselves from Settings → Updates, verifying each payload against JellyTau's signing key before installing. Android installs are handled by the system installer, so the app links to the releases page instead.
Recommended IDE Setup
VS Code + Svelte + Tauri + rust-analyzer.
License
MIT