Skip to content

feat: add cost efficiency analytics - #93

Merged
jmlago merged 1 commit into
mainfrom
feat/analytics-cost-efficiency
Jul 31, 2026
Merged

feat: add cost efficiency analytics#93
jmlago merged 1 commit into
mainfrom
feat/analytics-cost-efficiency

Conversation

@jmlago

@jmlago jmlago commented Jul 31, 2026

Copy link
Copy Markdown
Member

Summary

  • default the dashboard to cached 30-day analytics; Latest 100 remains an explicit troubleshooting view
  • add blended $/Mtok, average $/request, and prompt cache hit rate
  • compare actual $/Mtok and cache efficiency by provider and model
  • show cost by policy/route and the actual destination model selected by routing
  • preserve consumer-key attribution as the workload/tag dimension
  • replace the vertical list of daily rows with a chronological side-by-side bar chart
  • carry cached-token counts through raw SQL aggregates and hourly rollups

Rollout

The rollup schema evolves in place with tokens_cached. A new rollup-state generation triggers the existing bounded backfill automatically (24 hours per five-minute CronJob run), so no manual database migration or full-table query is required.

Follow-up telemetry

Historical fallback rate, counterfactual savings, custom-policy fingerprint attribution, and rule-branch activation are not derivable from the current hourly facts. They require persisting bounded fields derived from decision_trace at ingestion time. This PR does not fabricate those values from the latest-100 memory buffer.

Tests

  • python -m pytest -q — 548 passed, 2 skipped

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Usage analytics now tracks cached tokens across storage and aggregation paths. The dashboard exposes cache-hit rate, blended cost, cost per request, route breakdowns, and activity efficiency details. Tests cover cached-token totals and dashboard markers.

Changes

Cached-token analytics

Layer / File(s) Summary
Persist cached-token analytics
host_store.py, tests/test_host_store.py
Hourly analytics storage and rollups now persist tokens_cached, use the hourly-v2-cache state, and calculate cache-related aggregate measures.
Propagate usage and derived metrics
auth_proxy.py, tests/test_dashboard_stats_sql.py
Usage counters, SQL totals, and reference aggregation now include cached tokens and derive cache-hit rate, cost per million tokens, and cost per request.
Render analytics dashboard metrics
auth_proxy.py, tests/test_auth_proxy_dashboard_full.py
The dashboard now displays cost, cache-hit, route, status, and bar-chart activity details.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CallsLedger
  participant HostStore
  participant AuthProxy
  participant Dashboard
  CallsLedger->>HostStore: aggregate and roll up tokens_cached
  HostStore->>AuthProxy: provide cached-token and cost totals
  AuthProxy->>Dashboard: render analytics cards and activity details
Loading

Possibly related PRs

Suggested reviewers: muncleuscles, acastellana

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add cost efficiency analytics' accurately describes the main change—introducing cost efficiency metrics to the dashboard. It is specific and directly related to the primary objective of the changeset.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/analytics-cost-efficiency

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jmlago
jmlago force-pushed the feat/analytics-cost-efficiency branch from 93319bf to f4ed04e Compare July 31, 2026 13:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/test_host_store.py (1)

59-78: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for cost_per_mtok.

The fixture validates tokens_cached, cache_hit_rate, and cost_per_request, but it does not validate the blended cost-per-million metric. For caller a, the expected value is 66666.6667 ($3 / 45 * 1_000_000).

Proposed test addition
     assert agg["totals"]["tokens_cached"] == 15
     assert agg["totals"]["cache_hit_rate"] == 0.5
     assert agg["totals"]["cost_per_request"] == 1.5
