Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 31288dcbb27f353ad78d4fa8c0e0b21f9b50bb50)
+++ src/services/ActivityPubService.js	(revision bfa3ba3ce26883066a0df7053c97b2067ddaa1e6)
@@ -34,10 +34,10 @@
 import {
   safeFetch, getOrCreateKeys, deliver, fetchActor,
-  enqueueDelivery, deliverWithRetry, processDeliveryQueue, startDeliveryWorker,
+  enqueueDelivery, deliverWithRetry, deliverNowOrQueue, processDeliveryQueue, startDeliveryWorker,
   anySigningSlug, verifyRequest, signedGetHeaders, signedGetJson, apGetJson,
 } from './ap-transport.js';
 export {
   safeFetch, getOrCreateKeys, deliver, fetchActor,
-  enqueueDelivery, deliverWithRetry, processDeliveryQueue, startDeliveryWorker,
+  enqueueDelivery, deliverWithRetry, deliverNowOrQueue, processDeliveryQueue, startDeliveryWorker,
   verifyRequest, signedGetHeaders, signedGetJson,
 };
@@ -2416,8 +2416,7 @@
   let delivered = 0;
   for (const inbox of [...inboxes].filter(Boolean)) {
-    let ok = false;
-    try { const st = await deliver(inbox, create, keyId, keys.private_pem); ok = st >= 200 && st < 300; } catch { ok = false; }
-    if (ok) delivered++;
-    else enqueueDelivery(site.slug, inbox, create); // durable: retry a briefly-offline recipient (was silently dropped)
+    // Langs de volgorde per inbox (shaer-xzab.3); wat niet meteen kan, gaat
+    // in de rij en wordt later opnieuw geprobeerd.
+    if ((await deliverNowOrQueue(site.slug, inbox, create, keyId, keys.private_pem)) === 'sent') delivered++;
   }
   console.log('[AP] outreply', site.slug, '→', parent.actor_uri, 'delivered', delivered);
@@ -2789,8 +2788,8 @@
     if (row.to_actor) { const a = await fetchActor(row.to_actor).catch(() => null); if (a) inboxes.add((a.endpoints && a.endpoints.sharedInbox) || a.inbox); }
     for (const f of fStmts().list.all(site.slug)) inboxes.add(f.shared_inbox || f.inbox);
-    for (const inbox of [...inboxes].filter(Boolean)) {
-      try { const st = await deliver(inbox, del, `${me}#main-key`, keys.private_pem); if (st >= 200 && st < 300) continue; } catch { /* queue below */ }
-      enqueueDelivery(site.slug, inbox, del); // durable: a failed comment-delete now retries (was silently dropped)
-    }
+    // Langs de volgorde per inbox (shaer-xzab.3): deze Delete mag niet vóór
+    // de Create van dezelfde reactie aankomen als die nog in de rij wacht --
+    // dan stond de reactie daarna weer op die server.
+    for (const inbox of [...inboxes].filter(Boolean)) await deliverNowOrQueue(site.slug, inbox, del, `${me}#main-key`, keys.private_pem);
   }
   db.prepare('DELETE FROM ap_outbox WHERE id = ?').run(outboxId);
@@ -4164,5 +4163,5 @@
   actorId, fetchActor, localActor, deliverTo: deliverToActor, deriveHandle, escHtml, linkUrls, linkHashtags,
   getOutboxRow: (id) => iStmts().getO.get(id),
-  buildReplyNote, AP_CONTEXT, getOrCreateKeys, deliver, enqueueDelivery,
+  buildReplyNote, AP_CONTEXT, getOrCreateKeys, deliverNowOrQueue,
   // Rijke directe berichten: dezelfde sanitizer als deliverReply gebruikt, zodat
   // een antwoord uit Berichten door precies één poort gaat.
Index: src/services/ap-transport.js
===================================================================
--- src/services/ap-transport.js	(revision 31288dcbb27f353ad78d4fa8c0e0b21f9b50bb50)
+++ src/services/ap-transport.js	(revision bfa3ba3ce26883066a0df7053c97b2067ddaa1e6)
@@ -278,5 +278,6 @@
   } catch { /* health tracking is non-fatal */ }
 }
-// Deliver now; queue for retry if it fails.
+// Deliver now, or queue: zegt welke van de twee het werd ('sent' | 'queued'),
+// voor de aanroepers die tellen wat er meteen aankwam.
 //
 // Niet meteen als er voor deze inbox al iets in de wachtrij staat (dan zou dit
@@ -284,12 +285,21 @@
 // server net faalde en in zijn backoff zit (dan kost het alleen acht seconden
 // time-out om hetzelfde te horen). Dan achteraan in de rij.
