Index: src/routes/guardian.js
===================================================================
--- src/routes/guardian.js	(revision b5924ebf31cdcc5aa15b62679804833e70054824)
+++ src/routes/guardian.js	(revision fcd696455474523785c5743fbe27829c039720d0)
@@ -10,5 +10,4 @@
  */
 import express from 'express';
-import fs from 'fs';
 import path from 'path';
 import { fileURLToPath } from 'url';
@@ -20,15 +19,5 @@
 
 const router = express.Router();
-
-// Cache-bust the PWA assets: /assets is served with a 1-year cache, so without
-// a per-build version the browser keeps running an old guardian.js/css after a
-// deploy (that was exactly the "no feedback / not arriving" bug). The version
-// is the file's mtime at process start; a redeploy restarts us and bumps it.
 const __dir = path.dirname(fileURLToPath(import.meta.url));
-function assetVersion(rel) {
-  try { return Math.floor(fs.statSync(path.join(__dir, '..', 'assets', rel)).mtimeMs).toString(36); }
-  catch { return '0'; }
-}
-const ASSET_V = { js: assetVersion('js/guardian.js'), css: assetVersion('css/guardian.css') };
 
 /** The acting site: ?site=slug when owned, else the user's first site. */
@@ -78,5 +67,4 @@
     sites,
     lang: L,
-    assetV: ASSET_V,
     t: (k, v) => i18nT(L, k, v),
     cspNonce: res.locals.cspNonce,
@@ -125,4 +113,18 @@
   res.json({ ok: true, committed: !!r.committed, readyToCommit: !!r.readyToCommit });
 });
+
+// ── PWA assets served no-cache, so an update is never masked by the 1-year
+//    /assets cache or a stuck install (that was the whole "nothing works after
+//    a deploy" bug). Small files; the browser revalidates and gets a 304 when
+//    unchanged, the fresh file when changed.
+function pwaAsset(rel, type) {
+  return (req, res) => {
+    res.set('Cache-Control', 'no-cache');
+    res.type(type);
+    res.sendFile(path.join(__dir, '..', 'assets', rel));
+  };
+}
+router.get('/app.js', pwaAsset('js/guardian.js', 'application/javascript'));
+router.get('/app.css', pwaAsset('css/guardian.css', 'text/css'));
 
 // ── Manage: release a committed ward (local Undo; federation is Fase 4). ──
Index: src/routes/posts.js
===================================================================
--- src/routes/posts.js	(revision b5924ebf31cdcc5aa15b62679804833e70054824)
+++ src/routes/posts.js	(revision fcd696455474523785c5743fbe27829c039720d0)
@@ -939,7 +939,17 @@
     ? Guardianship.offersCollection(`${gMe}/queues/offers`, site.slug, gMe).orderedItems
     : []).filter((o) => o['shaer:ward'] === gMe && o['shaer:needsMyAccept']);
+  // FEP-633c §2: who guards this account (committed). Shown so a ward can always
+  // see its guardians, not just pending offers. Derive a display @handle when the
+  // stored one is missing or is the escalation (inbox) handle rather than a @handle.
+  const guardianHandle = (uri, cached) => {
+    if (cached && cached.charAt(0) === '@') return cached;
+    try { const u = new URL(uri); return `@${u.pathname.split('/').filter(Boolean).pop()}@${u.host}`; }
+    catch { return uri; }
+  };
+  const myGuardians = (site ? Guardianship.listGuardians(site.slug) : [])
+    .map((g) => ({ uri: g.other_uri, handle: guardianHandle(g.other_uri, g.other_handle) }));
   renderPage(req, res, 'pages/messages', {
     pageTitleKey: 'msg.title', bodyClass: 'on-special', items, seenAt,
-    hasMore, nextOffset: offset + FEED_PAGE, moreBase, guardianOffers,
+    hasMore, nextOffset: offset + FEED_PAGE, moreBase, guardianOffers, myGuardians,
     success: req.query.success || null, error: req.query.error || null,
   });
