Index: src/config/database.js
===================================================================
--- src/config/database.js	(revision bfa3ba3ce26883066a0df7053c97b2067ddaa1e6)
+++ src/config/database.js	(revision 7ccdced94ed9434ec28142de104082d14bd8cd78)
@@ -895,4 +895,10 @@
   // Rijen van voor deze kolom krijgen hun host hier, eenmalig.
   ensureColumn('ap_delivery', 'host', 'TEXT');
+  // Is deze rij al eens geprobeerd? Dan KAN hij aangekomen zijn, ook al gaf het
+  // een fout (een time-out nadat de ander hem verwerkte). Een Delete voor iets
+  // dat nooit de deur uitging, hoeft niet; voor iets dat misschien aankwam wel.
+  // Standaard 1: van rijen van voor deze kolom weten we het niet, en dan is
+  // "misschien aangekomen" de veilige kant. Nieuwe rijen zeggen het zelf.
+  ensureColumn('ap_delivery', 'tried', 'INTEGER DEFAULT 1');
   try {
     const zonder = db.prepare('SELECT id, inbox FROM ap_delivery WHERE host IS NULL').all();
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision bfa3ba3ce26883066a0df7053c97b2067ddaa1e6)
+++ src/services/ActivityPubService.js	(revision 7ccdced94ed9434ec28142de104082d14bd8cd78)
@@ -34,10 +34,10 @@
 import {
   safeFetch, getOrCreateKeys, deliver, fetchActor,
-  enqueueDelivery, deliverWithRetry, deliverNowOrQueue, processDeliveryQueue, startDeliveryWorker,
+  enqueueDelivery, deliverWithRetry, deliverNowOrQueue, cancelUndelivered, processDeliveryQueue, startDeliveryWorker,
   anySigningSlug, verifyRequest, signedGetHeaders, signedGetJson, apGetJson,
 } from './ap-transport.js';
 export {
   safeFetch, getOrCreateKeys, deliver, fetchActor,
-  enqueueDelivery, deliverWithRetry, deliverNowOrQueue, processDeliveryQueue, startDeliveryWorker,
+  enqueueDelivery, deliverWithRetry, deliverNowOrQueue, cancelUndelivered, processDeliveryQueue, startDeliveryWorker,
   verifyRequest, signedGetHeaders, signedGetJson,
 };
@@ -2850,9 +2850,9 @@
   inboxes.delete(`${me}/inbox`); inboxes.delete(`${base}/ap/inbox`);
   let delivered = 0;
+  // Langs de volgorde per inbox (shaer-xzab.3): een bewerking die vóór de nog
+  // wachtende Create aankomt, wordt genegeerd, en daarna brengt de Create de
+  // oude tekst.
   for (const inbox of [...inboxes].filter(Boolean)) {
-    let ok = false;
-    try { const st = await deliver(inbox, update, `${me}#main-key`, keys.private_pem); ok = st >= 200 && st < 300; } catch { ok = false; }
-    if (ok) delivered++;
-    else enqueueDelivery(site.slug, inbox, update); // durable: retry the edit later (was silently dropped)
+    if ((await deliverNowOrQueue(site.slug, inbox, update, `${me}#main-key`, keys.private_pem)) === 'sent') delivered++;
   }
   console.log('[AP] outreply edit', site.slug, 'delivered', delivered);
@@ -4152,10 +4152,8 @@
     return { delivered: false, inbox: null };
   }
-  try {
-    const st = await deliver(inbox, payload, `${me}#main-key`, keys.private_pem);
-    if (st >= 200 && st < 300) { console.log('[AP] guardianship', activity.type, 'delivered →', inbox, st); return { delivered: true, inbox }; }
-    console.warn('[AP] guardianship', activity.type, 'got', st, 'from', inbox, '→ queued for retry');
-  } catch (e) { console.warn('[AP] guardianship', activity.type, 'to', inbox, 'failed:', e.message, '→ queued for retry'); }
-  enqueueDelivery(site.slug, inbox, payload);
+  // Langs de volgorde per inbox (shaer-xzab.3), zoals elke bezorging.
+  const hoe = await deliverNowOrQueue(site.slug, inbox, payload, `${me}#main-key`, keys.private_pem);
+  if (hoe === 'sent') console.log('[AP] guardianship', activity.type, 'delivered →', inbox);
+  else console.warn('[AP] guardianship', activity.type, 'to', inbox, '→ queued for retry');
   return { delivered: true, inbox };   // queued: the retry worker gets it there
 }
