Context
Migration 0109_ai_usage_actual_tokens.sql added real input_tokens/output_tokens/total_tokens/cost_usd columns to ai_usage_events, and every AI call (both self-host CLI providers and the hosted BYOK direct-fetch path) already writes them via recordAiUsageEvent. But nothing reads them back for the HOSTED gittensory-api Worker: no HTTP endpoint aggregates the table (src/api/routes.ts has zero references to it), and the one dashboard built to visualize it (grafana/dashboards/orb-ai-usage.json) is wired exclusively to the self-host reporting-exporter's local SQLite export (docker-compose.yml's GITTENSORY_REPORTING_SOURCE_DB, mounted from the self-host container's own local app DB) -- architecturally unable to see the hosted Cloudflare D1's rows at all.
The only two existing readers, sumAiEstimatedNeuronsSince and countByokAiEventsForRepoSince (src/db/repositories.ts), sum a proxy quota column and a row count respectively -- neither surfaces real tokens or dollar cost.
Net effect: a real token-burn incident on the hosted Worker today would be completely invisible except via an ad hoc manual D1 SQL query -- nothing prompts an operator to run one.
Requirements
- Add a hosted-Worker-reachable aggregate of
ai_usage_events' real token/cost columns, scoped by repo and/or time window.
- Surface it via either (a) a new field on the existing
/v1/internal/ops/stats endpoint, or (b) a new dedicated internal endpoint, whichever fits the existing ops-stats shape better.
- Consider whether a review-burst-style anomaly rule keyed on token/cost volume (rather than the publish ledger -- see the companion issue on review-burst's blind spot) belongs here or as a follow-up.
Deliverables
- A new repository function that sums real tokens/cost from
ai_usage_events for a repo/window.
- Wiring into the ops-stats endpoint (or a new endpoint), gated the same way the rest of that surface is.
- Tests covering the aggregate query, including the zero-rows case.
Acceptance criteria
- An operator can query the hosted Worker (not just self-host's local reporting export) and get real token/cost totals for a repo/window.
- 100% branch coverage on the new aggregate + endpoint wiring.
Parent: #1667
Context
Migration
0109_ai_usage_actual_tokens.sqladded realinput_tokens/output_tokens/total_tokens/cost_usdcolumns toai_usage_events, and every AI call (both self-host CLI providers and the hosted BYOK direct-fetch path) already writes them viarecordAiUsageEvent. But nothing reads them back for the HOSTED gittensory-api Worker: no HTTP endpoint aggregates the table (src/api/routes.tshas zero references to it), and the one dashboard built to visualize it (grafana/dashboards/orb-ai-usage.json) is wired exclusively to the self-hostreporting-exporter's local SQLite export (docker-compose.yml'sGITTENSORY_REPORTING_SOURCE_DB, mounted from the self-host container's own local app DB) -- architecturally unable to see the hosted Cloudflare D1's rows at all.The only two existing readers,
sumAiEstimatedNeuronsSinceandcountByokAiEventsForRepoSince(src/db/repositories.ts), sum a proxy quota column and a row count respectively -- neither surfaces real tokens or dollar cost.Net effect: a real token-burn incident on the hosted Worker today would be completely invisible except via an ad hoc manual D1 SQL query -- nothing prompts an operator to run one.
Requirements
ai_usage_events' real token/cost columns, scoped by repo and/or time window./v1/internal/ops/statsendpoint, or (b) a new dedicated internal endpoint, whichever fits the existing ops-stats shape better.Deliverables
ai_usage_eventsfor a repo/window.Acceptance criteria
Parent: #1667