0.4.1
A small operational release: the two public federation documents become cacheable, and the README picks up the object-cache recommendation that node operators should act on.
/.well-known/openyacht and /openyacht/v1/capabilities now send Cache-Control: public — five minutes for the discovery document, an hour for capabilities. Both are unsigned and byte-identical for every caller, so there was never a reason to serve them with no-store.
The discovery document deliberately gets minutes rather than the 24 hours the protocol recommends consumers hold it for. That 24 hours is an application-layer cache the consumer controls and can bypass on a signature failure to pick up rotated keys; a CDN or proxy honouring our max-age is one they cannot. Key-rotation recovery is worth far more than the handful of origin hits saved on an endpoint that only sees partner adds and throttled refetches. Capabilities gets the longer hour: it carries no keys, and a consumer that briefly misses a feature flag degrades gracefully by design.
Everything else stays uncacheable, on purpose. /openyacht/v1/listings is filtered per partner — a shared cache entry would hand one partner another partner's view — and health checks and error responses must stay fresh. If you run a CDN or page cache in front of this site, leave the federation paths uncached.
A persistent object cache is now a documented recommendation. Every verified inbound request bumps that partner's rate-limit counter, and without Redis or Memcached that counter is two wp_options writes per request, on top of the audit row the request already logs. The cost scales directly with how hard your partners poll, and no page cache can absorb it, because the surface it protects is per-partner. Nothing breaks without one — this is a scaling recommendation, not a conformance requirement — but it is the first thing worth fixing on a busy node. See "Use a persistent object cache" in the README.
No database changes and no configuration changes: upgrading is a straight plugin update.