Index: src/services/ap-transport.js
===================================================================
--- src/services/ap-transport.js	(revision bfa3ba3ce26883066a0df7053c97b2067ddaa1e6)
+++ src/services/ap-transport.js	(revision 7ccdced94ed9434ec28142de104082d14bd8cd78)
@@ -241,5 +241,5 @@
 function deliveryStmts() {
   if (!_insDeliv) {
-    _insDeliv = db.prepare('INSERT INTO ap_delivery (slug, inbox, host, body, attempts, next_at) VALUES (?,?,?,?,0,CURRENT_TIMESTAMP)');
+    _insDeliv = db.prepare('INSERT INTO ap_delivery (slug, inbox, host, body, attempts, next_at, tried) VALUES (?,?,?,?,0,CURRENT_TIMESTAMP,?)');
     // Alleen de OUDSTE openstaande rij per inbox: een nieuwere wacht op hem, ook
     // als hij zelf al aan de beurt zou zijn. Op id, want dat is de volgorde
@@ -260,7 +260,44 @@
   return { ins: _insDeliv, due: _dueDeliv, del: _delDeliv, bump: _bumpDeliv, host: _hostDeliv, off: _offDeliv, pendInbox: _pendInbox, hostWaits: _hostWaits };
 }
-export function enqueueDelivery(slug, inbox, activity) {
+// `tried`: ging er al een poging aan vooraf? Standaard ja, want zo riep iedereen
+// dit aan: na een mislukte deliver(). Alleen wie in de rij zet zonder te
+// proberen (deliverNowOrQueue bij een wachtende inbox of server) zegt nee.
+export function enqueueDelivery(slug, inbox, activity, { tried = true } = {}) {
   if (!slug || !inbox || !activity) return;
-  try { deliveryStmts().ins.run(slug, inbox, inboxHost(inbox), JSON.stringify(activity)); } catch { /* ignore */ }
+  try { deliveryStmts().ins.run(slug, inbox, inboxHost(inbox), JSON.stringify(activity), tried ? 1 : 0); } catch { /* ignore */ }
+}
+
+function objectIdOf(activity) {
+  const o = activity && activity.object;
+  return typeof o === 'string' ? o : (o && typeof o.id === 'string' ? o.id : null);
+}
+
+/**
+ * Een Delete van iets dat voor deze inbox nog in de rij staat (Robins vraag,
+ * 26-10: "shouldn't a Delete on an undelivered Create resolve internally?").
+ *
+ * Ja: haal de wachtende Create en Update van dat object uit de rij. Dan komt
+ * wat gewist is nooit meer aan bij een server die het nog niet had -- de
+ * volgorde per inbox alleen zorgde er wel voor dat de Delete NA de Create
+ * kwam, maar de Create kwam dan nog steeds.
+ *
+ * Of de Delete daarna nog hoeft, hangt af van of er iets aangekomen KAN zijn:
+ * een rij die al eens geprobeerd is, kan dat (een time-out nadat de ander hem
+ * verwerkte). Dan gaat de Delete toch; die is onschuldig als ze hem niet
+ * kenden, en zonder hem blijft de post daar misschien staan.
+ */
+export function cancelUndelivered(inbox, objectId) {
+  if (!inbox || !objectId) return { cancelled: 0, mayHaveArrived: false };
+  let cancelled = 0, mayHaveArrived = false;
+  try {
+    for (const r of db.prepare('SELECT id, body, attempts, tried FROM ap_delivery WHERE inbox = ?').all(inbox)) {
+      let a; try { a = JSON.parse(r.body); } catch { continue; }
+      if (!a || (a.type !== 'Create' && a.type !== 'Update') || objectIdOf(a) !== objectId) continue;
+      if (r.tried || r.attempts > 0) mayHaveArrived = true;
+      deliveryStmts().del.run(r.id);
+      cancelled++;
+    }
+  } catch { /* geen wachtrij te lezen: dan gewoon de Delete */ }
+  return { cancelled, mayHaveArrived };
 }
 // Record delivery health per follower so the followers list can flag dead accounts.
@@ -289,9 +326,16 @@
 // hoort (shaer-xzab.3). Drie plekken deden eerst zelf deliver() en pas bij een
 // mislukking enqueueDelivery(), en gingen zo langs de volgorde per inbox.
+//
+// 'cancelled': een Delete van iets dat deze inbox nooit kreeg; er gaat niets
+// heen (zie cancelUndelivered).
 export async function deliverNowOrQueue(slug, inbox, activity, keyId, privPem) {
   if (!inbox) return 'queued';
+  if (activity && activity.type === 'Delete') {
+    const r = cancelUndelivered(inbox, objectIdOf(activity));
+    if (r.cancelled && !r.mayHaveArrived) return 'cancelled';
+  }
   try {
     const st = deliveryStmts();
-    if (st.pendInbox.get(inbox) || st.hostWaits.get(inboxHost(inbox))) { enqueueDelivery(slug, inbox, activity); return 'queued'; }
+    if (st.pendInbox.get(inbox) || st.hostWaits.get(inboxHost(inbox))) { enqueueDelivery(slug, inbox, activity, { tried: false }); 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 */ }
