Repository navigation
fix(azure): commitments fabricate State "active" and Region from fields the SDK omits #74
Description
Summary
The same six Azure converters stamp a state of active and the client's own region onto every commitment, but the SDK response type carries neither field. The reservation listing is subscription-wide and unfiltered by region, so a reservation in one region is labelled with whichever region the client was constructed for and matched against recommendations it does not discount. The unconditional active state means an expired or cancelled reservation still counts as live coverage. The grouped sibling finding is that the same converters leave count, start date, end date and cost unset, so coverage arithmetic sees zero committed capacity and every Azure commitment looks long expired.
Location
providers/azure/services/cache/client.go:251(identical incosmosdb/client.go:252,database/client.go:282,search/client.go:197,synapse/client.go:223,managedredis/client.go:223)providers/azure/services/cache/client.go:260(identical in the five sibling converters) (A08b-007)
All at 3c0f8ac94048a2c36fce5ccddee54e6c4849a5cd
Failure scenario
ReservationDetailProperties has no state and no region field, so both values are invented. The reservation listing is subscription-wide and unfiltered by region, so a westeurope reservation returned to a client constructed for eastus is stamped Region: "eastus" and matched against eastus recommendations that it does not discount. State: "active" is unconditional, so an expired or cancelled reservation still counts as live coverage and suppresses a needed repurchase.
The same defect appears at:
A08b-007: Azure commitments never populate Count, StartDate, EndDate or Cost
Evidence
commitment := &common.Commitment{
Provider: common.ProviderAzure,
Account: c.subscriptionID,
CommitmentType: common.CommitmentReservedInstance,
Service: common.ServiceCache,
Region: c.region,
State: "active",
}Suggested fix
Source region and state from an inventory API that reports them (armreservations.ReservationResponse has Location and ProvisioningState), and leave them empty rather than guessing when unavailable.
Found by the 2026-09-02 codebase audit, finding A08b-006, reported by one reviewer and independently confirmed by a second. Full report: docs/audits/codebase-audit-2026-09-02.md.
Activity
cristim commentedon Oct 4, 2026
Source investigation also confirmed the same fabricated region/active-state and missing quantity/date fields in the Compute converter at main 9962786. Filed #190 for that sibling path so a six-converter repair does not leave Compute behind. This is source evidence, not live subscription acceptance; shared inventory scoping and cost semantics still need to be established before implementation.
cristim commentedon Oct 4, 2026
Further source and contract review for #74 and #190 found that replacing the converters alone would leave incorrect matching.
armreservations/v4 v4.0.0SDK exposes actual child ID, location, SKU quantity, provisioning state, benefit start, purchase timestamp, precise expiry, and applied scope.EffectiveDateTimeis the start of the current reservation revision, not the original purchase. Currentpkg/recfilter/dedupe.gofilters recent purchases usingStartDatebefore invoking the provider-specific filter, so those timestamps cannot be conflated.Costscalar has hourly-cost consumers, so assigning an order-level total or inventing zero would not fix the missing-cost contract. The complete repair needs explicit missing-cost semantics without silently changing existing consumers.Sources: cached SDK v4
models.go(Properties,ReservationResponse), timestamp decoding inmodels_serde.go, and the current sharedpkg/recfilter/dedupe.goat main9962786e06951a20d58980954e8024fbf49e2d0c. Official contracts: tenant reservation listing, applied reservation discovery, and benefit scopes.No implementation or live subscription verification is claimed. These findings remain part of the open issue: establish the full scoped inventory/consumer contract, separate purchase and benefit timestamps, settle missing cost and service identity, then verify SDK decoding through the actual consumer with pre-fix failures and independent review. Compute remains tracked in #190.
fix(azure/compute): source reservation inventory fields from the rese…
fix(azure/compute): source reservation inventory fields from the rese…
refactor(azure): move strict reservation inventory checks to the shar…
cristim commentedon Oct 17, 2026
Decision needed (one line): for armreservations-sourced commitments with no historical price, is
Cost = 0acceptable, or should Commitment gain an explicit cost-known marker? Context:convertSavingsPlanis fixed (#494, #498). The six reservation converters (cache, cosmosdb, database, search, synapse, managedredis) still stampRegion: c.regionandState: Activefrom the consumption ReservationDetail API, which has no state, location or dates. The real fix moves them to armreservations, as compute already does throughinternal/reservations/strict.go, after #423 and #439 merge. Safe default: an explicit missing-cost marker, never an order total inCost. First slice: cache plus managedredis, about 300 lines. Markingstatus/needs-info.