Repository navigation
fix(aws): credit replacement RIs bought inside the coverage lookback in the EC2 expiry deduction - #449
Conversation
…in the EC2 expiry deduction The per-pool expiry adjustment subtracted expiring RIs from lagged Cost Explorer coverage without seeing replacements bought inside the coverage window, so a re-run recommended buying them again. The new AdjustExistingCoverageForExpiringCommitmentsWithCoverageOptions credits active or payment-pending RIs that started after now minus CoverageLookbackDays and do not expire in the window, and deducts max(0, expiring - replacements) per pool, mirroring the RDS family path from #347. The existing function delegates with no lookback, so its callers see no change until they pass one. Closes #346 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reached
This review includes 3 billable files and costs up to $0.75.
Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing. Or wait 52 minutes for your next included review. View limit details
Comment |
|
@coderabbitai review |
|
Independent review verdict: CLEAN at 0f74be1Reviewer: fresh Claude agent (Sonnet, high effort), not the author. Coordinator: claude-cc-reviewer. Formula, per pool key = region + instance type (
Hand-checked scenarios (coverage 60% on demand 30, E=10 expiring in 15d, lookback 30):
Non-blocking:
Gate:
|
|
CI is green on head |
Summary
The EC2 per-pool expiry adjustment (
providers/aws/recommendations/expiry.go) subtracts RIs that expire inside the window from lagged Cost Explorer coverage. It gave no credit for replacement RIs already bought inside the coverage lookback. Lagged coverage does not see those yet, so a re-run recommended buying the replacements again. The RDS family path fixed the same problem in #347 (family_nu.go:392-523). This ports that rule to the EC2 per-pool path.New API
PoolExpiryOptions{WindowDays, CoverageLookbackDays}.AdjustExistingCoverageForExpiringCommitmentsWithCoverageOptions(recs, commitments, coverage, opts).Rule
Per pool, R is the summed
Countof commitments that meet all three conditions:StartDateis after now minusCoverageLookbackDays, credited only when that is above 0.The deduction becomes
max(0, expiring - R). Pools that net to zero are skipped. The 2-line lookback check mirrorsfamily_nu.go:511-512and has a comment pointing there.family_nu.goitself is unchanged.Compatibility
The existing
...WithCoveragefunction now delegates with no lookback. Its existing tests are unchanged and green, and its callers see no change until they pass a lookback. The CLI, MCP and platform need to call the new function with the samelookbackDaysthey give the coverage fetch. Only the CLI calls it today (cmd/multi_service_helpers.go:540); its adoption is tracked in LeanerCloud/cloud-commitments-cli#2235. MCP and platform do not call it. The size-flex and pool-key limitations are tracked in #450.Godoc limitations
Edge change on the zero-lookback path: an expiring RI with a negative
Countused to raise coverage. It is now clamped to 0.Pools are org-wide (
commitmentPoolKeyhas no account dimension), so a replacement in another linked account is credited. That is consistent with org-wide coverage and RI sharing.CHANGELOG.mdhas an Unreleased / Added entry, in the style of #347.Closes #346
Verification (macOS, Go 1.26.9)
Build and lint
(cd providers/aws && GOWORK=off go test -race -short ./...): passes.make build,make vet: pass.gocyclo -over 10: clean.New tests (
expiry_lookback_test.go, 11 top-level):ExistingCoveragePercentExact, both pointer and value.Fail-before. With the credit disabled, 7 test functions fail: InsideLookback, BeforeLookback, PartialAndOverReplacement, States, PoolMatching, MissingDemand, SkippedRecs. The independent reviewer re-ran this in a scratch copy.
Mutation probes (reviewer, scratch copy), each failing tests:
max(0, ...)cap;Review. The plan had 2 passes and the diff 2 passes, all by the same non-author reviewer, with no actionable findings on tree
b9bf8002. One test literal changed after review: the "account ignored" row uses"other-linked-account"instead of a 12-digit account ID that tripped the git-secrets hook. The behaviour under test is unchanged.Fixtures only. No AWS call or purchase.
🤖 Generated with Claude Code