Index: src/config/database.js
===================================================================
--- src/config/database.js	(revision 8f520e0a3f2cbb78f2fda599e80a671c5579edc9)
+++ src/config/database.js	(revision af5b79bce6ea434335758683cb102f0e695757ce)
@@ -563,4 +563,8 @@
   ensureColumn('ap_outbox', 'wave', 'INTEGER');    // FEP-633c shaer:wave (guardian -> ward nudge)
   ensureColumn('ap_mentions', 'wave', 'INTEGER');  // inbound guardian wave
+  // FEP-633c §2.2: object hint that the author is a ward. Register-only for now;
+  // used later at reddings-boei / escalation routing.
+  ensureColumn('ap_timeline', 'has_guardians', 'INTEGER');
+  ensureColumn('ap_mentions', 'has_guardians', 'INTEGER');
   ensureColumn('ap_followers', 'name', 'TEXT');    // cached display name (shaer-aa3)
   ensureColumn('ap_followers', 'handle', 'TEXT');  // @user@host
Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 8f520e0a3f2cbb78f2fda599e80a671c5579edc9)
+++ src/services/ActivityPubService.js	(revision af5b79bce6ea434335758683cb102f0e695757ce)
@@ -278,4 +278,6 @@
       ...Guardianship.helpRequestProps(post),
       ...Guardianship.waveProps(post),
+      // FEP-633c §2.2: object hint that the author is a ward.
+      ...Guardianship.hasGuardiansProps(site.slug),
       tag: [
         ...mentionTags(post.content),
@@ -312,4 +314,5 @@
       tag: [...hashtagTags(base, post.content)],
       replies: `${id}/replies`,
+      ...Guardianship.hasGuardiansProps(site.slug),
     };
   }
@@ -488,4 +491,6 @@
     sensitive: !!post.nsfw,
   };
+  // FEP-633c §2.2: object hint that the author is a ward (safely ignorable).
+  Object.assign(note, Guardianship.hasGuardiansProps(site.slug));
   if (post.nsfw) note.summary = post.content_warning || 'Gevoelige inhoud';
   if (attachment.length) note.attachment = attachment;
@@ -1504,4 +1509,6 @@
         for (const s of subs) {
           tlStmts().ins.run(o.id, s.slug, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.url || null, o.published || null, media, o.sensitive ? 1 : 0, o.summary || null);
+          // FEP-633c §2.2: register the ward hint on the stored object (no action yet).
+          if (Guardianship.objectHasGuardians(o)) { try { db.prepare('UPDATE ap_timeline SET has_guardians = 1 WHERE id = ? AND slug = ?').run(o.id, s.slug); } catch { /* ignore */ } }
           if (poll) { try { db.prepare('UPDATE ap_timeline SET poll_json = ? WHERE id = ? AND slug = ?').run(JSON.stringify(poll), o.id, s.slug); } catch { /* ignore */ } }
         }
@@ -1522,8 +1529,9 @@
         const help = Guardianship.isHelpRequest(o);
         const wave = Guardianship.isWave(o);
