Skip to content

audit(reshape): verify CE-driven cross-family alternatives (closes #152) - #814

Merged
cristim merged 3 commits into
mainfrom
fix/152-wave6
Jul 19, 2026
Merged

cristim merged 3 commits into
mainfrom
fix/152-wave6

Conversation

@cristim

@cristim cristim commented May 28, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Audits fillAlternativesFromRecs / passesDollarUnitsCheck / termMatchesIfKnown against all five AWS RI Exchange API rules (convertible class, same region, same term, dollar-units, platform scope)
  • Adds exchange-alternatives-audit.md at repo root with: old peerFamilyGroups allowlist diff, per-delta classification, and a no-tightening verdict
  • Extends pkg/exchange/reshape_crossfamily_test.go with three audit fixtures: cross-group surface (m5 sees c5/r5), new-gen family surface (m8g absent from old allowlist), dollar-units pre-filter blocks a sub-threshold offering

Test plan

  • go build ./... passes
  • go test github.com/LeanerCloud/CUDly/pkg/exchange/... github.com/LeanerCloud/CUDly/internal/api/... passes (1413 tests, +3 from baseline)
  • Read exchange-alternatives-audit.md verdict: no predicate tightening required

Summary by CodeRabbit

  • Documentation

    • Added comprehensive audit documentation covering AWS Reserved Instance exchange alternatives, validation rules, and acceptance criteria.
  • Tests

    • Added test cases validating cross-family and cross-group exchange alternatives are properly surfaced.
    • Added test coverage ensuring newer generation families are correctly handled in exchange scenarios.
    • Added validation tests confirming cost-based filtering rules are applied correctly to alternative recommendations.

@cristim cristim added triaged Item has been triaged priority/p3 Polish / idea / may never ship severity/low Minor harm urgency/this-quarter Within the quarter impact/internal Team-internal only effort/m Days type/chore Maintenance / non-user-visible labels May 28, 2026
@coderabbitai

coderabbitai Bot commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

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: 4 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: fc4499f7-56ff-4df7-b90d-ff0eae8bcf5b

📥 Commits

Reviewing files that changed from the base of the PR and between 61bd1f9 and f808083.

📒 Files selected for processing (1)
  • exchange-alternatives-audit.md
📝 Walkthrough

Walkthrough

Adds a markdown audit document (exchange-alternatives-audit.md) analyzing the replacement of a hand-curated peerFamilyGroups allowlist with CE-driven cross-family alternatives, including AWS exchange rules, delta analysis, and a predicate verdict. Three new fixture-driven tests in pkg/exchange/reshape_crossfamily_test.go implement the fixture set (A–E) described in that document.

Changes

RI Exchange Alternatives Audit and Fixture Tests

Layer / File(s) Summary
Audit document: allowlist → CE-driven predicate
exchange-alternatives-audit.md
New markdown document enumerating AWS GetReservedInstancesExchangeQuote acceptance rules, contrasting old allowlist vs CE-driven predicate behavior, delta analysis, a verdict on predicate correctness, and the named fixture set A–E mapped to test cases.
Fixture tests: cross-family surfacing and dollar-units pre-filter
pkg/exchange/reshape_crossfamily_test.go
Adds TestAudit_CrossGroupAlternativesSurface (m5.xlarge → c5.large + r5.large, ordered cheapest-first), TestAudit_NewGenerationFamilySurfaces (m8g.large surfaces without allowlist exclusion), and TestAudit_DollarUnitsPreFilterBlocksInvalidAlternative (c5.medium fails dollar-units check, empty AlternativeTargets).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

urgency/eventually, type/docs

Poem

A rabbit once counted the families with care,
Old allowlists removed — CE rules now are there!
From m5 to c5, or r5 they hop,
m8g joins the warren, no gatekeeper to stop,
Dollar-units must pass or the path goes kerplop. 🐇✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: auditing the verification of CE-driven cross-family alternatives, which aligns with the documentation audit and test fixtures added in the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/152-wave6

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

@cristim

cristim commented May 28, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor
✅ 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.

@cristim

cristim commented May 30, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@cristim

cristim commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Rate Limit Exceeded

@cristim have exceeded the limit for the number of chat messages per hour. Please wait 39 minutes and 0 seconds before sending another message.

cristim commented Jun 7, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review


Generated by Claude Code

@coderabbitai

coderabbitai Bot commented Jun 7, 2026 •

Copy link
Copy Markdown
Contributor

@cristim: Triggering a full review of PR #814 now.


🧠 Learnings used
Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-05-05T15:44:54.463Z
Learning: In the LeanerCloud/CUDly repository, when a CodeRabbit review flags something as "outside-diff" that was already implemented in an earlier commit of the same PR, it is likely a stale-snapshot artifact where the review diff was generated against a pre-fix view. The inline comment convention `(CR pass on PR #<number> Finding N)` is used by the maintainer (cristim) to mark lines that were changed in direct response to a prior CodeRabbit review pass.

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-07T19:32:26.182Z
Learning: In LeanerCloud/CUDly `providers/aws/services/rds/client.go`, `findOfferingID` validates AZConfig with a switch that has a `default: error` case covering non-empty invalid values (e.g. "typo-az"), not just an empty-string check. A bad non-empty AZConfig previously fell through to `multiAZ==false` in `paginateRDSOfferings` (same mis-buy as the old default). Fixed in PR `#1085` commit 681fd9e81. Regression test added.

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-07T18:13:37.445Z
Learning: In LeanerCloud/CUDly `providers/gcp/services/computeengine/client.go`, `convertGCPRecommendation` no longer hardcodes `Term = "1yr"` (fixed in PR `#1047` commit 8f9a787, H-3 audit finding). It propagates `params.Term` with a `"1yr"` default, validates via `termPlan`, and returns nil on unknown term. This is stricter than memorystore/cloudstorage/cloudsql (which default and continue): computeengine returns nil on unknown term because it is on the purchase path. Regression tests: `TestConvertGCPRecommendation_PropagatesParamsTerm`, `TestConvertGCPRecommendation_RejectsUnknownTerm`.

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-07T17:45:38.069Z
Learning: In LeanerCloud/CUDly `providers/gcp/services/cloudsql/client.go`, `getSQLPricing` had the same per-hour/term-total unit mismatch as memorystore and cloudstorage: `commitmentPrice` (per-hour SKU rate) was passed directly to savings math that expected a term total, producing ~99.99% savings, and `HourlyRate` was set to `per-hour / hoursInTerm` (near-zero). Fixed in PR `#1047` commit 20590c6b4 (issue `#1078` folded in): `commitmentPriceTerm := commitmentPrice * hoursInTerm`; `HourlyRate = commitmentPrice` (raw per-hour). `convertGCPRecommendation` also hardcoded `rec.Term = "1yr"`, ignoring `params.Term`; fixed with same defaulting pattern as memorystore/cloudstorage. Regression tests: `TestGetSQLPricing_CommitmentPriceIsTermTotal` and `TestCloudSQLConvertGCPRecommendation_PropagatesTermFromParams`. PaymentOption was already correct (`if paymentOption == "" { paymentOption = "monthly" }`).

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-07T19:32:26.182Z
Learning: In LeanerCloud/CUDly `providers/aws/recommendations/parser_services.go`, `parseRDSDetails` uses an exhaustive switch on `DeploymentOption`: "Multi-AZ" maps to "multi-az", "Single-AZ" maps to "single-az", nil leaves AZConfig unset, and any other non-nil value returns an error. Silent defaulting to "single-az" for unknown values was removed in PR `#1085` commit 681fd9e81. Regression test added.

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-07T17:38:19.433Z
Learning: In LeanerCloud/CUDly GCP service converters (`convertGCPRecommendation` in memorystore/client.go and cloudstorage/client.go), `rec.Term` must be derived from `params.Term` with a `"1yr"` default — not hardcoded to `"1yr"`. Without this, 3-year callers always emit 1-year commitments even though the downstream `termYears` derivation from `rec.Term` is correct. Fixed in PR `#1047` commit c6280c390 (F2 for memorystore, F4 for cloudstorage). Regression tests: `TestConvertGCPRecommendation_PropagatesTermFromParams` and `TestCloudStorageConvertGCPRecommendation_PropagatesTermFromParams`.

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-07T17:38:19.433Z
Learning: In LeanerCloud/CUDly `providers/gcp/services/computeengine/client.go`, `convertGCPRecommendation` must force `paymentOption = "monthly"` unconditionally (logging a WARN when a non-monthly value such as "upfront", "all-upfront", or "partial-upfront" is supplied) because GCP CUDs are monthly-only and any non-monthly value passed through would be a silent misconfiguration. Fixed in PR `#1047` commit c6280c390 (F1). Regression test: `TestConvertGCPRecommendation_NonMonthlyPaymentOptionForcedToMonthly`.

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-07T18:28:28.139Z
Learning: In LeanerCloud/CUDly `providers/gcp/recommendations.go`, `collectRegion` fans out to all four GCP service clients (computeengine, cloudsql, memorystore, cloudstorage) concurrently (fixed in PR `#1047` commit 95a390f, H-2 finding). `regionResult` gains `cache` and `storage` slices; merge is updated accordingly. The decision was to wire (not trim) memorystore and cloudstorage because both have complete `GetRecommendations` implementations and their no-op `PurchaseCommitment` paths are orthogonal to surfacing advisory recommendations. Regression tests: `TestRegionResult_HasCacheAndStorageFields` and `TestShouldIncludeService_Cache_Storage`.

Learnt from: cristim
Repo: LeanerCloud/CUDly PR: 0
File: :0-0
Timestamp: 2026-06-07T19:32:26.182Z
Learning: In LeanerCloud/CUDly `providers/aws/services/rds/client.go`, `normalizeEngineName` uses `==` (not `strings.Contains`) for oracle and sqlserver checks. Edition-qualified tokens (oracle-se2, oracle-ee, sqlserver-se, sqlserver-web, sqlserver-ex, etc.) must pass through as valid RDS ProductDescription values. Using Contains was self-contradictory: the error message told callers to supply the exact edition tokens. Fixed in PR `#1085` commit 681fd9e81. `TestNormalizeEngineName_EditionTokensPassThrough` covers 10 edition variants.
✅ Action performed

Full review finished.

@cristim

cristim commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 8, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Full review finished.

@cristim
cristim changed the base branch from feat/multicloud-web-frontend to main June 9, 2026 15:45
@cristim

cristim commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 19, 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@exchange-alternatives-audit.md`:
- Around line 122-123: The heading for Fixture C is split across two lines
(lines 122-123), which causes incorrect Markdown parsing and lint errors.
Combine the entire heading text "### Fixture C: dollar-units false positive at
CE layer is caught at exchange time, not recommendation time" onto a single
line, and then add a blank line after this heading before any body text follows
to ensure proper Markdown formatting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 45c8d0ee-adc6-4122-b0fd-06a1155e4c7f

📥 Commits

Reviewing files that changed from the base of the PR and between 451a70f and 61bd1f9.

📒 Files selected for processing (2)
  • exchange-alternatives-audit.md
  • pkg/exchange/reshape_crossfamily_test.go

Comment thread exchange-alternatives-audit.md Outdated
@cristim

cristim commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 19, 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.

@cristim

cristim commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 9, 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.

@cristim

cristim commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 10, 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.

cristim added 3 commits July 17, 2026 21:20
The peerFamilyGroups allowlist removed in 1d76df7 was both too
restrictive (prevented cross-group exchanges like m5->c5 that AWS
would accept) and too narrow (missed new-gen families like m8g). The
CE-driven path is correct: term-match + dollar-units guards together
enforce the same rules as GetReservedInstancesExchangeQuote without a
per-pair API call.

Add docs/exchange-alternatives-audit.md: full diff of old allowlist vs
CE approach, classification of each delta, and verdict (no predicate
tightening required).

Extend reshape_crossfamily_test.go with three audit fixtures (#152):
- cross-group alternatives surface (m5 sees c5/r5)
- new-generation family surfaces (m8g, absent from old allowlist)
- dollar-units pre-filter blocks an offering AWS would reject
The comment referenced docs/exchange-alternatives-audit.md but the file
sits at the repo root as exchange-alternatives-audit.md.
The Fixture C heading wrapped onto a second line, so Markdown parsed the
continuation as body text and markdownlint flagged a missing blank line
after the heading. Keep the heading on one line.
@cristim
cristim merged commit 6d42551 into main Jul 19, 2026
19 checks passed
@cristim
cristim deleted the fix/152-wave6 branch July 27, 2026 11:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/m Days impact/internal Team-internal only priority/p3 Polish / idea / may never ship severity/low Minor harm triaged Item has been triaged type/chore Maintenance / non-user-visible urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant