Skip to content

fix(cli): purchase-output corrections (savings label, no-upfront warning, descriptive RI IDs)#618

Merged
cristim merged 3 commits into
feat/multicloud-web-frontendfrom
fix/purchase-output-615-616-617
May 20, 2026
Merged

fix(cli): purchase-output corrections (savings label, no-upfront warning, descriptive RI IDs)#618
cristim merged 3 commits into
feat/multicloud-web-frontendfrom
fix/purchase-output-615-616-617

Conversation

@cristim
Copy link
Copy Markdown
Member

@cristim cristim commented May 20, 2026

Summary

Three correctness fixes for the purchase flow output:

  • fix(cli): purchase confirmation prompt labels monthly savings as 'annual' #615 - Monthly savings label: The ConfirmPurchase prompt said "estimated annual savings" but EstimatedSavings is a monthly value (from Cost Explorer's coverage API). Updated the doc comment and the printed line to say "monthly", consistent with the summary line and CSV column.

  • fix(cli): spurious 3yr no-upfront warning in --input-csv mode (uses flag default, not CSV per-row payment) #616 - Skip 3yr no-upfront warning in CSV mode: warnRDS3YearNoUpfront was firing a false alarm when --input-csv was used, because the --payment flag keeps its no-upfront default even though each CSV row carries its own payment option. Added an early return when CSVInput != "" so the warning only fires in interactive/flag-driven mode.

  • fix(cli): purchased RDS RIs get generic reservation IDs instead of descriptive names #617 - Descriptive RDS reservation IDs: Reserved DB instances were being named with a generic rds-<type>-<unix-timestamp> ID. Now executePurchase computes a descriptive ID (account/engine/region/size/coverage-aware) up front and threads it through PurchaseOptions.ReservationID into PurchaseCommitment, so the reservation is identifiable in the AWS console and billing exports. generatePurchaseID was also fixed to handle pointer Details types (*DatabaseDetails, *CacheDetails, *ComputeDetails) that the live parser produces, preventing the engine segment from silently dropping out of real purchases.

Closes #615, Closes #616, Closes #617

Out of scope: multi-account execution is tracked separately and intentionally not addressed here.

Verification

  • go build ./... - clean
  • go vet github.com/LeanerCloud/CUDly/cmd github.com/LeanerCloud/CUDly/providers/aws/services/rds - no issues
  • go test github.com/LeanerCloud/CUDly/cmd github.com/LeanerCloud/CUDly/providers/aws/services/rds github.com/LeanerCloud/CUDly/pkg/common - 889 passed
  • Pre-commit hooks (gofmt, go vet, gocyclo, go-sec, trivy) - all passed

Summary by CodeRabbit

  • Bug Fixes

    • Fixed incorrect RDS 3-year no-upfront warning appearing when running with CSV input where payment options are provided per row.
  • Improvements

    • Updated purchase confirmation messaging to reference estimated monthly savings instead of annual savings for improved clarity.
    • Reserved database instances now receive descriptive names at purchase time instead of generic auto-generated names.

Review Change Stack

cristim added 3 commits May 20, 2026 22:44
The EstimatedSavings column returned by the Cost Explorer coverage API
contains a monthly value, and the "Estimated monthly savings" summary
line already says "monthly". The ConfirmPurchase prompt was the only
place that said "annual", which was misleading when the number shown
matches the monthly column. Update the doc comment and the printed
line to say "monthly" so all three surfaces are consistent.

Closes #615
When running with --input-csv, the payment option comes from each
CSV row rather than from the --payment flag (which keeps its default
of no-upfront). The warnRDS3YearNoUpfront validator was firing a
false alarm against the flag default even when every CSV row used
partial-upfront or all-upfront. Return early when CSVInput is set so
the warning only fires in interactive / flag-driven mode.

Closes #616
Thread a descriptive commitment ID through PurchaseOptions.ReservationID
so it reaches the provider and names the reserved instance in the AWS
console and billing exports, rather than using a generic timestamp-based
fallback.

- pkg/common/types.go: add ReservationID field to PurchaseOptions
- cmd/multi_service_helpers.go: compute generatePurchaseID up front in
  executePurchase and pass it as opts.ReservationID; the result.CommitmentID
  fallback reuses the same ID instead of recomputing
- providers/aws/services/rds/client.go: prefer opts.ReservationID when set,
  sanitize it, fall back to the generic rds-<type>-<unix> form when empty
