Skip to content

fix(gcp/computeengine): report monthly CUD cost as recurring, not upfront - #385

Merged
cristim merged 2 commits into
fix/271-gcp-compute-sku-pricingfrom
fix/383-gcp-compute-monthly-cost-semantics
Oct 13, 2026
Merged

cristim merged 2 commits into
fix/271-gcp-compute-sku-pricingfrom
fix/383-gcp-compute-monthly-cost-semantics

Conversation

@cristim

@cristim cristim commented Oct 13, 2026

Copy link
Copy Markdown
Member

What

Align Compute Engine CUD cost fields with the shared semantics (CommitmentCost = upfront, 0 for monthly or no-upfront; RecurringMonthlyCost = USD per month). Before, a monthly rec had CommitmentCost = the term total and RecurringMonthlyCost = total / months.

The platform currently computes upfront + monthly x term (platform scheduler.go:1650), so the old output was counted about 2x. This PR removes that overcount. platform#683: please confirm for the platform owner that no other consumer relies on CommitmentCost being the term total for GCP.

  • enrichRecWithPricing sets RecurringMonthlyCost = committed term total / months and leaves CommitmentCost 0. A pricing failure leaves RecurringMonthlyCost nil (unknown), not 0.
  • BreakEvenMonths is no longer computed here: with no upfront payment it is undefined, and the old value treated the whole term cost as sunk.
  • OnDemandCost is unchanged (on-demand price over the term).
  • GCP CUDs are billed monthly (https://cloud.google.com/docs/cuds), so the forced monthly payment option stays.

Stacked on go#381

This branch contains the go#381 commits (pricing); merge #381 first, then this one rebases cleanly onto main. Only the last commit is new.

Fail before, pass after

TestConverterFillsPricingForScorer (4 vCPU, 6 GiB, live-shaped N1 1-year SKUs) on the pre-change code:

Error:      Should be zero, but was 838.10424
Messages:   a monthly CUD has no upfront payment, so CommitmentCost is 0 (...)
Error:      Should be zero, but was 20.431520501138948
Messages:   no upfront payment, so there is nothing to break even on

After: passes, with RecurringMonthlyCost = (4 x 0.019915 + 6 x 0.002669) x 8760 / 12 = 69.84 USD/month. go test ./... in providers/gcp passes.

Closes #383
Refs platform#683

🤖 Generated with Claude Code

…ront

CommitmentCost is the upfront payment and is 0 for a monthly commitment;
the committed price goes to RecurringMonthlyCost. The platform adds upfront
plus monthly x term, so the term total in CommitmentCost was counted twice.
BreakEvenMonths is dropped: with no upfront payment there is none.

Closes #383
Refs platform#683

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@cristim cristim added priority/p2 Backlog-worthy severity/medium Moderate harm type/bug Defect labels Oct 13, 2026
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-go/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: da5f3134-0ad9-47ce-9536-9f5dc17a18b9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@cristim

cristim commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Independent review (claude-opus-5-5) of 2112144: CHANGES REQUESTED

Reviewed head 2112144 (0fcebc2 plus a merge of go#381's 1a25519).

The CommitmentCost and RecurringMonthlyCost change is right. Docs (https://docs.cloud.google.com/docs/cuds, redirected from cloud.google.com/docs/cuds): "You are billed a monthly fee for the commitments you purchase." The page mentions no upfront option. So CommitmentCost = 0, RecurringMonthlyCost = committed hourly x 8760 x years / (12 x years) = hourly x 730, and the forced monthly all match the shared semantics. The platform computes upfront + monthly x term (platform internal/scheduler/scheduler.go, UpfrontCost: rec.CommitmentCost / MonthlyCost: rec.RecurringMonthlyCost), so a 1yr n2-standard-8 now totals 0 + 178.65 x 12 = 2143.82, where it used to be 2 x 2143.82.

Blocking

  1. client.go enrichRecWithPricing: rec.OnDemandCost = pricing.OnDemandPrice is the on-demand price over the whole term. AWS (parser_ri.go, EstimatedMonthlyOnDemandCost; parser_sp.go hourly x 730) and Azure (consumption.go, x DaysPerMonth / lookBack) report it monthly. The platform also reads it as "the canonical on-demand monthly baseline" (internal/config/types.go:592) and computes savings % = savings / on_demand_cost (frontend/src/approval-details.ts:296). Live, end to end, for n2-standard-8 in us-central1: OnDemandCost = 3403.01 (1yr) and 10209.04 (3yr), where the monthly figure is 0.388472 x 730 = 283.58. That makes the platform's savings % 12x or 36x too small. This PR is the cost-semantics change and states that OnDemandCost is left unchanged; it needs to be on-demand hourly x 730 as well.

Non-blocking
2. Coverage gap: changing monthly := pricing.CommitmentPrice / float64(termYears*12) to / 12 survives the suite, because TestConverterFillsPricingForScorer is 1yr only. A 3yr case would pin it. The live 3yr value is 0.174824 x 730 = 127.62.
3. Cloud SQL and Memorystore still use the old semantics (CommitmentCost = term total, BreakEvenMonths). Needs a follow-up issue.
4. GetOfferingDetails falls through to upfrontCost = totalCost for any payment option other than monthly or upfront. It is unreachable from the converter (which forces monthly), and it predates this PR.

Evidence

@cristim
cristim merged commit aeedcaf into fix/271-gcp-compute-sku-pricing Oct 13, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority/p2 Backlog-worthy severity/medium Moderate harm type/bug Defect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant