Repository navigation
Fress v1.0.3
Fress v1.0.3 — the never-unreached release
This release closes, at the root, the error some users saw on the download button: "No download was started: the download sources could not be reached. Retry, or open the app for its official options."
What was wrong
Every catalog lookup (GitHub Releases, the F-Droid index, vendor manifests) was a single unauthenticated HTTP request. Three independent roots turned ordinary network weather into that failure:
- One dropped packet failed the whole lookup. A DNS hiccup, a connection reset, or a slow handshake — routine on throttled or censored networks — was never retried.
- The GitHub rate-limit window could be exhausted by browsing. Unauthenticated GitHub allows 60 requests/hour per IP, and every lookup spent 2–3 of them even when nothing had changed. Once drained, every lookup failed until the window reset.
- A failed lookup forgot everything the app already knew. Even a repository resolved successfully minutes earlier failed again from scratch.
What changed (native layer, api_resilience)
- Transient failures are retried — up to four attempts with jittered exponential backoff; a server-sent
Retry-Afteris honored (capped at 15 s). Deterministic answers (404, refusals, broken bodies) fail exactly once, as they should. - GitHub quota is conserved — every answer is cached with its
ETag; repeat lookups revalidate withIf-None-Matchand a 304 costs no rate-limit budget. Steady-state browsing of an unchanged catalog spends almost no quota. - Stale-while-error — if every fresh attempt fails, the last known answer (up to 7 days old, refreshed by every successful revalidation) is served instead of an error: a slightly old release list still names real, downloadable files, and a working download beats an error toast.
- Vendor manifests share the retry contract — a KDE mirror or Tor manifest behind one lost packet no longer fails the whole official-resolver chain.
Security posture
Unchanged. The resilience layer never constructs URLs, chooses hosts, or sees credentials; URL admission, redirect rules and the public-address-only resolver are exactly as audited. The cache stores only public API response bodies, atomically written, and can never become a new way for a lookup to fail.
Quality
- 22 new tests over real loopback HTTP pin every serving path (fresh 200, quota-free 304 with on-the-wire
If-None-Matchproof, 5xx retries to success, exactly-once 404/403/redirect refusals, stale-serve through a rate-limited window, ancient-entry refusal). cargo test272 passed / 0 failed ·clippy -D warningsclean ·fmtclean · 12/12 CI checks green ·validate:versions8 fields agree on 1.0.3.
Full changelog: https://github.com/WasewaseX/Fress/blob/main/CHANGELOG.md