Index: test/rich-reply.test.js
===================================================================
--- test/rich-reply.test.js	(revision feced2ce628d8bee7974f77404806f4be6f2272b)
+++ test/rich-reply.test.js	(revision 5190152c90d2d397b7f87f9c900eae8d8c1e2856)
@@ -120,2 +120,26 @@
   assert.equal(r, null);
 });
+
+test('rich edit: content replaced, language updated, attachments survive', async () => {
+  const r = await AP.deliverReply(site, {
+    postId: 'p1', postSlug: 'hallo', parent, text: 'origineel', html: '',
+    attachments: [{ url: '/media/reply-media/keep.webp', mediaType: 'image/webp', name: 'blijft' }],
+    language: 'nl',
+  });
+  const upd = await AP.deliverOutboxUpdate(site, r.id, '', { html: '<p>bewerkt met <em>nadruk</em></p>', language: 'en' });
+  assert.ok(upd && upd.ok);
+  const row = db.prepare('SELECT * FROM ap_outbox WHERE id = ?').get(r.id);
+  assert.match(row.content, /bewerkt met <em>nadruk<\/em>/);
+  assert.match(row.content, /^<p><a [^>]*class="u-url mention"/); // mention re-attached inline
+  assert.equal(row.language, 'en');
+  assert.equal(JSON.parse(row.attachments)[0].url, '/media/reply-media/keep.webp');
+});
+
+test('plain edit path unchanged; bogus language keeps the old one', async () => {
+  const r = await AP.deliverReply(site, { postId: 'p1', postSlug: 'hallo', parent, text: 'plain start', language: 'nl' });
+  const upd = await AP.deliverOutboxUpdate(site, r.id, 'plain bewerkt', { language: '???' });
+  assert.ok(upd && upd.ok);
+  const row = db.prepare('SELECT * FROM ap_outbox WHERE id = ?').get(r.id);
+  assert.match(row.content, /plain bewerkt/);
+  assert.equal(row.language, 'nl');
+});
