Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 41a7637a2e5b561b6a96b9a2791ddd41145c13c3)
+++ src/services/ActivityPubService.js	(revision cc24fa1a1c54af244bb602d55eaf9fe37c7e9565)
@@ -455,4 +455,8 @@
     ? `<a href="${escHtml(parent.actor_url || parent.actor_uri)}" class="u-url mention">${escHtml(handle)}</a> ` : '';
   const content = `<p>${mention}${body}</p>`;
+  // Dedup: skip if the exact same reply was already sent (double-submit guard).
+  const dup = db.prepare('SELECT 1 FROM ap_outbox WHERE site_slug = ? AND IFNULL(in_reply_to, \'\') = ? AND content = ? LIMIT 1')
+    .get(site.slug, parent.object_uri || '', content);
+  if (dup) { console.log('[AP] outreply skipped (duplicate)'); return { duplicate: true, delivered: 0 }; }
   const id = crypto.randomUUID();
   iStmts().insO.run(id, site.slug, postId, postSlug || null, parent.object_uri || null, parent.actor_uri || null, handle, content);
