Skip to content

fix(azure): collect Synapse recommendations in the provider fan-out - #382

Merged
cristim merged 4 commits into
fix/292-azure-advisor-derive-fieldsfrom
fix/47-azure-wire-synapse
Oct 13, 2026
Merged

cristim merged 4 commits into
fix/292-azure-advisor-derive-fieldsfrom
fix/47-azure-wire-synapse

Conversation

@cristim

@cristim cristim commented Oct 13, 2026

Copy link
Copy Markdown
Member

Refs #47 (wires Synapse; Search and Managed Redis are deliberately left out, see below, so #47 stays open until that is decided)

Stacked on #378 (base fix/292-azure-advisor-derive-fields). Merge order: #366, #378, this.

Per-client check

Evidence

TestGetRecommendations_CollectsSynapseForDataWarehouse is fixture-based (fake client) and does not compile on the parent, which has no Synapse constructor hook. go test ./... in providers/azure passes; pre-commit gocyclo passes (the Advisor-fn fallback was extracted to keep GetRecommendations under the limit).

🤖 Generated with Claude Code

cristim and others added 2 commits October 13, 2026 20:55
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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cristim cristim added priority/p2 Backlog-worthy severity/medium Moderate harm urgency/this-quarter Within the quarter impact/few Limited audience effort/s Hours type/bug Defect labels Oct 13, 2026
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: LeanerCloud/cloud-commitments-go/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 00ee7b9b-cbb5-46b9-9a39-36aa0f2b0efe

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · 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 13, 2026

Copy link
Copy Markdown
Member Author

Independent review (claude-opus-5-5) of 479eddb: APPROVE

Scope: this PR's own diff against its parent #378 (2673415), commits 57168a5 and 479eddb. Review only; no Azure calls were needed for this diff.

Evidence (local, fresh clone, macOS, fixture-based):

  • Final tree at 479eddb: go vet ./... and go test ./... in providers/azure pass; GOWORK=off go build ./... passes for pkg, providers/aws, providers/azure and providers/gcp; gofmt -l clean; misspell (US locale) clean on the changed file.
  • The intermediate commit 57168a5 is not what lands; the final tree builds and tests clean.
  • Mutation: forcing includeSynapse to false makes TestGetRecommendations_CollectsSynapseForDataWarehouse fail, so the wiring test is not vacuous.
  • Synapse results join mergeServiceResults as an attempted service (includeSynapse), so a Synapse failure counts toward the all-attempted-failed guard. The Synapse client returns an error on page errors and the page cap, so it never yields a silent partial.

Non-blocking:

  1. providers/azure/recommendations.go:113 still says "All six service calls"; there are now seven goroutines.
  2. Search and Managed Redis staying unwired is stated only in the comment at recommendations.go:195-196 ("see fix(azure): the recommendations aggregator never calls managedredis, search or synapse #47"); fine as long as fix(azure): the recommendations aggregator never calls managedredis, search or synapse #47 tracks it.

Gate notes (not findings against this diff):

cristim and others added 2 commits October 13, 2026 21:36
…he GetRecommendations doc

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cristim

cristim commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Independent review (claude-opus-5-5) of 87db9c8: APPROVE

Re-review against parent #378 (462df7e). Merge-base = 462df7e. Review only.

  • The doc comment now reads "All seven service calls" (recommendations.go:113).
  • Synapse is stubbed (newSynapseClientFn = newFakeFn(...), restored in cleanup) in the fan-out tests that used the real client.
  • Network check: I made the real newSynapseClientFn panic and ran the whole package. Exactly one test still constructs it: TestRecommendationsClientAdapter_GetRecommendations_PropagatesContextCancellation (recommendations_test.go:344). That test runs every real client on a context canceled before the call, and the Synapse loop checks ctx.Err() before NextPage (services/synapse/client.go:155-157), so it returns without a request. No test reaches the network through Synapse. The same pattern for the other real clients in that test predates this PR.
  • Evidence (local, fresh clone, macOS): go vet and go test ./... in providers/azure pass. Forcing includeSynapse false fails TestGetRecommendations_CollectsSynapseForDataWarehouse.
  • CI has not run on this head, because the base is the fix(azure): derive Advisor fields from the payload and fail loud on truncation #378 branch. Fresh green CI on the exact head is required after retarget.

Non-blocking: if strict isolation is wanted, stubbing Synapse in PropagatesContextCancellation too would make the test independent of the client's ctx check.

@cristim
cristim merged commit 23e587d into fix/292-azure-advisor-derive-fields Oct 13, 2026
1 check passed
cristim added a commit that referenced this pull request Oct 13, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/few Limited audience priority/p2 Backlog-worthy severity/medium Moderate harm type/bug Defect urgency/this-quarter Within the quarter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant