Index: src/routes/posts.js
===================================================================
--- src/routes/posts.js	(revision e951b7c4efb52daa3b8964b528fd3f604de85365)
+++ src/routes/posts.js	(revision 2923a951b1ae82d7e0ece377c760c02bf001fc91)
@@ -354,12 +354,15 @@
   } catch (e) { /* FTS issues non-fatal */ }
 
-  // ActivityPub: federate when a post BECOMES published (draft/scheduled → published
-  // via the editor). A brand-new published post is handled in the create route.
-  if (finalStatus === 'published' && post.status !== 'published' && !fanOnly) {
-    ActivityPubService.deliverCreate(site, {
+  // ActivityPub: federate edits to followers. A post that BECOMES published →
+  // Create (new post); an already-published post that's edited → Update (so
+  // Mastodon refreshes its cached copy). fan_only posts don't federate.
+  if (finalStatus === 'published' && !fanOnly) {
+    const apPost = {
       id: post.id, slug: finalSlug, title: title || finalSlug,
       content: cleanContent, cover_image_url: cover_image_url || null,
       published_at: publishedAt, created_at: post.created_at,
-    }).catch(() => { /* best-effort */ });
+    };
+    if (post.status !== 'published') ActivityPubService.deliverCreate(site, apPost).catch(() => { /* best-effort */ });
+    else ActivityPubService.deliverUpdate(site, apPost).catch(() => { /* best-effort */ });
   }
 
