Skip to content

fix(aws/recommendations): complete NaN/Inf money guards across parser_ri, ondemand_series, RI-utilization (follow-up to #1461) - #1473

Merged
cristim merged 3 commits into
mainfrom
fix/nan-inf-money-followup-1461
Jul 20, 2026
Merged

cristim merged 3 commits into
mainfrom
fix/nan-inf-money-followup-1461

Conversation

@cristim

@cristim cristim commented Jul 20, 2026

Copy link
Copy Markdown
Member

Follow-up to #1461 — completes the NaN/Inf/negative money guards that were stranded

#1461 merged with only its first commit (the SP-path parseOptionalFloat
NaN/Inf guard). The two follow-up commits that closed the rest of the same
bug class — added on the PR branch after an adversarial (Fable) review — never
reached main. This PR brings them to main. Verified on current origin/main:
ondemand_series.go has no non-finite guard, so these are live bugs.

strconv.ParseFloat (and fmt.Sscanf %f) accept "NaN"/"Inf" with a nil
error
, so a corrupt CE float slips through every err == nil / != 0 / <= 0
check downstream.

Sites fixed (all in providers/aws/recommendations)

  • parser_ri.go money parsers (parseCostInformation, parseAWSCostDetails):
    routed through the shared guarded parseOptionalFloat, so the RI path rejects
    NaN/Inf/negative exactly like the SP path (restores real SP/RI parity — the
    doc comments claiming it already asserted a parity that didn't hold).
  • parseOptionalFloat: also rejects negative values (every field it parses
    is a non-negative financial metric; mirrors the repo's stricter parseSPFloat).
  • ondemand_series.go accumulateDailyResults: a "NaN"/"Inf" daily CE
    amount slipped past the downstream all-zero fail-loud check (NaN != 0) and
    poisoned the ladder baseline the engine sizes purchases from. Now fails
    loud. No negative guard here — CE unblended cost is legitimately negative on
    credit/refund days.
  • parser_ri.go parseRIUtilizationSignals: NaN/Inf were stored as a live
    --target-coverage signal (NaN <= 0 is false), producing NaN purchase
    counts. Now routed through parseOptionalFloatOrWarn (warn + 0).
  • parser_ri.go parseRecommendedQuantity: Sscanf %f also accepts NaN/Inf;
    a non-finite quantity would corrupt the purchase count. Fail loud.
  • utilization.go parseFloat: degrades NaN/Inf to 0 (a single non-finite
    hours value would otherwise poison every utilization aggregate).

Verification

  • Regression tests added for every site; each verified fail-on-bug /
    pass-on-fix
    (e.g. removing the ondemand_series guard fails
    TestGetOnDemandSeries_NonFiniteAmountFails).
  • go build ./..., go vet, full recommendations suite (400+ tests) green.
  • gocyclo -over 10 clean (the refactor reduced complexity). Local golangci is
    v2.11.4 (CI pins v2.10.1); the diff adds no new findings — all pre-existing
    package lint debt is on lines this PR did not touch.
  • Independent Fable adversarial review gate before merge.

cristim added 2 commits July 20, 2026 16:14
… too

Addresses the Fable adversarial-review finding on this PR: the SP-path
non-finite guard did not fully close the bug class. The RI sibling parser
(parseCostInformation, parseAWSCostDetails) parsed the same CE money fields
(EstimatedMonthlySavingsAmount/Percentage, UpfrontCost,
EstimatedMonthlyOnDemandCost, RecurringStandardMonthlyCost) with bare
strconv.ParseFloat and no guard, so a "NaN"/"Inf" value still flowed into
CommitmentCost/OnDemandCost/savings/RecurringMonthlyCost. The doc comments also
claimed the SP path "mirrors the RI path", which was false after the first commit.

Changes:
- Route both RI money parsers through the shared parseOptionalFloat, restoring
  genuine SP/RI parity (comments now hold).
- parseOptionalFloat also rejects negative values (every field it parses is a
  non-negative financial metric; mirrors the repo's stricter parseSPFloat).
- utilization.go parseFloat degrades NaN/Inf to 0 with a warning, so a single
  non-finite hours value can't poison every downstream utilization aggregate.

Tests:
- New TestRICostParsers_RejectNonFiniteAndNegative (verified it fails when the
  RI routing is reverted).
- Extended TestParseOptionalFloat_RejectsNonFinite with negative cases + a
  zero-is-valid sanity check.
- Updated TestParseRecommendationDetail_MalformedCostFields error-string
  assertions to the now-unified "failed to parse <Field> ..." wording.
…package

Second round of the Fable adversarial review on this PR: it found the same
non-finite bug class still open at three more parse sites in the recommendations
package that the first two commits missed.

- ondemand_series.go accumulateDailyResults: a "NaN"/"Inf" CE daily amount
  parsed with a nil error and slipped past the downstream all-zero fail-loud
  check (NaN != 0), poisoning the ladder baseline the engine sizes purchases
  from. Now fails loud on non-finite. NO negative guard here -- CE unblended
  cost is legitimately negative on credit/refund days.
- parser_ri.go parseRIUtilizationSignals: NaN/Inf were stored into
  AverageInstancesUsedPerHour / RecommendedUtilization; the --target-coverage
  guards are all `<= 0` and NaN <= 0 is false, so a stored NaN was treated as a
  live signal and produced NaN purchase counts. Now routed through
  parseOptionalFloatOrWarn (warn + 0).
- parser_ri.go parseRecommendedQuantity: fmt.Sscanf %f also accepts NaN/Inf;
  a non-finite quantity would corrupt the purchase count. Fail loud.

Tests:
- ondemand_series_test.go: TestGetOnDemandSeries_NonFiniteAmountFails.
- parser_ri_test.go: non-finite-degrades-to-zero case in the utilization-signals table.
- parser_sp_test.go: TestUtilizationParseFloat_DegradesNonFinite for the
  utilization.go parseFloat guard added in the previous commit.
@cristim cristim added triaged Item has been triaged priority/p1 Next up; this sprint severity/high Significant harm urgency/now Drop other things impact/all-users Affects every user effort/s Hours type/bug Defect labels Jul 20, 2026
@coderabbitai

coderabbitai Bot commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 79195c87-b0fc-4c39-a6a6-f57d7223c586

📥 Commits

Reviewing files that changed from the base of the PR and between a6665b5 and 5946557.

📒 Files selected for processing (9)
  • providers/aws/ladder/adapters.go
  • providers/aws/ladder/adapters_test.go
  • providers/aws/recommendations/ondemand_series.go
  • providers/aws/recommendations/ondemand_series_test.go
  • providers/aws/recommendations/parser_ri.go
  • providers/aws/recommendations/parser_ri_test.go
  • providers/aws/recommendations/parser_sp.go
  • providers/aws/recommendations/parser_sp_test.go
  • providers/aws/recommendations/utilization.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/nan-inf-money-followup-1461

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

@cristim

cristim commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…tity (Fable follow-ups)

Addresses the Fable open-PR review findings on this PR:

- ladder/adapters.go mapActiveSP (MED, live money path): SavingsPlan.Commitment
  parsed with bare strconv.ParseFloat and no non-finite guard, despite the doc
  claiming it "fails loud on a non-numeric Commitment (money path)". A NaN/Inf
  commitment flowed through sumSPHourlyCost / sumExpiringSPHourlyCost into the
  ladder layer-state totals the engine sizes purchases from. Now rejects
  NaN/Inf/negative (a commitment is a non-negative money rate).
- parser_ri.go parseRecommendedQuantity (LOW): rejected non-finite but still
  accepted a negative purchase count ("-3" via Sscanf/Atoi). Now rejects negatives.
- parser_ri.go parseRIUtilizationSignals (LOW): the refactor dropped
  service/account context from the parse-failure warning; the field label now
  carries "service=.. account=.." so an operator can identify the corrupt row.

Regression tests: TestSPLister_NonFiniteOrNegativeCommitmentFails (verified fails
when the guard is reverted), plus NaN/Inf/negative cases in the quantity table.
@cristim

cristim commented Jul 20, 2026

Copy link
Copy Markdown
Member Author

Addressed the Fable open-PR review: guarded ladder/adapters.go mapActiveSP SP-commitment parse (NaN/Inf/negative → fail loud; it fed the ladder purchase-sizing totals), rejected negative purchase counts in parseRecommendedQuantity, and restored service/account context to the RI utilization-parse warnings. Regression tests added (verified fail-on-revert).

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

@cristim: Reviewing the latest updates, including the new commitment and purchase-quantity guards and their regression coverage.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cristim
cristim merged commit 299b6fd into main Jul 20, 2026
19 checks passed
@cristim
cristim deleted the fix/nan-inf-money-followup-1461 branch July 27, 2026 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/all-users Affects every user priority/p1 Next up; this sprint severity/high Significant harm triaged Item has been triaged type/bug Defect urgency/now Drop other things

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant