A browser signs every control-plane request with X-Unibus-Pub/Ts/Nonce/Sig
(busauth.signedHeaders). The CORS Allow-Headers only listed Content-Type and
Authorization, so the browser's preflight rejected the real request and the SPA
failed with 'Failed to fetch' on the first authenticated call (listRooms). Add the
four X-Unibus-* headers to Access-Control-Allow-Headers.
This was invisible to the Node smoke (fetch in Node does no CORS preflight); only a
real browser surfaced it. Verified live: enmanuel logs into uniweb against the
cluster and lists rooms. Regression test asserts the header is present.
Add Server.AllowedOrigins and an applyCORS step at the top of ServeHTTP so a
browser SPA (uniweb) can call the control plane cross-origin: an allow-listed
Origin gets the Access-Control-Allow-* headers, and a preflight (OPTIONS) is
answered 204 before the rate limiter and auth ever run. A disallowed or missing
origin gets no headers (preflight 403), so the browser blocks the request.
Wire it through membershipd's --cors-origins flag (comma list, reusing
splitRoutes as a generic parser). Empty allowlist = CORS off, no headers
emitted, behavior identical to before: native Go/Kotlin clients send no Origin
and are unaffected. Opt-in per deployment (issue uniweb/0001, Phase 0).
Tests: preflight allow/deny, header on the real response, CORS-off default, and
no-Origin native client unaffected.