+        const hasG = Guardianship.objectHasGuardians(o);   // §2.2 hint, register-only
         for (const slug of slugs) {
           try {
-            const r = db.prepare('INSERT OR IGNORE INTO ap_mentions (slug, object_uri, note_url, actor_uri, actor_name, actor_handle, actor_icon, actor_url, content, published, help_request, wave, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)')
-              .run(slug, o.id, safeUrl(o.url) || null, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.published || null, help ? 1 : 0, wave ? 1 : 0);
+            const r = db.prepare('INSERT OR IGNORE INTO ap_mentions (slug, object_uri, note_url, actor_uri, actor_name, actor_handle, actor_icon, actor_url, content, published, help_request, wave, has_guardians, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)')
+              .run(slug, o.id, safeUrl(o.url) || null, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.published || null, help ? 1 : 0, wave ? 1 : 0, hasG ? 1 : 0);
             if (r.changes) {
               console.log('[AP] mention', actorUri, '→', slug, help ? '(help request)' : '');
Index: src/services/guardianship/index.js
===================================================================
--- src/services/guardianship/index.js	(revision 8f520e0a3f2cbb78f2fda599e80a671c5579edc9)
+++ src/services/guardianship/index.js	(revision af5b79bce6ea434335758683cb102f0e695757ce)
@@ -16,5 +16,5 @@
  */
 export { SHAER_CONTEXT, GUARDIAN_RELATIONSHIP, GUARDIAN_RELATIONSHIP_COMPACT, isGuardianRelationship } from './context.js';
-export { helpRequestProps, isHelpRequest, waveProps, isWave } from './notes.js';
+export { helpRequestProps, isHelpRequest, waveProps, isWave, hasGuardiansProps, objectHasGuardians } from './notes.js';
 export { wireDelivery, c2sVisibility, deliverDirectNote } from './delivery.js';
 export { wireHandshake, handleOutbox as handleGuardianshipOutbox, handleInbox as handleGuardianshipInbox, parseRelationship } from './handshake.js';
Index: src/services/guardianship/notes.js
===================================================================
--- src/services/guardianship/notes.js	(revision 8f520e0a3f2cbb78f2fda599e80a671c5579edc9)
+++ src/services/guardianship/notes.js	(revision af5b79bce6ea434335758683cb102f0e695757ce)
@@ -5,4 +5,21 @@
  * on direct notes. Everyone who does not speak shaer can ignore it.
  */
+import { listGuardians } from './relations.js';
+
+/**
+ * shaer:hasGuardians (§2.2): an advisory OBJECT hint that the author is a ward,
+ * so a remote server can route interactions to the guardians WITHOUT fetching
+ * the actor. Stamped on every object a ward publishes; MUST be safely ignorable.
+ */
+export function hasGuardiansProps(slug) {
+  try { return (slug && listGuardians(slug).length) ? { 'shaer:hasGuardians': true } : {}; }
+  catch { return {}; }
+}
+
+/** True when an incoming object carries the ward hint (§2.2). Register-only for
+ *  now; acted on later at reddings-boei / escalation routing. */
+export function objectHasGuardians(o) {
+  return !!o && (o['shaer:hasGuardians'] === true || o.hasGuardians === true);
+}
 
 /** Extra JSON-LD properties for an outgoing note built from an ap_outbox row. */
@@ -31,3 +48,3 @@
 }
 
-export default { helpRequestProps, isHelpRequest, waveProps, isWave };
+export default { helpRequestProps, isHelpRequest, waveProps, isWave, hasGuardiansProps, objectHasGuardians };
Index: test/has-guardians.test.js
===================================================================
--- test/has-guardians.test.js	(revision af5b79bce6ea434335758683cb102f0e695757ce)
+++ test/has-guardians.test.js	(revision af5b79bce6ea434335758683cb102f0e695757ce)
@@ -0,0 +1,26 @@
+// FEP-633c §2.2: shaer:hasGuardians object hint (outbound stamp + register).
+import { test } from 'node:test';
+import assert from 'node:assert/strict';
+
+process.env.DATABASE_PATH = ':memory:';
+process.env.PUBLIC_BASE_URL = 'https://test.example';
+
+const dbMod = await import('../src/config/database.js');
+const db = dbMod.default;
+dbMod.initializeDatabase();
+const G = await import('../src/services/guardianship/index.js');
+
+db.prepare('INSERT INTO users (id, username, email, password_hash, role) VALUES (?,?,?,?,?)').run('u1','u1','u1@t','x','god');
+db.prepare('INSERT INTO sites (id, slug, title, owner_id, is_primary) VALUES (?,?,?,?,1)').run('s1','kid','kid','u1');
+db.prepare('INSERT INTO sites (id, slug, title, owner_id, is_primary) VALUES (?,?,?,?,0)').run('s2','free','free','u1');
+db.prepare("INSERT INTO ap_guardianships (slug, role, other_uri, status, created_at) VALUES ('kid','ward','https://m.example/mom','accepted',CURRENT_TIMESTAMP)").run();
+
+test('a ward stamps the hint; a free actor does not', () => {
+  assert.deepEqual(G.hasGuardiansProps('kid'), { 'shaer:hasGuardians': true });
+  assert.deepEqual(G.hasGuardiansProps('free'), {});
+});
+
+test('objectHasGuardians reads the hint, register-only', () => {
+  assert.equal(G.objectHasGuardians({ 'shaer:hasGuardians': true }), true);
+  assert.equal(G.objectHasGuardians({}), false);
+});
