Index: src/routes/activitypub.js
===================================================================
--- src/routes/activitypub.js	(revision 1d76e0e533a2fe46c00fba8193b72c7be6685346)
+++ src/routes/activitypub.js	(revision 060d4a512c8521a8df44895c3c233dee3ed00795)
@@ -321,5 +321,8 @@
     const base = baseUrl(req);
     const me = `${base}/ap/users/${auth.site.slug}`;
-    AP.sendAP(res, { '@context': AP.AP_CONTEXT, ...build(`${me}/queues/${name}`, auth.site.slug, me) });
+    // 304 als er niets veranderde (Barts punt, 9-8). Zonder dit haalde een app
+    // bij elke actie de hele lijst opnieuw op -- een hulpvraag afvinken vroeg de
+    // honderd wards inclusief poorten terug.
+    AP.sendMaybe304(req, res, { '@context': AP.AP_CONTEXT, ...build(`${me}/queues/${name}`, auth.site.slug, me) });
   });
 }
Index: src/routes/guardian.js
===================================================================
--- src/routes/guardian.js	(revision 1d76e0e533a2fe46c00fba8193b72c7be6685346)
+++ src/routes/guardian.js	(revision 060d4a512c8521a8df44895c3c233dee3ed00795)
@@ -185,5 +185,7 @@
   const site = siteForUser(req);
   if (!site) return res.status(404).json({ error: 'no_site' });
-  res.json(dashboardState(site, resolveLang(req)));
+  // Het paneel tikt elke 45 seconden, of er nu iets gebeurd is of niet. Met een
+  // ETag kost stilte een lege 304 in plaats van het hele paneel (Barts punt, 9-8).
+  return AP.sendMaybe304(req, res, dashboardState(site, resolveLang(req)), { contentType: 'application/json' });
 });
 
