Reviewed commit: be11bdcb5. Note: origin/main moved to 3e9660d06 during the review; re-verify against current main before changing code, since a finding may have been fixed or moved.
ApplyCountOverride and ApplyInstanceLimit assign .Count directly and leave the cost fields describing the old quantity. The confirmation prompt, the CSV report and the audit record all then state the wrong money, on the exact screen the operator uses to approve the spend.
Where
cmd/helpers.go:491-502 - ApplyCountOverride
cmd/helpers.go:505-526 - ApplyInstanceLimit
- The correct idiom, in the same file:
cmd/helpers.go:173-178 (applyCoverage, routed through common.ScaleRecommendationCosts, with a comment explaining why desynchronising count and cost is a bug) and cmd/helpers.go:396-403 (applyTargetCoverageRI)
- Consumers of the stale fields:
ConfirmPurchase's savings figure (cmd/multi_service.go:157 -> sumPassedRecs over EstimatedSavings), the UpfrontPayment / EstimatedSavings CSV columns (cmd/multi_service_csv.go:272-274), the TOTAL row (cmd/multi_service_csv.go:307-321), and the audit record's EstimatedCost (pkg/common/audit.go:60-61)
What
After either helper runs, CommitmentCost, OnDemandCost, EstimatedSavings and RecurringMonthlyCost still describe the pre-override or pre-truncation quantity. Every other sizing path in the same file routes through common.ScaleRecommendationCosts precisely to keep the two in sync, and applyCoverage carries a comment saying why.
Failure scenario (override)
A recommendation with Count = 1, CommitmentCost = $4,000. The operator runs:
cudly ... --override-count 10 --purchase
ApplyCountOverride sets Count = 10 and leaves CommitmentCost = $4,000. The confirmation prompt and the CSV both report about $4,000 upfront while AWS is charged about $40,000. That is a 10x understatement on the approval screen.
Failure scenario (limit)
A recommendation with Count = 20, CommitmentCost = $100,000, run with --max-instances 5. Count becomes 5, the cost stays $100,000, so the CSV and the audit record overstate the purchase by 4x. The error runs in both directions depending on which helper fired, so an operator cannot even learn a consistent correction factor.
Fix direction
Route both helpers through common.ScaleRecommendationCosts(rec, newCount/oldCount) the way applyCoverage does, guarding oldCount == 0.
The regression test should assert the cost fields, not just Count. A test that only checks Count after the override passes today and would keep passing with the bug present.
Related
--max-instances is separately applied per (service, region) rather than as the documented global cap, filed as its own issue from this review. The two interact: the per-region application means ApplyInstanceLimit runs many times per run, so the cost desync fires once per region as well.
Reviewed commit:
be11bdcb5. Note:origin/mainmoved to3e9660d06during the review; re-verify against currentmainbefore changing code, since a finding may have been fixed or moved.ApplyCountOverrideandApplyInstanceLimitassign.Countdirectly and leave the cost fields describing the old quantity. The confirmation prompt, the CSV report and the audit record all then state the wrong money, on the exact screen the operator uses to approve the spend.Where
cmd/helpers.go:491-502-ApplyCountOverridecmd/helpers.go:505-526-ApplyInstanceLimitcmd/helpers.go:173-178(applyCoverage, routed throughcommon.ScaleRecommendationCosts, with a comment explaining why desynchronising count and cost is a bug) andcmd/helpers.go:396-403(applyTargetCoverageRI)ConfirmPurchase's savings figure (cmd/multi_service.go:157->sumPassedRecsoverEstimatedSavings), theUpfrontPayment/EstimatedSavingsCSV columns (cmd/multi_service_csv.go:272-274), theTOTALrow (cmd/multi_service_csv.go:307-321), and the audit record'sEstimatedCost(pkg/common/audit.go:60-61)What
After either helper runs,
CommitmentCost,OnDemandCost,EstimatedSavingsandRecurringMonthlyCoststill describe the pre-override or pre-truncation quantity. Every other sizing path in the same file routes throughcommon.ScaleRecommendationCostsprecisely to keep the two in sync, andapplyCoveragecarries a comment saying why.Failure scenario (override)
A recommendation with
Count = 1,CommitmentCost = $4,000. The operator runs:ApplyCountOverridesetsCount = 10and leavesCommitmentCost = $4,000. The confirmation prompt and the CSV both report about $4,000 upfront while AWS is charged about $40,000. That is a 10x understatement on the approval screen.Failure scenario (limit)
A recommendation with
Count = 20,CommitmentCost = $100,000, run with--max-instances 5.Countbecomes 5, the cost stays $100,000, so the CSV and the audit record overstate the purchase by 4x. The error runs in both directions depending on which helper fired, so an operator cannot even learn a consistent correction factor.Fix direction
Route both helpers through
common.ScaleRecommendationCosts(rec, newCount/oldCount)the wayapplyCoveragedoes, guardingoldCount == 0.The regression test should assert the cost fields, not just
Count. A test that only checksCountafter the override passes today and would keep passing with the bug present.Related
--max-instancesis separately applied per (service, region) rather than as the documented global cap, filed as its own issue from this review. The two interact: the per-region application meansApplyInstanceLimitruns many times per run, so the cost desync fires once per region as well.