Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 971d00b75043758242745bd7dd7e24dd2fef68bf)
+++ src/services/ActivityPubService.js	(revision 189e335181d42f72a28a9744f64da578c83bbda7)
@@ -653,5 +653,5 @@
     for (const m of listOutbox(slug).slice(0, need)) {
       items.push({
-        type: 'sent', outboxId: m.id, to_handle: m.to_handle, to_actors: m.to_actors,
+        type: 'sent', outboxId: m.id, to_handle: m.to_handle, to_actor: m.to_actor, to_actors: m.to_actors,
         in_reply_to: m.in_reply_to, post_slug: m.post_slug, content: m.content,
         editable: m.editable, language: m.language, created_at: m.created_at,
@@ -785,4 +785,17 @@
     // onbeantwoord bericht leest.
     t.mine = t.messages.some((m) => m.type === 'sent');
+    // Waar gaat een antwoord uit deze draad heen? Twee paden, en ze sluiten
+    // elkaar uit: hangt de draad aan een post, dan antwoord je op het NIEUWSTE
+    // ontvangen bericht erin (dat is de parent van de thread) -- anders is het
+    // een direct bericht aan de tegenpartij.
+    const inkomend = t.messages.filter((m) => m.type !== 'sent');
+    const laatste = inkomend[inkomend.length - 1];
+    t.replyTo = {
+      interactionId: (laatste && laatste.interactionId) || null,
+      postSlug: (t.post && t.post.slug) || null,
+      actorUri: (laatste && (laatste.actorUri || laatste.url))
+        || (t.messages.find((m) => m.to_actor) || {}).to_actor
+        || (() => { try { return JSON.parse((t.messages.find((m) => m.to_actors) || {}).to_actors || '[]')[0] || null; } catch { return null; } })(),
+    };
   }
   return out;
@@ -4429,5 +4442,5 @@
   try {
     const rows = db.prepare(`
-      SELECT i.kind, i.actor_name, i.actor_handle, i.actor_url, i.actor_icon, i.content, i.created_at, i.published, i.visibility,
+      SELECT i.id AS interaction_id, i.kind, i.actor_uri, i.actor_name, i.actor_handle, i.actor_url, i.actor_icon, i.content, i.created_at, i.published, i.visibility,
              i.emoji_json, i.actor_emoji_json, i.media_json, i.quote_json, i.embed_json,
              p.slug AS post_slug, p.title AS post_title
@@ -4438,4 +4451,7 @@
     for (const r of rows) out.push({
       type: r.kind, name: r.actor_name, handle: r.actor_handle, url: r.actor_url, icon: r.actor_icon,
+      // Waar een antwoord uit de draad heen moet: het id is de parent voor
+      // deliverReply, de uri het adres voor een direct bericht.
+      interactionId: r.interaction_id, actorUri: r.actor_uri,
       content: stripLeadingMentions(r.content), post_slug: r.post_slug, post_title: r.post_title, created_at: r.created_at,
       // When the post was written, for display. created_at (when it reached us)
@@ -4671,4 +4687,8 @@
   getOutboxRow: (id) => iStmts().getO.get(id),
   buildReplyNote, AP_CONTEXT, getOrCreateKeys, deliver, enqueueDelivery,
+  // Rijke directe berichten: dezelfde sanitizer als deliverReply gebruikt, zodat
+  // een antwoord uit Berichten door precies één poort gaat.
+  sanitizeHtml: (h) => HtmlSanitizerService.sanitize(h),
+  htmlToPlainText: (h) => HtmlSanitizerService.toPlainText(h),
 });
 /**
