Index: src/routes/activitypub.js
===================================================================
--- src/routes/activitypub.js	(revision d3a1abdc2929d6581864dfb33aae492a310becf7)
+++ src/routes/activitypub.js	(revision a9da2c04639cc50ea277110a4eac16c934999834)
@@ -106,5 +106,5 @@
   const fanClause = audience === 'friend' ? '' : "AND (fan_only IS NULL OR fan_only = 0)";
   const posts = db.prepare(
-    `SELECT id, slug, title, content, cover_image_url, cover_video_url, nsfw, content_warning, published_at, created_at
+    `SELECT id, slug, title, content, cover_image_url, cover_video_url, nsfw, content_warning, c2s_attachments, published_at, created_at
      FROM posts WHERE site_id = ? AND status = 'published' ${fanClause}
      ORDER BY COALESCE(published_at, created_at) DESC LIMIT 20`
@@ -410,5 +410,5 @@
   // rank 1 last) → Mastodon flips it back to pin-rank ascending on the profile.
   const posts = db.prepare(
-    `SELECT id, slug, title, content, cover_image_url, cover_video_url, nsfw, content_warning, published_at, created_at
+    `SELECT id, slug, title, content, cover_image_url, cover_video_url, nsfw, content_warning, c2s_attachments, published_at, created_at
      FROM posts WHERE site_id = ? AND status = 'published' AND (fan_only IS NULL OR fan_only = 0)
        AND pinned IS NOT NULL AND pinned > 0
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision d3a1abdc2929d6581864dfb33aae492a310becf7)
+++ src/services/ActivityPubService.js	(revision a9da2c04639cc50ea277110a4eac16c934999834)
@@ -1921,5 +1921,5 @@
   if (!site) return;
   const recent = db.prepare(
-    `SELECT id, slug, title, content, cover_image_url, cover_video_url, nsfw, content_warning, published_at, created_at
+    `SELECT id, slug, title, content, cover_image_url, cover_video_url, nsfw, content_warning, c2s_attachments, published_at, created_at
      FROM posts WHERE site_id = ? AND status = 'published' AND (fan_only IS NULL OR fan_only = 0)
      ORDER BY COALESCE(published_at, created_at) DESC LIMIT 20`
Index: test/c2s-compose.test.js
===================================================================
--- test/c2s-compose.test.js	(revision d3a1abdc2929d6581864dfb33aae492a310becf7)
+++ test/c2s-compose.test.js	(revision a9da2c04639cc50ea277110a4eac16c934999834)
@@ -117,4 +117,31 @@
 });
 
+test('the OUTBOX serves the attachment too, not only the delivered Create', async () => {
+  // Root of the broken iPhone player (Robins schermafdrukken, 30-7): the
+  // outbox SELECT did not include c2s_attachments, so a note pulled via the
+  // outbox (backfill, boiert.eu) had NO Video attachment and readers fell
+  // back to the content tag with its relative, dead src. The delivered copy
+  // was fine, which is why one device worked and the other did not. This
+  // locks the outbox contract: the same narrow SELECT, through buildNote,
+  // must carry the attachment.
+  const r = await AP.ingestOutboxActivity(site, user, {
+    type: 'Create',
+    object: {
+      type: 'Note', content: '<p>buiten</p>',
+      to: ['https://test.example/ap/users/kid/followers'],
+      cc: ['https://www.w3.org/ns/activitystreams#Public'],
+      attachment: [{ type: 'Video', url: '/media/reply-media/buiten.mp4', mediaType: 'video/mp4' }],
+    },
+  });
+  const row = db.prepare(
+    `SELECT id, slug, title, content, cover_image_url, cover_video_url, nsfw, content_warning, c2s_attachments, published_at, created_at
+     FROM posts WHERE id = ?`).get(r.id);
+  const note = AP.buildNote('https://test.example', site, row);
+  const vid = (note.attachment || []).find((a) => a.url.endsWith('buiten.mp4'));
+  assert.ok(vid, 'the outbox-shaped row still yields the Video attachment');
+  assert.equal(vid.type, 'Video');
+  assert.ok(!/<video\b/i.test(note.content), 'and the content stays clean');
+});
+
 test('a media-only post is a post, not an empty-note error', async () => {
   const r = await AP.ingestOutboxActivity(site, user, {
