Index: src/routes/activitypub.js
===================================================================
--- src/routes/activitypub.js	(revision 04d5aebb050cd1c96020a822d03370dbf5b13399)
+++ src/routes/activitypub.js	(revision fa33214eb34752fafee25fc95942f470701006f8)
@@ -254,4 +254,8 @@
 queueRoute('offers', (id, slug, me) => Guardianship.offersCollection(id, slug, me));
 queueRoute('follows', (id) => Guardianship.followsCollection(id));
+// §5.3 turned around (shaer-p729): what this ward has asked to follow, still
+// waiting on its guardians. Owner-only like the rest — who a child wants to
+// follow is nobody else's business.
+queueRoute('outgoing-follows', (id, slug, me) => Guardianship.outgoingFollowsCollection(id, slug, me));
 queueRoute('wards', (id, slug) => Guardianship.wardsCollection(id, slug));
 // Availability (FEP-633c 3.6.1) is never public: the ward reads its
@@ -696,5 +700,7 @@
   // 201 Created → Location header (AP spec); 202 Accepted for side-effect verbs.
   if (out.status === 201 && out.url) res.set('Location', out.url);
-  return res.status(out.status || 202).json({ ok: true, id: out.id, url: out.url });
+  // `state` carries a third outcome the app must be able to tell apart from a
+  // plain success: a ward's follow held for its guardians (§5.3, shaer-p729).
+  return res.status(out.status || 202).json({ ok: true, id: out.id, url: out.url, ...(out.state ? { state: out.state } : {}) });
 });
 
Index: src/routes/guardian.js
===================================================================
--- src/routes/guardian.js	(revision 04d5aebb050cd1c96020a822d03370dbf5b13399)
+++ src/routes/guardian.js	(revision fa33214eb34752fafee25fc95942f470701006f8)
@@ -278,4 +278,31 @@
 });
 
+// ── §5.3, the other direction (shaer-p729): the ward wants to follow SOMEONE,
+//    and the guardians decide. Same quorum arithmetic and the same availability
+//    rules as the inbound gate above; only the question is turned around, which
+//    is why it gets its own endpoint rather than a flag on that one.
+router.post('/api/outgoing-follow/:id', requireAuth, express.json({ limit: '4kb' }), async (req, res) => {
+  const site = siteForUser(req);
+  if (!site) return res.status(404).json({ error: 'no_site' });
+  const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
+  const me = AP.actorId(base, site.slug);
+  const decision = req.body?.decision === 'reject' ? 'reject' : 'approve';
+
+  const pending = Guardianship.outgoing.getPending(req.params.id);
+  if (!pending) return res.status(404).json({ error: 'gone' });
+  const allGuardians = Guardianship.listGuardians(pending.ward_slug).map((g) => g.other_uri);
+  if (!allGuardians.includes(me)) return res.status(403).json({ error: 'not_a_guardian' });
+  Guardianship.availability.oneAnswer(me, Date.now());
+  const guardians = Guardianship.availability.availableSet(pending.ward_slug, allGuardians, Date.now());
+  const r = Guardianship.outgoing.decide(pending.id, me, decision, guardians);
+  try {
+    // Only on approval does anything leave the building. A refusal is a local
+    // fact: the follow was never sent, so there is nothing out there to undo
+    // and nobody to inform that a child asked about them.
+    if (r.outcome === 'approved') await AP.performApprovedFollow(r.follow);
+  } catch { return res.status(502).json({ error: 'delivery', outcome: r.outcome }); }
+  res.json({ ok: true, outcome: r.outcome });
+});
+
 // ── Wave (FEP-633c §5, shaer:wave): a gentle "thinking of you" from a
 //    guardian to a ward. A private direct note, never a feed post. Warmth