+    assert agg["totals"]["cost_per_mtok"] == 66666.6667
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_host_store.py` around lines 59 - 78, Extend the existing caller
“a” assertions in the analytics aggregation test to validate
agg["totals"]["cost_per_mtok"] equals approximately 66666.6667, using the test’s
appropriate floating-point comparison for the computed blended metric.
tests/test_auth_proxy_dashboard_full.py (1)

1164-1168: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test chart behavior, not only HTML markers.

These assertions verify IDs and one CSS token. They do not fail when renderSeries receives incorrectly ordered data or renders bars without the expected cost and cache details. Add a focused assertion for the generated series, or a targeted source assertion if browser execution is unavailable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_auth_proxy_dashboard_full.py` around lines 1164 - 1168, Strengthen
the dashboard test around the chart rendering verified by the existing
HTML-marker assertions: inspect the generated series passed to renderSeries and
assert that its data preserves the expected ordering and includes the required
cost and cache details. If browser execution is unavailable, add a targeted
assertion against the chart source that validates this series construction
rather than only checking element IDs and CSS.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@host_store.py`:
- Line 1082: Update the analytics rollup state handling around
_ANALYTICS_STATE_NAME, rollup_analytics(), analytics_rollup_state(), and
analytics_aggregate() to add a bounded, one-shot migration from existing
"hourly" rows into "hourly-v2-cache". Ensure the migration preserves/backfills
coverage, then mark or remove the legacy state with a safe guard so subsequent
reads cannot repeatedly reconstruct it or loop indefinitely.

---

Nitpick comments:
In `@tests/test_auth_proxy_dashboard_full.py`:
- Around line 1164-1168: Strengthen the dashboard test around the chart
rendering verified by the existing HTML-marker assertions: inspect the generated
series passed to renderSeries and assert that its data preserves the expected
ordering and includes the required cost and cache details. If browser execution
is unavailable, add a targeted assertion against the chart source that validates
this series construction rather than only checking element IDs and CSS.

In `@tests/test_host_store.py`:
- Around line 59-78: Extend the existing caller “a” assertions in the analytics
aggregation test to validate agg["totals"]["cost_per_mtok"] equals approximately
66666.6667, using the test’s appropriate floating-point comparison for the
computed blended metric.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8bccf7db-695e-4e73-a9d5-5d4140d63534

📥 Commits

Reviewing files that changed from the base of the PR and between 2785335 and 93319bf.

📒 Files selected for processing (5)
  • auth_proxy.py
  • host_store.py
  • tests/test_auth_proxy_dashboard_full.py
  • tests/test_dashboard_stats_sql.py
  • tests/test_host_store.py

Comment thread host_store.py


_ANALYTICS_LOCK_KEY = 0x616E616C_79746963
_ANALYTICS_STATE_NAME = "hourly-v2-cache"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 --glob '*.py' \
  "hourly-v2-cache|[\"']hourly[\"']|_ANALYTICS_STATE_NAME|analytics_rollup_state|rollup_analytics|covered_(from|until)"

Repository: genlayerlabs/unhardcoded

Length of output: 162


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Tracked files named host_store.py:\n'
git ls-files | rg '(^|/)host_store\.py$' || true

printf '\nSearch relevant identifiers and state names:\n'
rg -n -C 5 "hourly-v2-cache|['\"]hourly['\"]|_ANALYTICS_STATE_NAME|analytics_rollup_state|rollup_analytics|covered_(from|until)" . --glob '*.py' || true

printf '\nFile list around host_store if present:\n'
fd -a 'host_store\.py$' . || true

Repository: genlayerlabs/unhardcoded

Length of output: 9406


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'host_store.py relevant rollup/aggregate sections:\n'
sed -n '1080,1205p' host_store.py | cat -n

printf '\nscripts/rollup_analytics.py full:\n'
sed -n '1,70p' scripts/rollup_analytics.py | cat -n

printf '\nTest setup around analytics rollup:\n'
sed -n '1,90p' tests/test_host_store.py | cat -n

printf '\nDiff/stat if available:\n'
git diff --stat HEAD~1..HEAD || true
git diff --unified=80 HEAD~1..HEAD -- host_store.py scripts/rollup_analytics.py tests/test_host_store.py || true

Repository: genlayerlabs/unhardcoded

Length of output: 50380


Add the migration and backfill guard for the rollup state name.

rollup_analytics() now writes "hourly-v2-cache", and analytics_rollup_state() / analytics_aggregate() now read that name. Existing databases will have "hourly" rows, so coverage from those rolls out of the view and becomes unavailable. Add a bounded one-shot migration that copies/populates coverage from "hourly" to "hourly-v2-cache" and delete or ignore the old state with a safe trigger to avoid infinite reconstruction.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@host_store.py` at line 1082, Update the analytics rollup state handling
around _ANALYTICS_STATE_NAME, rollup_analytics(), analytics_rollup_state(), and
analytics_aggregate() to add a bounded, one-shot migration from existing
"hourly" rows into "hourly-v2-cache". Ensure the migration preserves/backfills
coverage, then mark or remove the legacy state with a safe guard so subsequent
reads cannot repeatedly reconstruct it or loop indefinitely.

@jmlago
jmlago merged commit 4827e07 into main Jul 31, 2026
1 check passed
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