Changelog
Release history, newest first. The authoritative source is CHANGELOG.md in the repository; this page summarises what each release actually changed and why.
3.4.1 — 27 August 2026 #
Stale-asset cache rotation, community fixes, CI correctness.
The headline fix addresses the root cause of recurring black screens. Bundles are patched at request time, but the service-worker cache name derived only from VERSION — so editing a patch changed the response without changing the cache key, and /assets/ is served cache-first. A stale copy could persist indefinitely.
- Cache names now include a build token: a digest of
VERSIONplus theserver.mjsmodification time. Any patch edit rotates both caches on the next load. - Four serve-time-patched assets were shipping
Cache-Control: immutable, pinning unpatched bodies for a year. Added toRUNTIME_PATCHED_ASSET_PATHSin bothserver.mjsandpublic/sw.js. /api/version.pwa_cachereported a cache name that never existed — it omitted the token.- Mobile keyboard closed on every keystroke in community modals. The shared modal ran its focus-trap effect with dep
[onClose], and every call site passed an inline arrow — so the effect re-ran per keystroke and its cleanup moved focus off the input. Android dismisses the keyboard on blur. - Two serve-time patches were silently dead: their anchors were written against pretty-printed source while the shipped bundles are minified.
regenerate-release.ymlrequiredpublic/index.html, which does not exist — the shell is at the repository root. That workflow failed on every release.ci.ymlnever syntax-checkedpublic/sw.jsdespite it being hand-edited with substituted placeholders.- The in-app Update button was a permanent
403on any install withENABLE_ADMIN_MODE=false— the default. Now accepts loopback as well as an admin cookie, with a409gate when the git tree is dirty.
3.4.0 — 13 August 2026 #
Performance: lazy asset loading, offline cache fix, gzip HTML.
- Service worker never activated on first visit.
cache.addAll()is all-or-nothing — a single 404 in a 50-URL precache list failed the whole install, so the worker never activated and offline never worked. Replaced withPromise.allSettled(). - Route chunks moved to lazy loading, cutting initial payload.
- HTML responses gzipped, with hashed assets pre-gzipped once and cached in memory.
3.3.9 — 9 August 2026 #
Cross-platform CLI, one-line installers, main-branch updates, automated screenshots.
isotopeCLI with.batand.ps1equivalents, so Windows is a first-class target.- One-line installers per platform, including a dedicated Termux path with home-screen widgets.
isotope updatepulls the tracked branch and restarts.
3.3.7 — 8 June 2026 #
Auth-gated sync state machine.
Sync retried indefinitely when a JWT could not be refreshed. Retrying an upload with a dead token cannot succeed, so it now enters an auth-blocked state and waits for a valid session rather than burning requests on a timer.
3.3.6 — 8 June 2026 #
Cloud sync download on a new device; storage cleanup.
A fresh install could fail to pull an existing account’s data. This is also where the richness-before-recency comparison was hardened, so an empty snapshot can never overwrite real study data.
3.3.5 — 7 June 2026 #
Speed probe, health cache, pre-gzipped bundles, 14 database indexes.
3.3.4 — 7 June 2026 #
Security headers, API 404 fencing, service-worker cache corrections.
/api/* and /__ai* now return JSON 404s instead of falling through to the SPA, so a typo surfaces as an error rather than an HTML page.
3.3.3 — 7 June 2026 #
Admin role check fixed; 8 undocumented database functions added to the schema.
isSupabaseAdminUser() filtered user_roles on an is_active column that did not exist, so admin auth failed silently for everyone.
3.3.2 — 7 June 2026 #
user_tours table added; /__admin/schema fixed; first schema gap audit.
The schema route served isotope-schema.sql, a file that no longer existed, returning HTTP 500.
3.2.0 — 7 June 2026 #
Leaderboard RLS fix and SQL index correction.
A stats_own policy using FOR ALL also blocked public SELECT, so the leaderboard rendered empty. Fixed by leaderboard-rls-fix.sql, which upgrading installs still need.
3.1.2-patch — PWA stability #
Seven service-worker and offline-mode fixes.
The one worth recording: the cache name embedded the full commit SHA rather than a truncated one, so a new build produced a name that did not match the old format. Cache reuse failed silently and duplicate caches accumulated — the app worked, storage grew, and nothing reported a problem. Also in this release: update-checker error handling and offline-mode memory management.
Earlier releases #
3.1.1 and before covered the initial self-hosted architecture: the serve-time bundle patcher, the Supabase proxy, row-level security across every table, and the backup and restore tooling. See CHANGELOG.md for the full record.
Versioning #
| Component | Meaning |
|---|---|
| Major | Reserved for a change that breaks an existing install’s data or schema. |
| Minor | New features, new tables, new routes. |
| Patch | Fixes and performance work. |
The authoritative version is VERSION at the repository root, reported live by /api/version. Note package.json can lag it between releases.
# what is actually running curl -s http://127.0.0.1:3000/api/version | python3 -m json.tool