Index: src/services/BlocklistService.js
===================================================================
--- src/services/BlocklistService.js	(revision 6b5d7da762e4f4cedbefb24fb218a1006897f071)
+++ src/services/BlocklistService.js	(revision e311202e61b8a8e0ce2a0f0f23d873495f89d76f)
@@ -56,5 +56,24 @@
 // `resolveHandle` (async handle → actor URL) is injected by the caller so this
 // service needs nothing from ActivityPubService (no circular import).
-export async function blockTarget(site, input, resolveHandle) {
+/**
+ * Een blokkade is pas een blokkade als de ander het merkt (Robin, 21-8).
+ *
+ * Tot vandaag bleef hij binnenshuis: rij in ap_blocks, inhoud opruimen, volger
+ * eruit -- en verder niets. De andere kant volgde je dan nog steeds in zijn
+ * eigen boeken en bleef je publieke outbox lezen. Precies wat de hub deed:
+ * kanaal en berichten stonden er gewoon nog. Vandaar dat we het nu ook
+ * VERSTUREN, zoals Mastodon dat doet: een Block naar de inbox van wie je
+ * blokkeert, en bij opheffen een Undo(Block) zodat de weg terug openligt.
+ *
+ * Alleen voor een actor-blokkade: een heel domein heeft geen inbox om aan te
+ * schrijven. En bezorgen mag nooit de blokkade zelf tegenhouden -- die staat
+ * al vast in de database voordat we ook maar iets proberen te versturen.
+ */
+async function meldBlokkade(site, target, kind, bezorg, undo = false) {
+  if (kind !== 'actor' || typeof bezorg !== 'function') return;
+  try { await bezorg(site, target, undo); } catch { /* de blokkade staat, de melding is een gunst */ }
+}
+
+export async function blockTarget(site, input, resolveHandle, bezorg) {
   const raw = String(input || '').trim();
   if (!site || !site.slug || !raw) return { error: 'empty' };
@@ -69,8 +88,16 @@
   purgeBlocked(kind, target);
   console.log('[AP] block', site.slug, kind, target);
+  await meldBlokkade(site, target, kind, bezorg);
   return { ok: true, label };
 }
 
-export function unblock(site, target) { blStmts().del.run(site.slug, target); return { ok: true }; }
+export async function unblock(site, target, bezorg) {
+  const rij = blStmts().list.all(site.slug).find((b) => b.target === target);
+  blStmts().del.run(site.slug, target);
+  // Undo(Block) zodat de ander weet dat de deur weer open is; zonder dit blijft
+  // hij bij zichzelf geblokkeerd staan en komt hij nooit terug.
+  await meldBlokkade(site, target, (rij && rij.kind) || 'actor', bezorg, true);
+  return { ok: true };
+}
 
 export default { listBlocks, isBlockedAny, blockTarget, unblock };
