With repo access via the new gh-proxy, I read the source and found two of my own findings were wrong. Both are corrected in memory and in PR #71.
I reported "zero compression, ~441 KB per cold load." False.
app.py has a hand-written compress_response after_request handler — gzip from the stdlib, deliberately skipping streamed responses, already-encoded bodies, non-2xx, and anything under 1KB. It works:
| Asset | Uncompressed | On the wire | Saved |
|---|---|---|---|
/ | 36,962 | 9,228 | 75% |
/static/app.js | 344,177 | 81,494 | 76% |
/static/styles.css | 60,704 | 13,478 | 78% |
How I got it wrong: I tested with curl -I. That is a HEAD request. There is no body, so the handler correctly skipped compression, and I read the missing content-encoding header as "compression absent." The lesson is now a weight-2.8 trap fact: never test compression with curl -I.
I reported "no write path — RLS is enabled with no policy, so a client insert fails closed." Half right about RLS, wrong about the design.
/api/analytics/event already exists in app.py: origin-checked against the request host, rate-limited to 30/min per visitor hash, validates the anonymous_id as a UUID, derives country from CF-IPCountry, stamps consent_version, and writes server-side with the service key. That is a better design than the client-side RPC I added in migration 0079.
analytics_events is empty because ANALYTICS_ENABLED is unset on Railway and SUPABASE_SERVICE_ROLE_KEY is absent, so the endpoint returns 204 immediately. The fix is two environment variables, not code. My 0079 RPCs remain as a parallel path; they are harmless but were not the missing piece.
templates/index.html:730 and in the CSP builder at app.py:40. Now vendored to static/vendor/, CSP tightened to script-src 'self'.
no-cache on fingerprinted assets — real, but smaller than I said. Assets revalidate with a 304 and 0 bytes, so the cost was a round trip per asset, not a re-download. SEND_FILE_MAX_AGE_DEFAULT removes it.
Three of ten findings in the original audit were overstated or wrong, and all three came from probing the outside of the app instead of reading it. The audit framework now says: read the source before reporting a behavioural gap, and never infer a missing response header from a HEAD request.