Index: CHANGELOG.de.md
===================================================================
--- CHANGELOG.de.md	(revision 0a93c15436f7a8f5a12389660d2feb0a690a17c6)
+++ CHANGELOG.de.md	(revision da71f9d9973e0edeed10e4bade48fe63b1e6d58c)
@@ -10,4 +10,8 @@
   Musik oder Embed wurde ohne Cover föderiert, sodass eine geteilte Umfrage eine
   leere Kachel zeigte; das Cover reist jetzt mit.
+- **Die Updates-Seite der Android-App zeigt, was wirklich installierbar ist.**
+  Sie las den neuesten Release-Branch, der der Handy-Build kurzzeitig
+  vorauslaufen konnte — Aktualisieren installierte dann dieselbe Version erneut.
+  Sie liest jetzt die Version des Handy-Bundles selbst.
 
 ## [1.3.4] — 2026-07-04
Index: CHANGELOG.md
===================================================================
--- CHANGELOG.md	(revision 0a93c15436f7a8f5a12389660d2feb0a690a17c6)
+++ CHANGELOG.md	(revision da71f9d9973e0edeed10e4bade48fe63b1e6d58c)
@@ -10,4 +10,8 @@
   federating without its cover, so a boosted poll showed a blank tile; the cover
   now travels with it.
+- **The Android app's Updates page shows what's actually installable.** It read
+  the newest release branch, which could be ahead of the phone build for a short
+  while — pressing update then reinstalled the same version. It now reads the
+  version of the phone bundle itself.
 
 ## [1.3.4] — 2026-07-04
Index: CHANGELOG.nl.md
===================================================================
--- CHANGELOG.nl.md	(revision 0a93c15436f7a8f5a12389660d2feb0a690a17c6)
+++ CHANGELOG.nl.md	(revision da71f9d9973e0edeed10e4bade48fe63b1e6d58c)
@@ -10,4 +10,8 @@
   embed federeerde zonder cover, waardoor een geboooste poll een leeg vak toonde;
   de cover reist nu mee.
+- **De Updates-pagina van de Android-app toont wat er écht te installeren valt.**
+  Hij las de nieuwste release-branch, die korte tijd vóór kon lopen op de
+  telefoon-build — bijwerken installeerde dan dezelfde versie opnieuw. Hij leest
+  nu de versie van de telefoonbundel zelf.
 
 ## [1.3.4] — 2026-07-04
Index: src/routes/admin-updates.js
===================================================================
--- src/routes/admin-updates.js	(revision 0a93c15436f7a8f5a12389660d2feb0a690a17c6)
+++ src/routes/admin-updates.js	(revision da71f9d9973e0edeed10e4bade48fe63b1e6d58c)
@@ -45,13 +45,29 @@
 const IS_ANDROID = process.platform === 'android'
   || (() => { try { return fs.existsSync('/data/data/com.termux/files/usr/bin'); } catch { return false; } })();
-// Phone tarballs are built from the stable branch → that's the phone's "latest".
-const ANDROID_LATEST_URL = 'https://raw.githubusercontent.com/roboburr/klonkt/stable/package.json';
+// "Latest" for a phone = what the update button can actually INSTALL: the version
+// of the prebuilt bundle on the release (BUILD-INFO.txt's bundle-version). Reading
+// the stable branch instead showed a new version during the CI window in which the
+// bundle was still being built — pressing update then reinstalled the old version.
+const ANDROID_BUILDINFO_URL = 'https://github.com/roboburr/klonkt-android/releases/download/termux-latest/BUILD-INFO.txt';
+const ANDROID_STABLE_URL = 'https://raw.githubusercontent.com/roboburr/klonkt/stable/package.json';
+
+async function fetchWithTimeout(url, ms) {
+  const ctl = new AbortController();
+  const t = setTimeout(() => ctl.abort(), ms);
+  try { return await fetch(url, { signal: ctl.signal, redirect: 'follow' }); }
+  finally { clearTimeout(t); }
+}
 
 async function androidLatestVersion() {
   try {
-    const ctl = new AbortController();
-    const t = setTimeout(() => ctl.abort(), 8000);
-    const r = await fetch(ANDROID_LATEST_URL, { signal: ctl.signal });
-    clearTimeout(t);
+    const r = await fetchWithTimeout(ANDROID_BUILDINFO_URL, 8000);
+    if (r.ok) {
+      const m = (await r.text()).match(/^bundle-version:\s*(\S+)/m);
+      if (m) return m[1];
+    }
+  } catch { /* fall through */ }
+  // Older releases have no bundle-version line → fall back to the stable branch.
+  try {
+    const r = await fetchWithTimeout(ANDROID_STABLE_URL, 8000);
     if (!r.ok) return null;
     return (await r.json()).version || null;
