Skip to content

feat(aws/recommendations): add SP commitment rate from CE recommendation details - #352

Open
cristim wants to merge 1 commit into
mainfrom
fix/ladder-od-to-commitment-349
Open

cristim wants to merge 1 commit into
mainfrom
fix/ladder-od-to-commitment-349

Conversation

@cristim

@cristim cristim commented Oct 12, 2026

Copy link
Copy Markdown
Member

Refs #349. PR-A of the go#349 plan: additive, nothing consumes it yet.

GetSPCommitmentRate returns r = (util/100) * EstimatedSPCost / (EstimatedSPCost + EstimatedSavingsAmount), ratio of sums over details matching the account (and region for EC2 Instance SP). EstimatedSavingsPercentage is deliberately not used (measured against all on-demand spend). Strict parsing: absent field or no match is ErrNoSPCommitmentRate, invalid is an error, never r == utilization.

Verification: recorded-shape fixtures only (30% discount; cross-check CurrentAverageHourlyOnDemandSpend*H - EstimatedOnDemandCost = SPCost + savings), ratio-of-sums, filters, typed absence, invalid fields, bad params. 7 mutations on formula/parse lines; 2 survivors fixed (unreachable r>1 bound removed, negative-savings test tightened). MANUAL VERIFICATION still required: CE field semantics against a live response.

🤖 Generated with Claude Code

…ion details

Refs #349. Derives r (commitment $ per on-demand $ for used commitment) as
(util/100) * EstimatedSPCost / (EstimatedSPCost + EstimatedSavingsAmount),
ratio of sums over matching details. Strict parsing; absence is
ErrNoSPCommitmentRate, never a 1:1 fallback. No consumers yet.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@cristim cristim added triaged Item has been triaged urgency/this-sprint Within the current sprint priority/p1 Next up; this sprint severity/high Significant harm impact/many Affects most users effort/m Days type/bug Defect labels Oct 12, 2026
@coderabbitai

coderabbitai Bot commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 3 billable files and costs up to $0.75.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 21 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 60 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-go/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 9bbde434-bee7-4245-b3dc-d042008d1fbb

📥 Commits

Reviewing files that changed from the base of the PR and between a2f6c67 and c8af0b6.


📒 Files selected for processing (3)
  • CHANGELOG.md
  • providers/aws/recommendations/sp_commitment_rate.go
  • providers/aws/recommendations/sp_commitment_rate_test.go

  • 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 12, 2026

Copy link
Copy Markdown
Member Author

Independent merge-gate review (Opus 5.5, claude-opus-5-5): APPROVE at c8af0b6

Head is up to date with main (merge-base = origin/main a2f6c67). Reviewed from git archive c8af0b65, GOWORK=off, go1.26.9.

Formula vs SDK (costexplorer v1.61.0 types.go, SavingsPlansPurchaseRecommendationDetail): EstimatedSPCost = "cost of the recommended Savings Plans over the length of the lookback period" (full commitment x hours, used and unused); EstimatedSavingsAmount is the lookback-total saving; EstimatedOnDemandCost is the OD left uncovered. Identity: savings = CurrentAvgHourlyODH - EstimatedOnDemandCost - EstimatedSPCost, so covered_od = SPCost + savings = OD value of usage the plan actually covers. Only utilSPCost is spent on that usage, so r = utilSPCost/covered_od. No double counting of utilization: covered_od already excludes waste, SPCost includes it, and util removes it once. Worked example: OD 100, 60 covered at 0.7, util 100: SPCost 42, savings 18, r = 42/60 = 0.70. Same usage, util 80: commitment 52.5, used 42, savings = 60 - 52.5 = 7.5, r = 0.852.5/60 = 0.70 (the rate is unchanged, as it should be). The "util 80 => 0.56" fixture holds SPCost and savings fixed, so it checks arithmetic only, not a physical scenario. If live CE ever reported EstimatedSPCost as used-only, the error direction is under-buy (r too low), not over-buy. This matches plan U1's fallback (HourlyCommitmentToPurchaseHu / OD). The manual live-CE verification caveat is in the godoc and the PR body.

r bounds: r = sum(u_i c_i)/sum(c_i+s_i) with u_i in [0,1], c_i,s_i >= 0 gives r <= 1, so the removed bound is unreachable. Negative fields and util > 100 fail in spRateTerms before any sum. NaN/Inf: rejected at parse; overflow to Inf in the sums gives r = 0 or NaN, and both error. Zero covered gives ErrNoSPCommitmentRate; r <= 0 (util 0) is an error. No input path returns r outside (0,1] without an error.

Filtering/params: term, payment, plan type and lookback go into the request (converters fail loud), so the response has only one term/payment and no mixing. AccountScope LINKED with an exact AccountId match. EC2 Instance SP matches on normalized region; Compute SP is the account blend, documented on Params.Region (D6 enforcement belongs to the consumer, PR-C). Pagination follows NextPageToken under the existing 20-page cap and fetchSPPageWithRetry.

Local evidence: go test -count=1 ./... (providers/aws) exit 0; go vet clean; git ls-files -z | xargs -0 git secrets --scan clean with BSD and GNU grep; no 12-digit IDs in the diff. CI green on this SHA (all 15 checks). Labels match go#349. Body says Refs #349 and does not close it.

Mutation run (one run, 16 mutants, non-blocking): 12 killed. 4 survived, all coverage gaps and no defects: (1) dropping the NaN/Inf parse check is still caught downstream by IsNaN(r); (2) dropping r <= 0 survives because no test uses util=0 (the guard exists and is correct); (3) skipping pagination survives because no multi-page fixture exists; (4) AccountScope PAYER is not asserted. Follow-ups: tests for util=0, two pages, and the AccountScope request field; a 3yr all-upfront fixture as the plan calls for; an unmapped CE region display name fails closed (ErrNoSPCommitmentRate).

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

Labels

effort/m Days impact/many Affects most users priority/p1 Next up; this sprint severity/high Significant harm triaged Item has been triaged type/bug Defect urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant