Index: test/follow-gating.test.js
===================================================================
--- test/follow-gating.test.js	(revision 5c373b8e846c6510a176f2fa06bfe3e2b6753102)
+++ test/follow-gating.test.js	(revision 5c373b8e846c6510a176f2fa06bfe3e2b6753102)
@@ -0,0 +1,34 @@
+// FEP-633c §5.3: follow-gating store. A follow on a ward waits for guardians.
+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');
+dbMod.initializeDatabase();
+const G = await import('../src/services/guardianship/index.js');
+
+const A = (s) => `https://test.example/ap/users/${s}`;
+const [KID, MOM, DAD, STRANGER] = [A('kid'), A('mom'), A('dad'), A('stranger')];
+
+test('any-quorum: one guardian approval is enough', () => {
+  G.follows.recordPending('kid', { id: 'f1', follower: STRANGER, inbox: `${STRANGER}/inbox`, quorum: 'any' });
+  assert.equal(G.follows.listForWard('kid').length, 1);
+  const r = G.follows.decide('f1', MOM, 'approve', [MOM, DAD]);
+  assert.equal(r.outcome, 'approved');
+  G.follows.remove('f1');
+  assert.equal(G.follows.listForWard('kid').length, 0);
+});
+
+test('all-quorum: needs every guardian', () => {
+  G.follows.recordPending('kid', { id: 'f2', follower: STRANGER, inbox: `${STRANGER}/inbox`, quorum: 'all' });
+  assert.equal(G.follows.decide('f2', MOM, 'approve', [MOM, DAD]).outcome, 'waiting');
+  assert.equal(G.follows.decide('f2', DAD, 'approve', [MOM, DAD]).outcome, 'approved');
+});
+
+test('a single reject denies the follow (§3.2 spirit)', () => {
+  G.follows.recordPending('kid', { id: 'f3', follower: STRANGER, inbox: `${STRANGER}/inbox`, quorum: 'any' });
+  const r = G.follows.decide('f3', DAD, 'reject', [MOM, DAD]);
+  assert.equal(r.outcome, 'rejected');
+});
