Index: src/config/database.js
===================================================================
--- src/config/database.js	(revision aa521c34b7f04012f799c30105288fb176538c25)
+++ src/config/database.js	(revision 8151340aee19dd0280b5185a8c3e9c56dc279653)
@@ -21,4 +21,31 @@
 db.pragma('busy_timeout = 5000');   // wait up to 5s for a lock instead of failing immediately
 db.pragma('synchronous = NORMAL');  // safe with WAL (no torn writes); fewer fsyncs = faster writes
+
+/**
+ * Tijdstempels in EEN spelling (shaer-a937).
+ *
+ * Deze database draagt twee vormen door elkaar: '2026-08-06 09:02:01' van
+ * CURRENT_TIMESTAMP en '2026-08-06T02:08:01.000Z' van toISOString(). SQLite
+ * vergelijkt ze als TEKST, en op positie 10 staat een 'T' (0x54) tegenover een
+ * spatie (0x20) -- dus binnen dezelfde dag wint de ISO-vorm altijd, hoe laat hij
+ * ook is. Een antwoord van 02:08 kwam zo boven een like van 09:02 te staan.
+ *
+ * `NU_ISO` is wat je SCHRIJFT, `isoSql()` is waarmee je VERGELIJKT of SORTEERT.
+ * De twee horen bij elkaar: het eerste zorgt dat er niets nieuws bijkomt, het
+ * tweede dat wat er al staat toch goed op volgorde komt.
+ *
+ * isoSql valt met COALESCE terug op de RAUWE waarde: strftime geeft NULL op iets
+ * dat het niet als tijd herkent, en zonder die terugval zou zo'n rij uit de
+ * sortering vallen -- of erger, als hij ook geSELECTeerd wordt (de cursor in de
+ * gesprekslezing) zou de client een lege stempel terugkrijgen en zijn plek
+ * kwijtraken. Waar zo'n onleesbare waarde dan LANDT is onbepaald: hij wordt als
+ * tekst vergeleken en 'geen datum' staat nu eenmaal boven '2026-...'. Dat is de
+ * juiste ruil -- data die je niet begrijpt bewaar je, je gooit hem niet weg.
+ *
+ * Ze staan HIER en niet in een dienst omdat ze over de opslag gaan: elke plek
+ * die sorteert importeert `db` toch al uit dit bestand.
+ */
+export const NU_ISO = "strftime('%Y-%m-%dT%H:%M:%SZ','now')";
+export const isoSql = (expr) => `COALESCE(strftime('%Y-%m-%dT%H:%M:%SZ', ${expr}), ${expr})`;
 
 export function initializeDatabase() {
Index: src/services/ArchiveExportService.js
===================================================================
--- src/services/ArchiveExportService.js	(revision aa521c34b7f04012f799c30105288fb176538c25)
+++ src/services/ArchiveExportService.js	(revision 8151340aee19dd0280b5185a8c3e9c56dc279653)
@@ -18,5 +18,5 @@
 import path from 'path';
 import crypto from 'crypto';
-import db from '../config/database.js';
+import db, { isoSql } from '../config/database.js';
 import { MEDIA_ROOT, resolveAudioPath } from '../config/paths.js';
 
@@ -494,5 +494,5 @@
   // is de volgorde van twee posts op dezelfde seconde niet bepaald.
   const posts = db.prepare(`SELECT * FROM posts WHERE site_id = ?
-                             ORDER BY COALESCE(published_at, created_at) ASC, id ASC`).all(site.id);
+                             ORDER BY ${isoSql('COALESCE(published_at, created_at)')} ASC, id ASC`).all(site.id);
 
   for (const post of posts) {
@@ -539,5 +539,5 @@
     try {
       replies = db.prepare(`SELECT * FROM ap_interactions WHERE post_id = ? AND kind = 'reply'
-                             ORDER BY COALESCE(published, created_at) ASC, id ASC`).all(post.id);
+                             ORDER BY ${isoSql('COALESCE(published, created_at)')} ASC, id ASC`).all(post.id);
     } catch { /* tabel kan ontbreken op een heel oude database */ }
     if (replies.length) {
Index: src/services/ap-cirkel.js
===================================================================
--- src/services/ap-cirkel.js	(revision aa521c34b7f04012f799c30105288fb176538c25)
+++ src/services/ap-cirkel.js	(revision 8151340aee19dd0280b5185a8c3e9c56dc279653)
@@ -7,5 +7,5 @@
  * een werktuig uit de dienstlaag: alleen db.
  */
-import db from '../config/database.js';
+import db, { isoSql } from '../config/database.js';
 
 // ── Cirkel = posts from the accounts you auto-boost ("feature an artist") ──
@@ -29,5 +29,5 @@
       LEFT JOIN ap_my_reactions rb ON rb.site_slug = t.slug AND rb.target_uri = t.id AND rb.kind = 'boost'
       WHERE t.slug = ? AND (f.auto_boost = 1 OR rb.target_uri IS NOT NULL)
-      ORDER BY COALESCE(t.published, t.created_at) DESC, t.rowid DESC
+      ORDER BY ${isoSql('COALESCE(t.published, t.created_at)')} DESC, t.rowid DESC
       LIMIT ? OFFSET ?`);
     return _cirkelPosts.all(slug, limit || 60, offset || 0);
Index: src/services/ap-timeline.js
===================================================================
--- src/services/ap-timeline.js	(revision aa521c34b7f04012f799c30105288fb176538c25)
+++ src/services/ap-timeline.js	(revision 8151340aee19dd0280b5185a8c3e9c56dc279653)
@@ -13,5 +13,10 @@
  * wireTimeline, hetzelfde injectiepatroon als guardianship en ap-c2s.
  */
-import db from '../config/database.js';
+import db, { isoSql } from '../config/database.js';
+
+// De helper woont sinds shaer-a937 in config/database.js: elke plek die
+// sorteert had hem nodig, en twee kopieen van dezelfde regel lopen uit elkaar.
+// Bovenaan, want de eerste statements hieronder gebruiken hem al.
+const STEMPEL = isoSql;
 
 // Het ene werktuig uit de dienstlaag. ActivityPubService vult het onderaan
@@ -26,5 +31,5 @@
   if (!_insTl) {
     _insTl = db.prepare('INSERT OR IGNORE INTO ap_timeline (id, slug, author_uri, author_name, author_handle, author_icon, author_url, content, url, published, media_json, nsfw, cw, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)');
-    _listTl = db.prepare('SELECT * FROM ap_timeline WHERE slug = ? ORDER BY COALESCE(published, created_at) DESC LIMIT ? OFFSET ?');
+    _listTl = db.prepare(`SELECT * FROM ap_timeline WHERE slug = ? ORDER BY ${STEMPEL('COALESCE(published, created_at)')} DESC LIMIT ? OFFSET ?`);
     _delTl = db.prepare('DELETE FROM ap_timeline WHERE id = ?');
   }
@@ -119,5 +124,5 @@
       JOIN sites s ON s.id = p.site_id
       WHERE s.slug = ? AND i.kind = 'reply'
-      ORDER BY COALESCE(i.published, i.created_at) DESC LIMIT ?`).all(slug, limit || 60);
+      ORDER BY ${STEMPEL('COALESCE(i.published, i.created_at)')} DESC LIMIT ?`).all(slug, limit || 60);
   } catch { return []; }
 }
@@ -242,5 +247,4 @@
  * een leeftijd die twee uur verschilde per vorm.
  */
-const STEMPEL = (rauw) => `COALESCE(strftime('%Y-%m-%dT%H:%M:%SZ', ${rauw}), ${rauw})`;
 
 const CONVERSATION_UNION = `
@@ -425,5 +429,5 @@
       WHERE m.slug = ?
         AND NOT EXISTS (SELECT 1 FROM ap_timeline t WHERE t.slug = m.slug AND t.id = m.object_uri)
-      ORDER BY COALESCE(m.published, m.created_at) DESC LIMIT ?`).all(slug, limit || 60);
+      ORDER BY ${STEMPEL('COALESCE(m.published, m.created_at)')} DESC LIMIT ?`).all(slug, limit || 60);
   } catch { return []; }
 }
