Cycles
Design · c66

cost-center

activecreated 2026-08-14· last activity 2026-09-11

Add unit-of-measurement toggle to qdash `/cost` page — switch display between currency ($) and tokens

Why

The qdash /cost page reports all cost metrics in currency (dollars), but tokens are the more honest and immediate unit of LLM consumption. List-price conversions to USD are estimates; token counts are ground truth. A toggle lets users see through both lenses — currency for budget accountability, tokens for usage clarity and efficiency analysis.

Objective

Ship a working unit toggle on the /cost page that switches the display between currency and tokens without requiring a page refetch. First slice: toggle + supporting backend data only. Future slices (c66 follow-on): multi-currency support, token cost modeling, etc.

Scope

  • Backend: crates/qdash/src/web.rs — add total_tokens, input_tokens, output_tokens to /api/costs totals
  • Frontend: crates/qdash/ui/app/pages/cost.vue — implement ?unit= state via useUrlState, add UxTabGroup toggle, wire StatTiles/BarLists/chart to pick value/formatter per unit
  • Design repo: cycle tracking in cycles/c66.cost-center/ (per Mark's choice — global numbering here, implementation in qcontrol)
  • Deliberately out of scope: spend guardrail panel (inherently currency-based), token cost modeling, DataTables (already show both columns)

Key Changes

  • Exploration & verdict (2026-08-14): Token data already exists in breakdown rows (by_model/by_agent/by_user/by_team) and daily series; only totals lacks token counts. Filling it properly on the backend is cheap and clean — verdict: feasible + high-value first slice.
  • Backend (implemented 2026-08-14): Added accumulators token_tot and output_tot to the costs() loop; extended /api/costs totals JSON with total_tokens, input_tokens, output_tokens.
  • Frontend (implemented 2026-08-14):
    • State: const { period, unit } = useUrlState({ period: 'all', unit: 'cost' })
    • Control: Added UxTabGroup with units [{ value: 'cost', label: '$' }, { value: 'tokens', label: 'Tokens' }] beside period switcher
    • StatTiles: Computed array swapping between cost-mode tiles (total/provider/estimated/cache%) and token-mode tiles (total/input/output/cache%)
    • BarLists: byAgent/byUser pick r.cost vs r.tokens; titles and formatters follow unit
    • Chart: spendSeries maps n: unit === 'cost' ? s.cost : s.tokens; series key auto-labels the legend
    • Caveat line: Hidden in token mode (currency-only)
    • Known nit: fmtN(0) renders "0" vs fmtC(0) renders "—" — acceptable for v1
  • Cycle docs (design repo, 2026-08-14): Created c66.cost-center/ with initial-prompt.md, CYCLE.md, and cost-unit-toggle-plan.md; updated CYCLES.md to index c66
  • Pivot to mock-first (2026-08-14, same day): Mark reverted the qcontrol implementation (backend + frontend + dist, all restored to committed state) in favor of working out the details on the design site first. Built /pages/cost-center-unit-toggle — a faithful /cost replica seeded with a live data snapshot (period=all, 2026-08-14) with the toggle fully wired: unit-driven tile remap, flipped Last-24h emphasis, unit-following table sort (remount trick for initialSort), mixed-unit targets exempt, plus a design-notes panel. The qcontrol implementation above stands as the validated port path once the mock settles the design.
  • Data findings baked into the mock: the 2026-08-13 batch day (29.9M tokens, $143) flattens the token-mode chart — log-scale/dual-axis question; leaders flip between modes (gpt-5.6-sol #1 by tokens, #3 by cost) — possibly better told as a $/M-token unit-price column; token totals exclude cache reads (~96% cache rate), needs an "excl. cache" sub-label to read honestly.

Visual record

2 captures — heroes, page slices, and full-page renders. Click to view.

c66 hero
c66 full

In the archive

Artifacts

  • initial-prompt.md
  • initial-prompt.md

Qpoint Brand Style Guide