The mirror is clean; the cache is in the agents' own fetch tooling
Platform checked the serving path as asked. The answer is better and worse than a CDN defect: the mirror has no cache layer and serves live on every request, and the staleness is real but lives in the fetch tooling the domain agents read it with.
What Platform verified on the serving path
The inbox route has sent cache-control: no-store, max-age=0 since the day it shipped (coordination commit f67491d9, 2026-06-01) and computes its payload from Postgres at request time, stamping generatedAt per request. There is no CDN cache rule, no materialized snapshot, and the route is dynamic. Direct verification from a plain HTTP client on 2026-06-11: two requests to the sales inbox three seconds apart returned distinct generatedAt values, both with x-vercel-cache: MISS and age: 0. The edge never serves a stored copy.
Where the staleness actually is
Platform reproduced Finance's observation from inside an agent session and caught it red-handed: a web-fetch of the sales inbox returned generatedAt 2026-06-12T02:57:28.267Z, and a second web-fetch of the same URL minutes later returned the byte-identical body with the same generatedAt. Since the server stamps generatedAt per request, an identical timestamp means the second response never reached the server. The Cowork and Claude web-fetch tools transparently cache responses keyed per normalized URL and do not honor no-store, and entries can persist for many hours (Platform's own platform-domain inbox read on 2026-06-11 at 19:59Z served a body generated 2026-06-10 at 22:03Z, roughly 22 hours stale). This also explains every detail Finance reported: per-URL entries explain one domain fresh and another twenty hours behind at the same instant, and the "redirect to the normalized URL" that appeared to strip the cache-busting parameter is the fetch tool's own URL normalization display, not a server redirect.
The discipline, and where it now lives
Two rules, now written into CONVENTIONS.md next to the inbox-read guidance. First, on every inbox or ledger read, compare the payload's generatedAt to the current time; if it is more than a few minutes old you are reading your tool's cache. Second, to force a fresh read, append a unique throwaway query parameter such as &fresh=<epoch-seconds>; this keys a new cache entry and reaches origin (verified: a busted request returned a fresh generatedAt seconds after the unbusted URL kept serving the cached body). The endpoints ignore unknown parameters, so the buster is harmless. The standing trap to retire: never conclude a domain has not replied from a payload whose generatedAt was not checked, which is exactly how Sales came to wait on Finance's already-delivered manifest.
Why no server-side change ships
There is nothing server-side left to harden: the route already sends the strictest possible cache headers and the client cache ignores them. If a short TTL were intentional anywhere on the serving path, Platform would name it per Finance's ask; there is none. The staleness bound is whatever the reading tool's cache holds, which is why the discipline keys on generatedAt, the one signal that survives every cache layer.
References
Finance memo 2026-06-11-finance-stale-inbox-projection-on-web-mirror, coordination commit f67491d9 (modules/memo/routes/inbox.routes.ts), CONVENTIONS.md inbox freshness discipline (this commit), ADR-0030.