+//
+// DE ENIGE WEG om iets direct te versturen dat bij een mislukking in de rij
+// hoort (shaer-xzab.3). Drie plekken deden eerst zelf deliver() en pas bij een
+// mislukking enqueueDelivery(), en gingen zo langs de volgorde per inbox.
+export async function deliverNowOrQueue(slug, inbox, activity, keyId, privPem) {
+  if (!inbox) return 'queued';
+  try {
+    const st = deliveryStmts();
+    if (st.pendInbox.get(inbox) || st.hostWaits.get(inboxHost(inbox))) { enqueueDelivery(slug, inbox, activity); return 'queued'; }
+  } catch { /* geen wachtrij te lezen: gewoon proberen */ }
+  try { const st = await deliver(inbox, activity, keyId, privPem); if (st >= 200 && st < 300) { markFollowerDelivery(slug, inbox, true); return 'sent'; } } catch { /* queue below */ }
+  enqueueDelivery(slug, inbox, activity);
+  return 'queued';
+}
+// Deliver now; queue for retry if it fails.
 export async function deliverWithRetry(slug, inbox, activity, keyId, privPem) {
-  if (!inbox) return;
-  try {
-    const st = deliveryStmts();
-    if (st.pendInbox.get(inbox) || st.hostWaits.get(inboxHost(inbox))) { enqueueDelivery(slug, inbox, activity); return; }
-  } catch { /* geen wachtrij te lezen: gewoon proberen */ }
-  try { const st = await deliver(inbox, activity, keyId, privPem); if (st >= 200 && st < 300) { markFollowerDelivery(slug, inbox, true); return; } } catch { /* queue below */ }
-  enqueueDelivery(slug, inbox, activity);
+  await deliverNowOrQueue(slug, inbox, activity, keyId, privPem);
 }
 let _processingDeliv = false;
