Skip to content

fix(azure): drop Advisor recommendations with absent or unparsable savings - #217

Merged
cristim merged 2 commits into
mainfrom
fix/zero-vs-absent-62
Oct 5, 2026
Merged

cristim merged 2 commits into
mainfrom
fix/zero-vs-absent-62

Conversation

@cristim

@cristim cristim commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

What

extFloat in providers/azure/recommendations.go now returns (float64, error). A missing annualSavingsAmount key, a nil value, a nil ExtendedProperties map, an empty string, a non-numeric value (for example "1,234.00"), a non-finite value (NaN, Inf, -Inf) and a negative value are errors. convertAdvisorRecommendation logs a warning and drops that Advisor recommendation. An explicit "0" is still kept with EstimatedSavings = 0.

Why

Before this change a missing key, nil value, nil map, empty string or unparsable value shipped a recommendation with a fabricated EstimatedSavings = 0. It was ranked below everything else and hidden by any savings threshold, and nothing was logged. NaN, Inf and negative inputs shipped as themselves rather than as 0, which is equally wrong for a savings figure. This is the first acceptance item of #62.

Behavior change: an Advisor recommendation with no ExtendedProperties at all was previously kept with zero savings. It is now dropped with a warning, because its savings are absent.

Not in this PR (remaining for #62)

  • pkg/config DryRun / AutoApprove: already fixed by fix(config): keep the dry-run default when YAML omits dry_run #202.
  • providers/azure/internal/recommendations/converter.go amountValue vs amountValuePtr: reviewed, left unchanged. amountValue feeds OnDemandCost, CommitmentCost and EstimatedSavings, which are value float64 fields on ExtractedFields and common.Recommendation. The Legacy path collapses absent to 0 for those same fields. Fixing it means making those shared fields pointers, which is a cross-module API change for its own PR. RecurringMonthlyCost already uses amountValuePtr correctly.
  • pkg/scorer/scorer.go > 0 threshold guards: changing scorer.Config to distinguish configured 0 from unset is a breaking API change across pkg/config and pkg/reporter, so it goes in a separate PR.

How verified

  • New test TestConvertAdvisorRecommendation_ZeroVersusAbsentSavings feeds a real "0", a populated value, and ten absent, unparsable, non-finite or negative subtests (key absent, nil value, nil map, thousands separator, empty string, NaN, nan, Inf, -Inf, negative) through convertAdvisorRecommendation.
  • On the pre-fix recommendations.go (from 2c38426^) all ten subtests fail (for example Expected nil, but got: &common.Recommendation{... EstimatedSavings:0 ...}). With the fix all pass.
  • providers/azure: go vet ./..., go test ./... and golangci-lint run (repo config) pass, with GOWORK=off GOTOOLCHAIN=go1.26.6.
  • Fixture-based only; no live Azure Advisor call was made.

Refs #62

Summary by CodeRabbit

  • Bug Fixes
    • Azure cost recommendations now exclude entries when annual savings data is missing or invalid, rather than displaying an incorrect savings estimate.
    • Recommendations with zero savings remain available, and valid annual savings are shown as monthly estimates.

…vings

extFloat returned 0 for a missing annualSavingsAmount key, a nil value and
a ParseFloat failure alike, so a recommendation whose savings Azure did not
report (or reported as "1,234.00") shipped with EstimatedSavings = 0 and was
ranked as worthless with no log.

extFloat now returns an error for both cases. convertAdvisorRecommendation
logs a warning and drops the recommendation instead, while an explicit "0"
is still kept as a real zero saving.

Refs #62
@cristim cristim added priority/p2 Backlog-worthy triaged Item has been triaged effort/l Weeks severity/high Significant harm urgency/this-quarter Within the quarter impact/many Affects most users type/bug Defect labels Oct 5, 2026
@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-go/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: fbe36054-0d9e-46ce-b1c2-c2cb0a3ac1bc
📥 Commits

Reviewing files that changed from the base of the PR and between 337c5e0 and 2c38426.

📒 Files selected for processing (2)
  • providers/azure/recommendations.go
  • providers/azure/recommendations_test.go

Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.


📝 Walkthrough

Walkthrough

Azure Advisor recommendation conversion now rejects recommendations with missing or invalid annual savings data. Tests cover valid savings amounts, including zero, and missing or invalid values.

Changes

Azure recommendation conversion

Layer / File(s) Summary
Validate savings during recommendation conversion
providers/azure/recommendations.go, providers/azure/recommendations_test.go
extFloat returns errors for missing, nil, or unparsable values. Conversion logs and drops recommendations when annual savings cannot be parsed. Tests cover valid and invalid savings values.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 2c384

The change distinguishes absent or unparsable savings from explicit zero savings. No new merge-blocking risk is established; merge after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: dropping Azure Advisor recommendations when savings data is absent or unparsable.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · 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 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. Your current included review allowance is based on your included PR review attempts over the past 7 days. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 16 minutes.

@cristim
cristim merged commit ac0f269 into main Oct 5, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/l Weeks impact/many Affects most users priority/p2 Backlog-worthy severity/high Significant harm triaged Item has been triaged type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant