Skip to content

fix(api): semantic-cache HIT bills incremental cost 0 + X-OmniRoute-Cost-Saved (PRD-2026-06-19) - #4308

Merged
diegosouzapw merged 1 commit into
release/v3.8.30from
fix/cache-hit-cost-reporting
Jun 19, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.30from
fix/cache-hit-cost-reporting

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Implements PRD-2026-06-19-cache-hit-cost-reporting (Option A).

Problem

On a semantic-cache HIT the gateway serves the stored response without an upstream call (incremental cost ≈ $0), but X-OmniRoute-Response-Cost reported the original call's full cost (recomputed from the cached usage). A consumer summing response-cost for billing was charging for hits that cost ≈$0 to serve (and stale entries inflated it).

Fix (Option A — separate incremental vs. saved cost)

  • HIT now bills X-OmniRoute-Response-Cost: 0.0000000000 (real incremental cost).
  • New header X-OmniRoute-Cost-Saved = the original/would-have-been cost (mirrors the existing tokens_saved concept) for cache analytics. Emitted only on cache hits.
  • MISS path unchanged.

Changes

  • src/shared/constants/headers.ts — add costSaved → X-OmniRoute-Cost-Saved.
  • src/domain/omnirouteResponseMeta.ts — builder/attachOmniRouteMetaHeaders emit Cost-Saved only when costSavedUsd is passed (additive; non-cache responses unchanged).
  • open-sse/handlers/chatCore/semanticCache.ts — HIT passes costUsd: 0 + costSavedUsd: cachedCost.
  • Docs: API_REFERENCE.md + openapi.yaml document the header + cache-hit cost semantics.

Tests (Hard Rule #18 — TDD, RED→GREEN)

  • tests/unit/omniroute-response-meta.test.ts — builder emits Cost-Saved when costSavedUsd provided, omits otherwise; HIT Response-Cost = 0.
  • tests/unit/chatcore-semantic-cache.test.ts — checkSemanticCache HIT ⇒ Response-Cost: 0.0000000000 + Cost-Saved = original cost (computed via the same calculateCost, gpt-4o, deterministic). RED on the unfixed code.
  • Plus a per-key isolation guard (#3740 edge from the PRD): key A's cached entry is not visible to key B.

Acceptance criteria

  1. ✅ repeated temperature:0 prompt → 1st (MISS) real cost; 2nd (HIT) Response-Cost: 0 + Cost-Saved = original.
  2. ✅ billing sums no longer count HITs.
  3. ✅ Cost-Saved available for cache analytics.
  4. ✅ MISS path + existing chatCore/cost suites unchanged (typecheck + lint + file-size + docs-sync green; focused cache/cost/telemetry sweep 41/41).

Closes the PRD (no GitHub issue).

…ost-Saved (PRD-2026-06-19)

On a semantic-cache HIT no upstream call is made, so the incremental cost of
serving the hit is 0. X-OmniRoute-Response-Cost was reporting the original
call's full cost (recomputed from the cached usage), making billing consumers
that sum response-cost charge for hits that cost ~$0 to serve.

Cache hits now emit X-OmniRoute-Response-Cost: 0.0000000000 and surface the
avoided cost in a new X-OmniRoute-Cost-Saved header (mirrors the existing
tokens_saved concept) for cache analytics. The MISS path is unchanged.

- headers.ts: add costSaved constant
- omnirouteResponseMeta.ts: builder/attach emit Cost-Saved when costSavedUsd passed
- semanticCache.ts: HIT passes costUsd:0 + costSavedUsd:cachedCost
- TDD: builder + checkSemanticCache regression (RED->GREEN) + per-key isolation guard
- docs: API_REFERENCE + openapi document the header and cache-hit semantics
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@diegosouzapw
diegosouzapw merged commit a23d0d6 into release/v3.8.30 Jun 19, 2026
4 checks passed
@diegosouzapw
diegosouzapw deleted the fix/cache-hit-cost-reporting branch June 19, 2026 21:53
diegosouzapw added a commit that referenced this pull request Jun 20, 2026
…s in pre-commit (#4318)

* fix(quality): complexity gate varre bin/ + electron (6A.11, fake-green fix)

ESLINT_ARGS passava só 'src open-sse', mas o config eslint.complexity.config.mjs
e o complexity-baseline.json já documentavam o escopo src+open-sse+electron+bin.
A edição do scan nunca tinha sido aplicada: o gate alegava cobrir bin/electron e
nunca os varria (fake-green — uma god-function nova em bin/ passava verde).

- exporta ESLINT_ARGS + adiciona 'electron' e 'bin' (casa o config)
- teste de build trava o escopo do scan
- baseline 1887->1888: electron+bin medem 0 (widening 0-custo); o +1 é drift
  pré-existente de src/open-sse da base a23d0d6 (#4308 et al.), não do widening

* fix(quality): check:tracked-artifacts no pre-commit (6A.12)

O gate estava no CI + pre-push, mas faltava no pre-commit — e o incidente do
symlink (artefato de build trackeado) acontece no 'git add'. Fecha o buraco no
ponto mais cedo.
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…ost-Saved (PRD-2026-06-19) (cheaper-inference#4308)

Cache HITs now report Response-Cost 0 (incremental) and surface the avoided cost in X-OmniRoute-Cost-Saved. MISS path unchanged. TDD + per-key isolation guard.
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…s in pre-commit (cheaper-inference#4318)

* fix(quality): complexity gate varre bin/ + electron (6A.11, fake-green fix)

ESLINT_ARGS passava só 'src open-sse', mas o config eslint.complexity.config.mjs
e o complexity-baseline.json já documentavam o escopo src+open-sse+electron+bin.
A edição do scan nunca tinha sido aplicada: o gate alegava cobrir bin/electron e
nunca os varria (fake-green — uma god-function nova em bin/ passava verde).

- exporta ESLINT_ARGS + adiciona 'electron' e 'bin' (casa o config)
- teste de build trava o escopo do scan
- baseline 1887->1888: electron+bin medem 0 (widening 0-custo); o +1 é drift
  pré-existente de src/open-sse da base ecbbff1 (cheaper-inference#4308 et al.), não do widening

* fix(quality): check:tracked-artifacts no pre-commit (6A.12)

O gate estava no CI + pre-push, mas faltava no pre-commit — e o incidente do
symlink (artefato de build trackeado) acontece no 'git add'. Fecha o buraco no
ponto mais cedo.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant