← Cycles
Design · c66

cost-center

archivedcreated 2026-08-14· last activity 2026-10-27

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.

Outcome

Closed 2026-10-01 — folded into c105 Cost Center. The toggle was never ported. Mark reverted the qcontrol implementation the same day in favour of the mock, and the page moved on underneath it: qdash ui/ was deprecated for the c99 Fable app. c105 re-drew /cost on the listing pattern. Every ledger row there carries Spend, Tokens and $ / 1M side by side, so a currency ⇄ tokens switch has nothing left to switch, and Mark retired it (c105 evaluation §9.5).

Carried forward into c105:

  • The batch-day flattening. The Spend card's spark and the per-team sparks handle this.
  • Leaders flipping between units. This became the Model lens's share-of-spend beside share-of-tokens, plus the $ / 1M column.
  • Token totals excluding cache. "Tokens" is defined as excluding cache everywhere, with cache priced into $ / 1M and given its own Token-kind lens.

The mock stays at /pages/cost-center-unit-toggle as the record.

Visual record

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

c66 hero
c66 full

In the archive

Artifacts

Qpoint Brand Style Guide