fix(platform-cost): apply all dashboard filters to raw SQL percentile/bucket queries

Raw SQL queries for percentile and histogram bucket distributions were only
filtering by createdAt >= start, ignoring end, provider, user_id, model, and
block_name. This caused percentile/bucket stats to silently include data
outside the selected filter scope.

Also: add P75 summary card to frontend, fix skeleton count (8->12) to match
rendered card count, fix "Avg Cost / Request" subtitle to accurately say
"cost-bearing requests", and add test assertion that raw queries receive active
filter params.
This commit is contained in:
majdyz
2026-04-13 01:23:26 +00:00
parent df989853c1
commit 0be1d7ddbc
3 changed files with 59 additions and 12 deletions

View File

@@ -275,6 +275,42 @@ async def get_platform_cost_dashboard(
"trackingAmount": True,
}
# Build parameterised WHERE clause for the raw SQL percentile/bucket
# queries so they honour all active dashboard filters, not just start date.
raw_params: list = [start]
raw_where_clauses = [
'"trackingType" = \'cost_usd\'',
'"createdAt" >= $1',
]
param_idx = 2 # $1 is already start
if end is not None:
raw_where_clauses.append(f'"createdAt" <= ${param_idx}')
raw_params.append(end)
param_idx += 1
if provider is not None:
raw_where_clauses.append(f'"provider" = ${param_idx}')
raw_params.append(provider.lower())
param_idx += 1
if user_id is not None:
raw_where_clauses.append(f'"userId" = ${param_idx}')
raw_params.append(user_id)
param_idx += 1
if model is not None:
raw_where_clauses.append(f'"model" = ${param_idx}')
raw_params.append(model)
param_idx += 1
if block_name is not None:
raw_where_clauses.append(f'LOWER("blockName") = LOWER(${param_idx})')
raw_params.append(block_name)
param_idx += 1
raw_where = " AND ".join(raw_where_clauses)
# Run all six aggregation queries in parallel.
(
by_provider_groups,
@@ -317,7 +353,7 @@ async def get_platform_cost_dashboard(
},
count=True,
),
# Percentile distribution of cost per request.
# Percentile distribution of cost per request (respects all filters).
query_raw_with_schema(
"SELECT"
" percentile_cont(0.5) WITHIN GROUP"
@@ -329,11 +365,10 @@ async def get_platform_cost_dashboard(
" percentile_cont(0.99) WITHIN GROUP"
' (ORDER BY "costMicrodollars") as p99'
' FROM {schema_prefix}"PlatformCostLog"'
" WHERE \"trackingType\" = 'cost_usd'"
' AND "createdAt" >= $1',
start,
f" WHERE {raw_where}",
*raw_params,
),
# Histogram buckets for cost distribution.
# Histogram buckets for cost distribution (respects all filters).
query_raw_with_schema(
"SELECT"
" CASE"
@@ -351,11 +386,10 @@ async def get_platform_cost_dashboard(
" END as bucket,"
" COUNT(*) as count"
' FROM {schema_prefix}"PlatformCostLog"'
" WHERE \"trackingType\" = 'cost_usd'"
' AND "createdAt" >= $1'
f" WHERE {raw_where}"
" GROUP BY bucket"
' ORDER BY MIN("costMicrodollars")',
start,
*raw_params,
),
)

View File

@@ -416,6 +416,7 @@ class TestGetPlatformCostDashboard:
mock_actions.group_by = AsyncMock(side_effect=[[], [], [], []])
mock_actions.find_many = AsyncMock(return_value=[])
raw_mock = AsyncMock(side_effect=[[], []])
with (
patch(
"backend.data.platform_cost.PrismaLog.prisma",
@@ -427,8 +428,7 @@ class TestGetPlatformCostDashboard:
),
patch(
"backend.data.platform_cost.query_raw_with_schema",
new_callable=AsyncMock,
side_effect=[[], []],
raw_mock,
),
):
await get_platform_cost_dashboard(
@@ -440,6 +440,12 @@ class TestGetPlatformCostDashboard:
# The where dict passed to the first call should include createdAt
first_call_kwargs = mock_actions.group_by.call_args_list[0][1]
assert "createdAt" in first_call_kwargs.get("where", {})
# Raw SQL queries should receive provider and user_id as parameters
assert raw_mock.await_count == 2
raw_call_args = raw_mock.call_args_list[0][0] # positional args of 1st call
raw_params = raw_call_args[1:] # first arg is the query template
assert "openai" in raw_params
assert "u1" in raw_params
def _make_prisma_log_row(

View File

@@ -205,7 +205,7 @@ export function PlatformCostContent({ searchParams }: Props) {
{loading ? (
<div className="flex flex-col gap-4">
<div className="grid grid-cols-2 gap-4 md:grid-cols-4">
{[...Array(8)].map((_, i) => (
{[...Array(12)].map((_, i) => (
<Skeleton key={i} className="h-20 rounded-lg" />
))}
</div>
@@ -240,7 +240,7 @@ export function PlatformCostContent({ searchParams }: Props) {
value={formatMicrodollars(
dashboard.avg_cost_microdollars_per_request ?? 0,
)}
subtitle="Known cost divided by total requests"
subtitle="Known cost divided by cost-bearing requests"
/>
<SummaryCard
label="Avg Input Tokens"
@@ -268,6 +268,13 @@ export function PlatformCostContent({ searchParams }: Props) {
)}
subtitle="Median cost per request"
/>
<SummaryCard
label="P75 Cost / Request"
value={formatMicrodollars(
dashboard.cost_p75_microdollars ?? 0,
)}
subtitle="75th percentile cost"
/>
<SummaryCard
label="P95 Cost / Request"
value={formatMicrodollars(