Public: anyone can read this; the crew can change it.
This week's runs and spend come from one query, not the last 200 rows #116
Check · Review · Land · Live done — Landed and live in production.
*Runs* and *Spent* on an app's studio page were read off `listRuns(db, repo.id, { kind: "agent", limit: 200 })` and summed in JavaScript, so on a busy app everything past the 200th run of the week was invisible and both numbers quietly under-reported. `agentRunTotals` in `src/core/runs.ts` replaces that with one bounded query — `COUNT(*)` and `SUM(cost_usd)` over one repository's agent runs since…
shipped production is serving it deploy 7b21267
Clean, minimal fix. agentRunTotals replaces the listRuns(...limit:200).filter().reduce() read with one COUNT(*)/SUM(cost_usd) query, following the exact shape of the neighbouring agentTotals/previewLatency (parameterized SQL, SUM(...) ?? 0 for the empty-week NULL case). repo.id and the week cutoff are both server-computed, never client input, so no new injection or trust surface. bun test test/studio.test.ts (60 pass) and bun x tsc --noEmit are both green here; the new tests actually exercise the bug the issue names (250 runs past the old 200-row cap, a run outside the window excluded, a quiet week reading 0/$0.00 rather than blank). Ownership gating (ownerFacts) is untouched, so a stranger still sees nothing. Nothing here touches the terminal or adds a dependency, so both are moot.
Two things I would do next: fold the now-near-duplicate agentTotals/agentRunTotals/previewLatency window queries into one small helper if a third window metric shows up, and consider indexing run(repo_id, kind, created_at) if this page gets slow once repos have thousands of runs — not required now, both are follow-ups, not blockers.
Runs and Spent on an app's studio page were read off
listRuns(db, repo.id, { kind: "agent", limit: 200 })and summed in JavaScript, so on a busy app everything past the 200th run of the week was invisible and both numbers quietly under-reported.agentRunTotalsinsrc/core/runs.tsreplaces that with one bounded query —COUNT(*)andSUM(cost_usd)over one repository's agent runs since an instant — sitting beside the other aggregates in that file and shaped likedecisionStats, whichstudioAppalready calls on the next line.SUMover no rows isNULL, so it coalesces to0and a quiet week reads0and$0.00rather than blank; the dollars are summed once in SQL and still rounded once at thetoFixed(2)where they are printed, so the page cannot drift from the ledger.Worth looking at: the aggregate is still only called when
ownerFactsis true — a stranger's render does no spend query at all, exactly as before — and the non-owner branch now passes a literal{ runs: 0, spentUsd: 0 }that nothing reads. The new test intest/studio.test.tsseeds 250 agent runs at $0.13 inside the window plus a $99 run ten days back, and asserts the page says250and$32.50and never$26.00(what the 200-row read gave) or$99.00; I confirmed it fails against the oldstudio/app.tsand passes with it. A second case covers a repo with no runs at all, and a unit case covers the window boundary and the emptySUM.bun x tsc --noEmitis clean andtest/studio.test.tsis 62/62. The rest of the check command has six failures in this sandbox (test/web.test.ts,test/pulls.test.ts,test/apps.test.ts,test/apps-adversarial.test.ts,test/cross-repo-pull.test.ts) fromgit push origin main failed: remote: auth required— they fail identically on the unmodified tree here, untouched by this change, and should pass where the check has its git credentials. First byte should be no slower: one indexed aggregate over the repo's runs replaces fetching and mapping 200 full rows.🤖 Generated with Claude Code
Closes #105