Repository navigation
fix(azure): derive Advisor fields from the payload and fail loud on truncation - #378
Conversation
… fail loud on truncation Only subscription-scoped reservation and Savings Plan Advisor recommendations are converted; resize and shutdown recommendations are no longer emitted as RI purchases with count 0. Commitment type, term, SKU and quantity come from the extended properties and a missing or unknown value is skipped with a recorded reason instead of defaulting. A page cap or page error now surfaces as a PartialResultError rather than a silently partial list. Refs #292 Refs #252 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
…s client covers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…visor-derive-fields
…visor converter Advisor routinely returns reservations for services this collector does not price; recording them as skips made nearly every subscription partial. Savings Plan rows now use ServiceSavingsPlansAll, the savings amount guard tests are restored, and the now-unused extractServiceType is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review (claude-opus-5-5) of 462df7e: APPROVE Re-review against parent #366 (2de6006). Merge-base = 2de6006. Review only. Source of truth for the extended-property keys:
My earlier findings are resolved:
Evidence (local, fresh clone, macOS, fixture-based):
Non-blocking:
|
…overs #378, #382) (#400) * fix(azure): surface skipped consumption recommendations as a typed partial-result error A non-USD billing currency or an unpriceable SKU was dropped with only a log line, so an EUR or GBP account looked like it had no savings. The skips are now recorded on a context-carried SkipLog and returned from GetRecommendations as *PartialResultError alongside the recommendations that did succeed. Closes #362 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(azure): derive Advisor recommendation fields from the payload and fail loud on truncation Only subscription-scoped reservation and Savings Plan Advisor recommendations are converted; resize and shutdown recommendations are no longer emitted as RI purchases with count 0. Commitment type, term, SKU and quantity come from the extended properties and a missing or unknown value is skipped with a recorded reason instead of defaulting. A page cap or page error now surfaces as a PartialResultError rather than a silently partial list. Refs #292 Refs #252 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(azure): drop Advisor Savings Plan rows the Benefit Recommendations client covers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(azure): keep a subscription's recommendations when its error is a partial result PartialResultError was only reachable from the internal package and the multi-subscription merge counted any error as a failed subscription, dropping its recommendations. Export the type and AsPartialResult, give it a Partial() method, and aggregate skips across subscriptions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(azure): ignore unmapped Advisor reservation types and tidy the Advisor converter Advisor routinely returns reservations for services this collector does not price; recording them as skips made nearly every subscription partial. Savings Plan rows now use ServiceSavingsPlansAll, the savings amount guard tests are restored, and the now-unused extractServiceType is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(azure): collect Synapse recommendations in the provider fan-out (#382) * fix(azure): collect Synapse recommendations in the provider fan-out The Synapse client was complete and tested but never called from GetRecommendations. Search and Managed Redis stay out: Search has no valid Consumption resource type and no reservation prices (#197), and Managed Redis queries the same RedisCache resource type as the cache client, so wiring it would emit the same recommendations twice. Refs #47 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(azure): repair merge of the Synapse wiring onto the Advisor branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(azure): stub the Synapse client in the adapter fan-out tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * fix(azure): satisfy lint in the Advisor converter Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Closes #292
Refs #252 (item 1, the Advisor page cap; the subscription cap and the other uncapped pagers stay open)
Stacked on #366 (needs
azrecs.SkipLog/RecordSkip). Base isfix/azure-consumption-skips-loud; merge #366 first, then retarget this to main.Root cause (providers/azure/recommendations.go, at e9a33bb)
convertAdvisorRecommendationhardcodedCommitmentReservedInstance,Term: "1yr",PaymentOption: "upfront"and letextIntdefaultqtysilently, so resource-level resize/shutdown recommendations (Microsoft.Computeimpacted field) became RI purchase rows with no SKU and Count 0 (fix(azure): advisor rightsizing and shutdown recs emitted as ri purchase recs with count 0 #292).collectAdvisorRecommendationsbroke out of the loop on the 50-page cap or a page error and returned(recs, nil)(fix(azure): Advisor page cap returns partial results as complete; subscriptions cap size unproven #252).Change
reservedResourceType) and Savings Plan (recommendationSubCategory) recommendations are converted; others are ignored. An unmappablereservedResourceTypeis a recorded skip.savings-plan, else RI. Term fromterm(P1Y/P3Y, or1yr/3yr). Savings must carrysavingsCurrency= USD. Reservations requireskuand a positiveqty. Anything absent or unknown is skipped and recorded, surfacing as thePartialResultErrorfrom fix(azure): surface skipped consumption recommendations as a typed partial-result error #366.errAdvisorTruncated, whichGetRecommendationsreports through the samePartialResultError.ExtendedPropertiesasmap[string]*string, so keys are not in the SDK.annualSavingsAmount,savingsCurrency,term,lookbackPeriodare the names in Microsoft's Advisor Resource Graph samples;reservedResourceType,recommendationSubCategory,sku,qtyare the keys the collector already used. I could not confirm them against a live payload.Savings Plan overlap with go#373
dropCoveredAdvisorSavingsPlansdrops an Advisor SavingsPlan row when the savings-plan client returned an SP row for the same (account, term). It keys instead of dropping all Advisor SP rows so advice survives when the Benefit Recommendations source returns nothing (or #373 is not merged yet), and the Benefit row wins because it carries the commitment amount. Test:TestGetRecommendations_AdvisorSavingsPlanDedupedAgainstBenefitRecs. The key does not distinguish multiple SP rows for one term (e.g. different scopes); if #373 emits several, the key needs a scope field.Not done, with reason
RecurringMonthlyCoststays nil (unknown).CommitmentCostis a plain float64, so unknown can only be 0; representing that needs apkg/commonchange, which is the architect's. Pricing from the retail catalog was left out of scope.Evidence (fixture-based, built from armadvisor types; no live Advisor data)
New tests cover derivation, rejection of each unknown or missing value, the non-purchase filter, nil recurring cost, and truncation surfacing through
GetRecommendations. The old tests assertingTerm == "1yr"andPaymentOption == "upfront"for a no-SKU compute recommendation were removed. They encoded the bug, and the new tests do not compile against the old signatures, so there is no meaningful before-run.go test ./...in providers/azure passes,go vetandGOWORK=off go build ./...are clean, and pre-commit gocyclo passes.🤖 Generated with Claude Code