Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision e311202e61b8a8e0ce2a0f0f23d873495f89d76f)
+++ src/services/ActivityPubService.js	(revision 4e5fe295413a76ce5327e908eaa1d702d538ee59)
@@ -1263,7 +1263,40 @@
 }
 // Manually drop a follower after a check (a still-live account would have to re-follow).
+/**
+ * Een volger verwijderen, en het hem ook LATEN WETEN (Robin, 21-8).
+ *
+ * Reject(Follow) is het standaardsignaal voor "je volgt me niet meer": de
+ * andere kant ruimt de relatie dan op in plaats van te blijven denken dat hij
+ * volgt. Zonder dit merkte de hub niets -- die bleef als volger in zijn eigen
+ * boeken staan terwijl er nooit meer iets werd bezorgd.
+ *
+ * Verwijderen gaat altijd door; de melding is een gunst en mag mislukken.
+ */
 export function removeFollower(slug, id) {
+  const rij = db.prepare('SELECT actor_uri FROM ap_followers WHERE slug = ? AND id = ?').get(slug, id);
   const info = db.prepare('DELETE FROM ap_followers WHERE slug = ? AND id = ?').run(slug, id);
+  if (info.changes > 0 && rij && rij.actor_uri) meldNietLangerVolger(slug, rij.actor_uri);
   return info.changes > 0;
+}
+
+/** Reject(Follow) naar een ex-volger; faalt stil, want de relatie is al weg. */
+export function meldNietLangerVolger(slug, actorUri) {
+  try {
+    const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
+    const me = actorId(base, slug);
+    const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get(slug);
+    if (!site) return;
+    const reject = {
+      '@context': AP_CONTEXT,
+      id: `${me}#reject-follow-${Date.now()}-${rid()}`,
+      type: 'Reject',
+      actor: me,
+      to: [actorUri],
+      object: { type: 'Follow', actor: actorUri, object: me },
+    };
+    deliverToActor(site, actorUri, reject)
+      .then((r) => console.log('[AP] Reject(Follow)', slug, '→', actorUri, r && r.delivered ? 'bezorgd' : 'niet bezorgd'))
+      .catch(() => {});
+  } catch { /* nooit blokkerend */ }
 }
 
Index: test/block-federeert.test.js
===================================================================
--- test/block-federeert.test.js	(revision e311202e61b8a8e0ce2a0f0f23d873495f89d76f)
+++ test/block-federeert.test.js	(revision 4e5fe295413a76ce5327e908eaa1d702d538ee59)
@@ -76,2 +76,17 @@
   assert.equal(db.prepare('SELECT count(*) c FROM ap_blocks WHERE target = ?').get('https://203.0.113.99/ap/actor').c, 1);
 });
+
+test('een verwijderde volger krijgt een Reject(Follow)', async () => {
+  bezorgd.length = 0;
+  const VOLGER = 'https://203.0.113.81/ap/actor';
+  db.prepare(`INSERT INTO ap_followers (slug, actor_uri, inbox, created_at)
+              VALUES ('dev', ?, ?, CURRENT_TIMESTAMP)`).run(VOLGER, `${VOLGER}/inbox`);
+  const rij = db.prepare('SELECT id FROM ap_followers WHERE actor_uri = ?').get(VOLGER);
+  assert.equal(AP.removeFollower('dev', rij.id), true);
+  await new Promise((r) => setTimeout(r, 150));   // bezorging is fire-and-forget
+  const rej = bezorgd.find((b) => b.activiteit.type === 'Reject');
+  assert.ok(rej, 'er is een Reject bezorgd');
+  assert.equal(rej.activiteit.object.type, 'Follow');
+  assert.equal(rej.activiteit.object.actor, VOLGER, 'het gaat om ZIJN follow op ons');
+  assert.equal(db.prepare('SELECT count(*) c FROM ap_followers WHERE actor_uri = ?').get(VOLGER).c, 0);
+});
