Index: src/services/MigrationService.js
===================================================================
--- src/services/MigrationService.js	(revision 919b82d343b38d9d40af336bd94eda6a74068b2b)
+++ src/services/MigrationService.js	(revision 19430fafe4c1863c62c35afc3d379b4fc3f511b7)
@@ -417,17 +417,14 @@
         if (auteur && auteur !== bronActor.id) continue;              // alleen wat van HEM was
         gezien++;
-        // Al binnen? Alleen overslaan als het bericht er OOK nog staat. Heb je
-        // het verwijderd, dan is opnieuw ophalen precies wat je bedoelt, en
-        // een mapping die dat blokkeert is een val: opruimen hielp dan niet,
-        // want de blokkade zat in ap_migration en niet in de posts.
-        const eerderPost = migrationTarget(site.slug, o.id);
-        if (eerderPost) {
-          const postId = String(eerderPost).split('/').pop();
-          if (db.prepare('SELECT 1 FROM posts WHERE id = ? AND site_id = ?').get(decodeURIComponent(postId), site.id)) {
-            rapport.overgeslagen++;
-            continue;
-          }
-          rapport.opnieuw++;   // weg hier, dus opnieuw binnenhalen
-        }
+        // Het interne id BLIJFT (Robins besluit, 14-8). Daarmee is "staat hij
+        // hier al" gewoon een blik in de tabel, en niet iets dat je uit een
+        // aparte mapping moet afleiden. Verwijder je een bericht en haal je
+        // opnieuw op, dan komt het gewoon terug: er staat immers niets meer.
+        const id = ruwId(o.id) || crypto.randomUUID();
+        if (db.prepare('SELECT 1 FROM posts WHERE id = ? AND site_id = ?').get(id, site.id)) {
+          rapport.overgeslagen++;
+          continue;
+        }
+        if (migrationTarget(site.slug, o.id)) rapport.opnieuw++;   // was er, is weg, komt terug
 
         // Media eerst, want een post die naar een plaatje wijst dat we niet
@@ -451,5 +448,4 @@
         }
 
-        const id = crypto.randomUUID();
         const cover = binnen.find((b) => AFBEELDING.test(b.type || ''));
         const rest = binnen.filter((b) => b !== cover);
@@ -526,9 +522,8 @@
         // Alleen LEGE velden worden gevuld. Wat jij zelf hebt aangepast blijft
         // staan; een migratie hoort je correcties niet terug te draaien.
-        const eerder = migrationTarget(site.slug, a.id);
-        if (eerder) {
-          const lokaalId = String(eerder).split('/').pop();
+        const trackId = ruwId(a.id) || crypto.randomUUID();
+        {
           const rij = db.prepare('SELECT id, cover_url, duration, artist FROM audio_tracks WHERE id = ? AND site_id = ?')
-            .get(lokaalId, site.id);
+            .get(trackId, site.id);
           if (rij) {
             trackKaart.set(String(a.id), rij.id);   // MOET, anders vinden de playlists hem niet
@@ -557,6 +552,4 @@
             continue;
           }
-          // De rij is weg maar de mapping staat er nog. Dan is opnieuw ophalen
-          // precies wat je wilt, dus we vallen door naar de gewone tak.
         }
         const bron = a.url && (typeof a.url === 'string' ? a.url : (Array.isArray(a.url) ? (a.url[0] && (a.url[0].href || a.url[0])) : a.url.href));
@@ -583,5 +576,4 @@
           else rapport.waarschuwingen.push(`hoes niet opgehaald: ${a.name || hoesUrl}`);
         }
-        const trackId = crypto.randomUUID();
         const mediaId = crypto.randomUUID();
         try {
@@ -651,7 +643,4 @@
           continue;
         }
-        // Bestond hij al? Dan dezelfde rij bijwerken. Zonder deze stap levert
-        // elke tweede ronde een dubbele plaat op.
-        const eerderPl = migrationTarget(site.slug, uri);
         // De hoes van de plaat, net als bij een nummer.
         let plHoes = null;
@@ -665,10 +654,7 @@
           else rapport.waarschuwingen.push(`hoes van playlist niet opgehaald: ${plc.name || uri}`);
         }
-        const plId = (() => {
-          if (!eerderPl) return crypto.randomUUID();
-          const bestaand = String(eerderPl).split('/').pop();
-          return db.prepare('SELECT 1 FROM playlists WHERE id = ? AND site_id = ?').get(bestaand, site.id)
-            ? bestaand : crypto.randomUUID();
-        })();
+        // Ook hier het id van de bron. Dan blijft [[playlist:<id>]] in een
+        // bericht wijzen, en is een tweede ronde vanzelf dezelfde rij.
+        const plId = ruwId(uri) || crypto.randomUUID();
         try {
           db.prepare(`INSERT INTO playlists (id, site_id, title, artist, year, kind, cover_url) VALUES (?,?,?,?,?,?,?)
