Skip to content

feat(inference): add token revenue and profit per GW-year y-axes / 新增每吉瓦年 token 收入与利润 Y 轴指标 - #973

Open
functionstackx wants to merge 3 commits into
masterfrom
feat/revenue-profit-per-mw-year
Open

feat(inference): add token revenue and profit per GW-year y-axes / 新增每吉瓦年 token 收入与利润 Y 轴指标#973
functionstackx wants to merge 3 commits into
masterfrom
feat/revenue-profit-per-mw-year

Conversation

@functionstackx

@functionstackx functionstackx commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds four y-axis metrics that reuse the normalized/OpenRouter token sale pricing path already behind Token Revenue per GPU Hour:

Metric key Formula Notes
tokenRevenuePerGwYear $/GPU/hr revenue × (1,000,000 ÷ all-in kW per GPU) × 8760 Gross revenue for one all-in utility GW running a year
tokenProfitPerGwYearH ($/GPU/hr revenue − costh) × GPU-hours per GW-year Owning, hyperscaler TCO
tokenProfitPerGwYearN ($/GPU/hr revenue − costn) × GPU-hours per GW-year Owning, Neocloud Giant TCO
tokenProfitPerGwYearR ($/GPU/hr revenue − costr) × GPU-hours per GW-year 3-year rental TCO

power and costh/costn/costr come from HW_REGISTRY, same as tpPerMw and the tokens-per-dollar axes. Profit can be negative when the sale price does not cover TCO at that operating point.

Changes

  • token-revenue.ts: TOKEN_SALE_PRICING_METRIC_KEYS, gpuHoursPerGwYear, tokenRevenuePerGwYear, tokenProfitPerGwYear, tokenSalePricingMetricFromRevenuePerGpuHour, tokenSalePricingLabels. usesTokenSalePricing and applyTokenRevenuePricing now cover all five sale-priced keys, so the OpenRouter price-source selector, subtitle, and URL state (i_revenue) work for the new axes without further wiring.
  • metric-registry.ts: four registry entries; the "Token Revenue per GPU Hour" control group becomes "Token Revenue" (GPU-hour + GW-year) and a "Token Profit per All in Utility GW per Year" group holds the three tiers.
  • chart-utils.ts: normalized placeholders in buildDerivedChartFields (zero when hardware lacks power or tier cost).
  • chart-rendering.ts: formatLargeNumber gains a billions tier so $/GW/yr ticks read 36.9B instead of 36900.0M.
  • useChartData.ts: axis label/title price-source suffix is now generic via tokenSalePricingLabels; existing "Token Revenue per GPU Hour at OpenRouter Pricing ($/GPU/hr)" strings are reproduced byte-for-byte (asserted in tests).
  • useInterpolatedTrendData.ts: Historical Trends interpolates priced $/GPU/hr revenue once and maps it through the new helper. tokenRevenuePerGwYear joins PROPORTIONAL_TO_THROUGHPUT; profit is affine so it is deliberately excluded.
  • ScatterGraph/GPUGraph/TrendChart: linear y-domain extends below zero only when data does (other metrics keep the zero floor); max padding handles all-negative extents.
  • axis-metric-explanations.ts: bilingual descriptions and formulas.
  • docs/data-transforms.md: documents the new fields.

Testing

  • bun run typecheck, bun run lint, bun run fmt, pre-commit typography check: clean.
  • bun run test:unit: 4321 passed. New tests cover B200/H200/H100 GPU-hours math, per-tier profit, negative profit, applyTokenRevenuePricing clearing and repricing all five keys, label generation, createChartDataPoint placeholders, Historical Trends interpolation for the new axes, and the billions formatter tier.
  • One pre-existing failure (benchmark-transform.test.ts, Object.groupBy) is a Node 20 sandbox limitation and reproduces on master.

中文说明

新增四个 Y 轴指标,复用「每 GPU 小时 token 收入」已有的标准化/OpenRouter token 售价路径:

  • tokenRevenuePerGwYear$/GPU/hr 收入 ×(1,000,000 ÷ 每 GPU 全电源配置 kW)× 8760,即 1 GW 全电源配置功率一年的 token 毛收入。
  • tokenProfitPerGwYearH/N/R($/GPU/hr 收入 − costh|costn|costr)× 每吉瓦年 GPU 小时数,分别对应超大规模自有、Neocloud Giant 自有与 3 年租赁的 TCO。售价低于 TCO 时为负值。

powercosth/costn/costr 均取自 HW_REGISTRY,与 tpPerMw 及 tokens-per-dollar 指标一致。

主要改动:usesTokenSalePricingapplyTokenRevenuePricing 统一泛化到 TOKEN_SALE_PRICING_METRIC_KEYS,OpenRouter 价格来源选择器、副标题与 URL 状态自动覆盖新指标;轴标签与标题的价格来源后缀改为通用逻辑,原有字符串保持不变;历史趋势插值先计算带价格的 $/GPU/hr 收入,再映射到各指标;ScatterGraphGPUGraphTrendChart 的线性 Y 轴仅在数据为负时向下延伸;formatLargeNumber 新增十亿(B)档位;补充中英双语指标说明、文档与单元测试。

测试:bun run typecheckbun run lintbun run fmt 均通过;bun run test:unit 4321 个用例通过,唯一失败项(Object.groupBy)为 Node 20 环境限制,在 master 上同样复现。


Note

Medium Risk
Touches derived chart math, sale-price pricing, and Y-axis scaling across scatter/GPU/trend charts; changes are well-tested but affect business-facing dollar metrics and trend interpolation.

