fix: fleet running costs subtracted a EUR tariff from a USD gross - #199
Conversation
Every gross in /api/fleet/economics comes from get_earned_by_platform, which is USD by contract. The electricity price came straight from the tariff config, in whatever currency the user set, and machine_economics does net = gross-cost. Live that rendered gross 5.00 (USD) minus cost 14.24 (EUR, 65 W at EUR 0.30/kWh) = net -9.24, verdict "losing money", with "turning it off would save that" — advice to switch off hardware, wrong by the whole FX spread. The true net was about -$11.35, not -9.24 of any currency. With a weaker tariff currency the error is not 15% but orders of magnitude. The payload also carried no currency field at all, and fleet.html rendered Number(v).toFixed(2), so the user saw bare numbers they could not attribute to a unit — while those numbers silently mixed two. Fixed the way /api/earnings/net was in #196: convert the TARIFF to USD, so the endpoint stays canonical USD like the rest of the API and the frontend's display-currency layer renders it in whatever the viewer reads in. When no rate is available the cost is None, not zero — a zero cost would render gross as net and overstate earnings, which is the mistake this module already guards against when no tariff is set at all. formatCurrency is now exported on CP so fleet.html can reach the one function that knows the viewer's display currency. null still renders as an em dash, so "not reporting" stays distinct from "earns nothing". Negative control, each part separately: not converting the tariff fails 2 tests; treating a missing rate as usable fails 1; dropping the currency label fails 1; restoring the bare-number renderer fails 1. Nothing overlaps. Closes CashPilot-dlr
|
Warning Review limit reached
Next review available in: 6 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #199 +/- ##
==========================================
+ Coverage 95.07% 95.08% +0.01%
==========================================
Files 46 46
Lines 5912 5925 +13
==========================================
+ Hits 5621 5634 +13
Misses 291 291
🚀 New features to boost your workflow:
|
The defect
Every gross in
/api/fleet/economicscomes fromget_earned_by_platform, which is USD by contract. The electricity price came straight from the tariff config, in whatever currency the user set.machine_economicsthen doesnet = gross - cost.Live, that rendered:
Advice to switch off hardware, wrong by the whole FX spread — the true net was about −$11.35, not −9.24 of any currency. With a weaker tariff currency the error is not 15% but orders of magnitude.
The payload also carried no currency field at all, and
fleet.htmlrenderedNumber(v).toFixed(2)— bare numbers the user could not attribute to a unit, while those numbers silently mixed two.The fix
Same design
/api/earnings/netsettled on in #196: convert the tariff to USD, so the endpoint stays canonical USD like the rest of the API and the frontend's display-currency layer renders it in whatever the viewer reads in.When no rate is available the cost is
None, not zero — a zero cost renders gross as net and overstates earnings, the mistake this module already guards against when no tariff is set at all. The payload says so explicitly (fx_unavailable,tariff_currency,cost_unavailable_reason).formatCurrencyis now exported onCPsofleet.htmlcan reach the one function that knows the viewer's display currency.nullstill renders as an em dash, so "not reporting" stays distinct from "earns nothing".Evidence
ruff check+ruff format --checkclean,node --checkclean, 2636 passed.Negative control, each part of the fix separately:
currencylabelNo overlap — each part is independently load-bearing.
Closes CashPilot-dlr