- cmd/main.go: generatePurchaseID now handles pointer Details
  (*DatabaseDetails, *CacheDetails, *ComputeDetails, nil-guarded) so the
  engine/platform segment appears in real purchases where the parser stores
  pointer types; normalization (lowercasing, hyphenation) is consolidated
  after the switch rather than duplicated per case
- tests: update mock expectations from exact PurchaseOptions struct to
  mock.MatchedBy matching on Source, so they tolerate the non-deterministic
  ReservationID; TestExecutePurchase additionally asserts ReservationID is
  non-empty and contains the instance type

Closes #617
@cristim cristim added triaged Item has been triaged priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-sprint Within the current sprint impact/internal Team-internal only effort/s Hours type/bug Defect labels May 20, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: afd47f9c-dbc4-4550-925b-7cc9cbe2218f

📥 Commits

Reviewing files that changed from the base of the PR and between a04604a and 265d660.

📒 Files selected for processing (8)
  • cmd/helpers.go
  • cmd/main.go
  • cmd/multi_service_helpers.go
  • cmd/multi_service_helpers_test.go
  • cmd/multi_service_test.go
  • cmd/validators.go
  • pkg/common/types.go
  • providers/aws/services/rds/client.go

📝 Walkthrough

Walkthrough

This PR fixes three purchase-related issues: descriptive RDS reservation ID generation, incorrect savings label in the confirmation prompt (monthly mislabeled as annual), and a spurious RDS warning in CSV input mode that checks the flag default instead of per-row payment options.

Changes

Descriptive Reservation IDs and Purchase Messaging

Layer / File(s) Summary
PurchaseOptions Contract & Engine Label Extraction
pkg/common/types.go, cmd/main.go
Added ReservationID field to PurchaseOptions; introduced extractEngineLabel helper to safely extract engine/platform from typed Details structs (both value and pointer forms).
Descriptive ID Generation with Normalized Engine
cmd/main.go
generatePurchaseID refactored to use extractEngineLabel to derive engine label, then normalized by lowercasing and replacing whitespace, underscores, and slashes with hyphens.
Purchase Flow: executePurchase & RDS Commitment Integration
cmd/multi_service_helpers.go, providers/aws/services/rds/client.go
executePurchase precomputes descriptive commitmentID and passes it via PurchaseOptions.ReservationID; RDS PurchaseCommitment uses the provided ID (sanitized with rds-reserved- prefix) when set, falling back to generic rds-<type>-<timestamp> value.
Purchase Execution Tests & Mock Updates
cmd/multi_service_helpers_test.go, cmd/multi_service_test.go
TestExecutePurchase captures PurchaseOptions via mock.MatchedBy and validates non-empty ReservationID containing resource type; multiple test scenarios update PurchaseCommitment mock expectations to match on Source field via matcher.
Confirmation Messaging & CSV Warning Guard
cmd/helpers.go, cmd/validators.go
ConfirmPurchase documentation and warning label updated to reference "estimated monthly savings" instead of "estimated annual"; warnRDS3YearNoUpfront exits early when toolCfg.CSVInput is set, preventing spurious warnings based on flag defaults.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • LeanerCloud/CUDly#600: Complements this PR by preserving per-recommendation details in the POST body, which enables the backend to construct and pass descriptive reservation IDs through the purchase flow.
  • LeanerCloud/CUDly#601: Reconstructs DatabaseDetails/CacheDetails/ComputeDetails from CSV Engine/Deployment columns, providing the typed structures that the new extractEngineLabel helper uses to derive normalized engine labels.

Poem

🐰 Hops through the purchase path with glee,
Descriptive names for all to see,
No more "annual" when "monthly" shines,
CSV warnings now align,
Reservation IDs bright and clear!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically summarizes the three main fixes: savings label correction, no-upfront warning suppression, and descriptive RI ID implementation.
Linked Issues check ✅ Passed All code changes directly address the three linked issues: label fix (#615), CSV warning suppression (#616), and descriptive reservation ID threading (#617).
Out of Scope Changes check ✅ Passed All changes are within scope: label/prompt corrections, CSV validation bypass, ID generation/threading, and corresponding test updates match the stated objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/purchase-output-615-616-617

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

@cristim
Copy link
Copy Markdown
Member Author

cristim commented May 20, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

✅ Actions performed

Review triggered.

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.

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

Labels

effort/s Hours impact/internal Team-internal only priority/p2 Backlog-worthy severity/medium Moderate 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