Commit graph

2 commits

Author SHA1 Message Date
chopratejas
e4e28b65f4 fix(proxy): surface CompressionDecision.passthrough_reason in tags
Adds ``CompressionDecision.apply_to_tags(tags)`` — a one-liner mutator
that stamps the passthrough reason into a tags dict for downstream
observability. Each migrated handler now calls
``_decision.apply_to_tags(tags)`` immediately after
``CompressionDecision.decide(...)``. The tags dict flows unchanged
into every downstream ``RequestOutcome(tags=tags, ...)`` construction,
which the funnel surfaces in ``RequestLog.tags`` — same mechanism the
funnel already uses for ``client``.

Dashboards can now slice passthrough traffic by cause:

  * tags["passthrough_reason"] == "bypass_header"
  * tags["passthrough_reason"] == "compression_disabled"
  * tags["passthrough_reason"] == "no_messages"
  * tags["passthrough_reason"] == "license_denied"

No-op when ``should_compress=True`` — compressing requests don't
carry the tag, so absence vs presence is itself the signal.

Bonus fix: ``handle_gemini_count_tokens`` was the one Gemini handler
that never pulled tags out of headers, so its emitted
``RequestOutcome`` reached the dashboard without any of the per-
request slicing keys. Added the missing ``tags = self._extract_tags
(request.headers)`` and threaded ``tags=tags`` into its outcome.

Closes the observability loop opened by PR #477: the four Gemini-
bypass-bug fixes are now visible in the request-log feed the moment
they fire.
2026-05-15 14:40:00 -07:00
chopratejas
2935cd9c89 refactor(proxy): introduce CompressionDecision; fix 4 missing-gate bugs
Pre-this-PR, four handler files computed "should this request be
compressed?" inline at five sites with subtle drift. Three Gemini
sites silently ignored ``x-headroom-bypass: true``; one of those
also ignored the license gate. Anthropic and OpenAI got the full
conjunction right, but encoded it inline.

``CompressionDecision.decide(headers, config, usage_reporter,
messages)`` is the single canonical factory. Precedence:

  1. ``bypass_header``       — user's explicit opt-out (highest)
  2. ``compression_disabled`` — operator config.optimize=False
  3. ``no_messages``         — nothing to compress
  4. ``license_denied``      — commercial gate

The factory exposes every constituent boolean
(``bypass_header_set``, ``config_optimize_enabled``,
``license_allows``, ``has_messages``) so debug tooling can answer
"what did the decision see?" without re-running it.

Each migrated site now logs ``Compression skipped: reason=<X>`` on
passthrough — new structured observability.

Bug fixes that came with the consolidation:

* ``handlers/gemini.py:handle_gemini_generate_content`` — now
  respects ``x-headroom-bypass``
* ``handlers/gemini.py:handle_google_cloudcode_stream`` — now
  respects ``x-headroom-bypass``
* ``handlers/gemini.py:handle_gemini_count_tokens`` — now respects
  ``x-headroom-bypass`` AND the license gate (was missing both)
2026-05-15 10:16:23 -07:00