Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 3f32994e887da124cb2b8928840846ebefb11c87)
+++ src/services/ActivityPubService.js	(revision b1512e001281fec55506cf6cfa04d9d39784a5a2)
@@ -2849,5 +2849,5 @@
 // during a flux window, e.g. a fleet-wide update), and drops notes that are gone
 // (404/410). Bump SELFHEAL_VERSION only on a release that warrants a re-sync.
-const SELFHEAL_VERSION = 18; // v18: link previews no longer hang behind the note re-fetch (an unreachable origin skipped the whole row)
+const SELFHEAL_VERSION = 19; // v19: head-read no longer stops on an og:image mention inside inline script
 async function fetchNoteAP(url) {
   try {
Index: src/services/EmbedResolver.js
===================================================================
--- src/services/EmbedResolver.js	(revision 3f32994e887da124cb2b8928840846ebefb11c87)
+++ src/services/EmbedResolver.js	(revision b1512e001281fec55506cf6cfa04d9d39784a5a2)
@@ -231,5 +231,9 @@
       // the full string every read turns a 1MB page into quadratic work.
       const window = tail + chunk;
-      if (len >= MAX_HEAD || /<\/head>/i.test(window) || /og:image/i.test(window)) done_ = true;
+      // Stop on the real <meta property="og:image">, not on the bare string.
+      // Big sites carry "og:image" inside inline JSON long before the actual
+      // tag, and stopping there cut the page off just short of the meta block:
+      // the same near-miss as the old size cap, with a different cause.
+      if (len >= MAX_HEAD || /<\/head>/i.test(window) || /<meta[^>]{0,300}og:image/i.test(window)) done_ = true;
       tail = chunk.slice(-512);
     }