Overview
Adds four inference Y-axis metrics that scale cache-aware token sale pricing from $/GPU/hr to $/GW/yr using all-in kW per GPU from HW_REGISTRY: gross tokenRevenuePerGwYear and net tokenProfitPerGwYearH/N/R (hyperscaler, Neocloud Giant, and 3-year rental TCO). Profit can be negative when sale price does not cover the tier hourly cost.

Token sale pricing is generalized via TOKEN_SALE_PRICING_METRIC_KEYS and helpers (gpuHoursPerGwYear, tokenSalePricingMetricFromRevenuePerGpuHour, tokenSalePricingLabels). applyTokenRevenuePricing and usesTokenSalePricing now cover all five sale-priced axes so OpenRouter/normalized source selection, subtitles, and URL state apply without extra wiring. Axis labels name the active price source for every sale-priced metric, not only GPU-hour revenue.

Charts and trends: buildDerivedChartFields emits normalized GW-year placeholders; Historical Trends interpolates priced $/GPU/hr once and maps through the shared helper (profit axes are affine, not proportional throughput). ScatterGraph, GPUGraph, and TrendChart allow linear Y domains below zero when data warrants it. formatLargeNumber adds a B tier for billion-scale ticks.

Metric registry control groups, bilingual axis explanations, docs (data-transforms.md), and unit tests are updated accordingly.

Reviewed by Cursor Bugbot for commit efb6fc2. Bugbot is set up for automated code reviews on this repo. Configure here.

Add four y-axis metrics that reuse the normalized/OpenRouter token sale
pricing path behind Token Revenue per GPU Hour:

- tokenRevenuePerMwYear: $/GPU/hr revenue x (1000 / all-in kW per GPU) x 8760
- tokenProfitPerMwYearH/N/R: ($/GPU/hr revenue - costh|costn|costr) x the
  same GPU-hours per MW-year; negative when sale prices sit below TCO

Generalize the price-source axis labels, the Historical Trends
interpolation, and applyTokenRevenuePricing over TOKEN_SALE_PRICING_METRIC_KEYS
so every sale-priced metric shares one pricing path. Let the linear y-domain
in ScatterGraph, GPUGraph, and TrendChart extend below zero only when the
data does, so negative profit stays visible. Add bilingual axis explanations,
docs, and unit tests.

中文:新增四个 Y 轴指标,复用每 GPU 小时 token 收入所用的标准化/OpenRouter token 售价路径:
tokenRevenuePerMwYear 为 $/GPU/hr 收入 ×(1000 ÷ 每 GPU 全电源配置 kW)× 8760;
tokenProfitPerMwYearH/N/R 为($/GPU/hr 收入 − costh|costn|costr)× 相同的每兆瓦年 GPU 小时数,
售价低于 TCO 时为负值。将价格来源轴标签、历史趋势插值以及 applyTokenRevenuePricing
统一泛化到 TOKEN_SALE_PRICING_METRIC_KEYS,使所有按售价计算的指标共用同一条定价路径。
ScatterGraph、GPUGraph 与 TrendChart 的线性 Y 轴仅在数据为负时才向下延伸,以保留负利润的可见性。
补充中英双语指标说明、文档与单元测试。
@vercel

vercel Bot commented Sep 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
inferencemax-app Ready Ready Preview Sep 3, 2026 7:29am UTC

Request Review

return {
type: (useLog ? 'log' : 'linear') as 'log' | 'linear',
domain: [yMin, ext[1] * 1.05] as [number, number],
domain: [yMin, yMax] as [number, number],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log scale drops negative profits

Medium Severity

Linear y-domains now extend below zero for profit, but a log y-scale still substitutes 0.1 when the extent is non-positive and does not keep signed values. With log scale left on, negative profit points become invalid log inputs and disappear, or the domain inverts when every point is a loss.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a1ccaa4. Configure here.

Rename tokenRevenuePerMwYear and tokenProfitPerMwYearH/N/R to their GW-year
equivalents and scale GPU-hours by 1,000,000 kW per GW instead of 1,000 kW
per MW. Update labels, bilingual explanations, docs, and tests. Add a
billions tier to formatLargeNumber so $/GW/yr ticks render as "36.9B" rather
than "36900.0M".

中文:将 tokenRevenuePerMwYear 与 tokenProfitPerMwYearH/N/R 重命名为对应的每吉瓦年指标,
GPU 小时数按每 GW 1,000,000 kW(而非每 MW 1,000 kW)换算。同步更新标签、中英双语说明、
文档与测试。为 formatLargeNumber 新增十亿(B)档位,使 $/GW/yr 刻度显示为 "36.9B" 而非 "36900.0M"。
@functionstackx functionstackx changed the title feat(inference): add token revenue and profit per MW-year y-axes / 新增每兆瓦年 token 收入与利润 Y 轴指标 feat(inference): add token revenue and profit per GW-year y-axes / 新增每吉瓦年 token 收入与利润 Y 轴指标 Sep 3, 2026

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit efb6fc2. Configure here.

// zero for every other metric so throughput charts still start at 0.
yMin = ext[0] < 0 ? ext[0] - range * 0.05 : Math.max(0, ext[0] - range * 0.05);
}
const yMax = ext[1] >= 0 ? ext[1] * 1.05 : ext[1] + range * 0.05;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collapsed domain for uniform negative profit

Medium Severity

All-negative max padding uses yRange * 0.05, so a single point or identical profits collapse to a [v, v] y-domain. Positive points still get max * 1.05 even when the range is zero, so a lone negative profit point gets a degenerate axis while a lone positive one does not.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit efb6fc2. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant