Index: test/standard-shapes.test.js
===================================================================
--- test/standard-shapes.test.js	(revision 0db3c72bed823ab28b6f74eedfed3a1cf11faf98)
+++ test/standard-shapes.test.js	(revision aae5881d65b8532bd2291b2184bce662263e8752)
@@ -83,2 +83,54 @@
   assert.equal(AP.quoteObject('rommel'), undefined);
 });
+
+// ── En dan het weghalen (shaer-nmw, tweede helft) ────────────────────
+//
+// Bewijzen dat de standaardvorm ERBIJ staat is de helft; de andere helft is dat
+// het dialect er niet meer NAAST staat. Zonder deze wacht sluipt een
+// shaer:author zo weer een nieuwe leg in en spreken we stilletjes weer onze
+// eigen taal. Daarom door de echte route, want daar wordt de vorm beslist.
+test('de C2S-leg spreekt geen dialect meer waar de standaard het regelt', async (t) => {
+  const crypto = await import('crypto');
+  const express = (await import('express')).default;
+  const db = (await import('../src/config/database.js')).default;
+  const routes = (await import('../src/routes/activitypub.js')).default;
+
+  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', 'kind', 'kind', 'u1');
+  db.prepare(`INSERT INTO ap_timeline (id, slug, author_uri, author_name, author_handle, author_icon,
+              reblog_name, reblog_handle, content)
+              VALUES ('https://elders/n1', 'kind', 'https://elders/u/til', 'Tante Til', '@til@elders',
+                      'https://elders/til.png', 'Esmee', '@es@elders', '<p>hoi</p>')`).run();
+
+  const bearer = 'test-token-' + 'b'.repeat(24);
+  db.prepare('INSERT INTO oauth_tokens (token_hash, client_id, user_id, site_slug, scope) VALUES (?,?,?,?,?)')
+    .run(crypto.createHash('sha256').update(bearer).digest('base64url'), 'c', 'u1', 'kind', 'read write');
+
+  const app = express();
+  app.use(routes);
+  const server = app.listen(0);
+  t.after(() => server.close());
+  await new Promise((r) => server.once('listening', r));
+  const doc = await (await fetch(`http://127.0.0.1:${server.address().port}/ap/users/kind/inbox`,
+    { headers: { Authorization: `Bearer ${bearer}` } })).json();
+
+  const tekst = JSON.stringify(doc);
+  // Op de SLEUTEL, niet op een stuk tekst: 'shaer:quote' zit ook in
+  // shaer:quoteCards, en dat is een poortnaam die blijft. Een te grove zeef
+  // zou hier rood staan om iets dat klopt -- of erger, groen om iets dat niet
+  // klopt.
+  for (const weg of ['shaer:author', 'shaer:booster', 'shaer:quote', 'shaer:embed']) {
+    assert.ok(!tekst.includes(`"${weg}":`), `${weg} hoort weg te zijn`);
+  }
+  // Wat WEL mag blijven, en waarom: per-lezer-interactiestatus heeft in AS2
+  // geen tegenhanger (Mastodon lost het in zijn eigen REST-API op), en de
+  // FEP-633c-termen zijn bewust van ons en in standaardisatie.
+  assert.ok(tekst.includes('shaer:liked'), 'interactiestatus blijft, die heeft geen standaard');
+
+  const item = doc.orderedItems.find((i) => i.object.id === 'https://elders/n1');
+  assert.equal(item.type, 'Announce', 'een boost is de wrapper, niet een zijkanaal');
+  assert.equal(item.object.attributedTo.name, 'Tante Til', 'en de byline zit in attributedTo');
+  assert.equal(item.object.attributedTo.preferredUsername, 'til');
+});