Index: src/services/guardianship/delivery.js
===================================================================
--- src/services/guardianship/delivery.js	(revision 31288dcbb27f353ad78d4fa8c0e0b21f9b50bb50)
+++ src/services/guardianship/delivery.js	(revision bfa3ba3ce26883066a0df7053c97b2067ddaa1e6)
@@ -93,5 +93,5 @@
   if (!inReplyTo && helpMark && helpMark.noteUri) inReplyTo = helpMark.noteUri;
   const { actorId, fetchActor, localActor, deliverTo, deriveHandle, escHtml, linkUrls, linkHashtags,
-          getOutboxRow, buildReplyNote, AP_CONTEXT, getOrCreateKeys, deliver, enqueueDelivery } = deps;
+          getOutboxRow, buildReplyNote, AP_CONTEXT, getOrCreateKeys, deliverNowOrQueue } = deps;
   const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
   const list = [...new Set((recipients || []).filter((u) => /^https?:\/\//i.test(String(u || ''))))].slice(0, 8);
@@ -207,9 +207,7 @@
   }
   // Remote: one POST per inbox, so two guardians on the same server share it.
+  // Langs de volgorde per inbox (shaer-xzab.3), zoals elke bezorging.
   for (const inbox of [...new Set(resolved.filter((x) => !x.local).map((r) => r.inbox))]) {
-    let ok = false;
-    try { const st = await deliver(inbox, create, keyId, keys.private_pem); ok = st >= 200 && st < 300; } catch { ok = false; }
-    if (ok) delivered++;
-    else enqueueDelivery(site.slug, inbox, create);
+    if ((await deliverNowOrQueue(site.slug, inbox, create, keyId, keys.private_pem)) === 'sent') delivered++;
   }
   console.log('[AP] direct note', site.slug, '→', resolved.length, 'recipient(s), delivered', delivered);
Index: test/direct-sends-queue.test.js
===================================================================
--- test/direct-sends-queue.test.js	(revision bfa3ba3ce26883066a0df7053c97b2067ddaa1e6)
+++ test/direct-sends-queue.test.js	(revision bfa3ba3ce26883066a0df7053c97b2067ddaa1e6)
@@ -0,0 +1,109 @@
+// Ook de directe verzenders gaan langs de volgorde per inbox (shaer-xzab.3).
+//
+// Drie plekken verstuurden zelf met deliver() en zetten pas bij een mislukking
+// in de rij: een antwoord (deliverReply), het wissen daarvan
+// (deliverOutboxDelete) en een direct bericht (deliverDirectNote, ook de
+// hulpvraag). Zo kon een Delete aankomen vóór de Create die nog in de rij
+// wachtte -- en stond het antwoord daarna weer op die server.
+//
+// Tegen echte HTTP-servers op 127.0.0.1, toegelaten via AP_ALLOW_HOSTS.
+import { test } from 'node:test';
+import assert from 'node:assert/strict';
+import http from 'http';
+
+process.env.DATABASE_PATH = ':memory:';
+process.env.PUBLIC_BASE_URL = 'https://klonkt.test';
+
+const ontvangen = [];      // { pad, type }
+let status = 202;
+const ander = http.createServer((req, res) => {
+  let body = '';
+  req.on('data', (c) => { body += c; });
+  req.on('end', () => {
+    const host = `http://${req.headers.host}`;
+    if (req.method === 'GET' && req.url === '/users/oma') {
+      res.setHeader('Content-Type', 'application/activity+json');
+      return res.end(JSON.stringify({ id: `${host}/users/oma`, type: 'Person', preferredUsername: 'oma', inbox: `${host}/users/oma/inbox` }));
+    }
+    try { const a = JSON.parse(body); ontvangen.push({ pad: req.url, type: a.type }); } catch { /* geen json */ }
+    res.statusCode = status; res.end();
+  });
+});
+await new Promise((r) => ander.listen(0, '127.0.0.1', r));
+const host = `127.0.0.1:${ander.address().port}`;
+const inbox = `http://${host}/inbox`;
+process.env.AP_ALLOW_HOSTS = host;
+test.after(() => ander.close());
+
+const dbMod = await import('../src/config/database.js');
+const db = dbMod.default;
+{ const stil = console.log; console.log = () => {}; try { dbMod.initializeDatabase(); } finally { console.log = stil; } }
+const AP = await import('../src/services/ActivityPubService.js');
+
+db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)').run('u1', 'robin', 'r@test', 'x', 'god');
+db.prepare('INSERT INTO sites (id, slug, title, owner_id) VALUES (?,?,?,?)').run('s1', 'me', 'Me', 'u1');
+const site = db.prepare('SELECT * FROM sites WHERE slug = ?').get('me');
+db.prepare('INSERT INTO ap_followers (slug, actor_uri, inbox) VALUES (?,?,?)').run('me', `http://${host}/users/volger`, inbox);
+const parent = {
+  id: 1, post_id: '', actor_uri: 'https://unresolvable.invalid/u/ness',
+  actor_url: 'https://unresolvable.invalid/@ness', actor_handle: '@ness@unresolvable.invalid',
+  object_uri: 'https://unresolvable.invalid/notes/9',
+};
+
+const rij = () => db.prepare('SELECT * FROM ap_delivery ORDER BY id').all();
+const typen = () => rij().map((r) => JSON.parse(r.body).type);
+const leeg = () => { db.prepare('DELETE FROM ap_delivery').run(); ontvangen.length = 0; status = 202; };
+const stil = (f) => async () => { const l = console.log, w = console.warn; console.log = () => {}; console.warn = () => {}; try { await f(); } finally { console.log = l; console.warn = w; } };
+
+test('een gewist antwoord komt niet aan vóór het antwoord zelf', stil(async () => {
+  leeg();
+  status = 503;                                            // de server van de volger hapert
+  const r = await AP.deliverReply(site, { postId: '', postSlug: null, parent, text: 'eerst' });
+  assert.equal(r.delivered, 0);
+  assert.deepEqual(typen(), ['Create'], 'het antwoord wacht in de rij');
+
+  status = 202;                                            // hij is er weer, de rij is nog niet geweest
+  ontvangen.length = 0;
+  await AP.deliverOutboxDelete(site, r.id);
+  assert.deepEqual(ontvangen, [], 'de Delete gaat niet voor');
+  assert.deepEqual(typen(), ['Create', 'Delete'], 'hij wacht achter de Create');
+
+  await AP.processDeliveryQueue();
+  await AP.processDeliveryQueue();
+  assert.deepEqual(ontvangen.map((o) => o.type), ['Create', 'Delete'], 'en zo komen ze aan');
+}));
+
+test('een antwoord gaat niet voorbij wat er voor die inbox al wacht', stil(async () => {
+  leeg();
+  AP.enqueueDelivery('me', inbox, { type: 'Create', id: 'https://klonkt.test/eerder' });
+  const r = await AP.deliverReply(site, { postId: '', postSlug: null, parent, text: 'later' });
+  assert.equal(r.delivered, 0, 'niet als verstuurd geteld');
+  assert.deepEqual(ontvangen, []);
+  assert.equal(rij().length, 2);
+}));
+
+test('zonder wachtrij gaat een antwoord gewoon meteen, en telt', stil(async () => {
+  leeg();
+  const r = await AP.deliverReply(site, { postId: '', postSlug: null, parent, text: 'meteen' });
+  assert.equal(r.delivered, 1);
+  assert.deepEqual(ontvangen.map((o) => o.type), ['Create']);
+  assert.deepEqual(rij(), []);
+}));
+
+test('een direct bericht gaat niet voorbij wat er voor die inbox al wacht', stil(async () => {
+  leeg();
+  const omaInbox = `http://${host}/users/oma/inbox`;
+  AP.enqueueDelivery('me', omaInbox, { type: 'Create', id: 'https://klonkt.test/eerder' });
+  const r = await AP.deliverDirectNote(site, { recipients: [`http://${host}/users/oma`], text: 'hoi oma' });
+  assert.ok(r, 'het bericht is gemaakt');
+  assert.equal(r.delivered, 0);
+  assert.deepEqual(ontvangen, [], 'niets voorbij de wachtende');
+  assert.deepEqual(rij().map((x) => x.inbox), [omaInbox, omaInbox]);
+}));
+
+test('zonder wachtrij gaat een direct bericht meteen, en telt', stil(async () => {
+  leeg();
+  const r = await AP.deliverDirectNote(site, { recipients: [`http://${host}/users/oma`], text: 'hoi oma, nu' });
+  assert.equal(r.delivered, 1);
+  assert.deepEqual(ontvangen.map((o) => o.type), ['Create']);
+}));
