Index: src/services/guardianship/handshake.js
===================================================================
--- src/services/guardianship/handshake.js	(revision 1a2d8ac96c0af0189037f8acd658b19b875be8b0)
+++ src/services/guardianship/handshake.js	(revision c26cc18be55079e31ab7f92b27f94d8de391003e)
@@ -56,7 +56,9 @@
     };
     relations.recordOffer(site.slug, 'guardian', rel.ward, { handle: deriveHandle(rel.ward), offerId });
-    const delivered = await deliverTo(site, rel.ward, offer).catch(() => false);
+    // The offer is now recorded (the guardian sees it as pending); delivery is
+    // async + retried, so a slow ward server never fails the whole action.
+    const res = await deliverTo(site, rel.ward, offer).catch(() => ({ delivered: false }));
     notify(site.slug, { kind: 'offer_sent', ward: rel.ward });
-    return { status: delivered ? 202 : 502, id: offerId, url: offerId };
+    return { status: 202, id: offerId, url: offerId, delivered: res && res.delivered !== false };
   }
 
@@ -82,7 +84,8 @@
     relations.removeRelation(site.slug, 'ward', row.other_uri);
   }
-  const delivered = await deliverTo(site, row.other_uri, answer).catch(() => false);
+  // The answer is committed locally; delivery is async + retried.
+  const res = await deliverTo(site, row.other_uri, answer).catch(() => ({ delivered: false }));
   notify(site.slug, { kind: type === 'Accept' ? 'offer_accepted' : 'offer_rejected', guardian: row.other_uri });
-  return { status: delivered ? 202 : 502, id: answer.id, url: answer.id };
+  return { status: 202, id: answer.id, url: answer.id, delivered: res && res.delivered !== false };
 }
 
