🐛 Problem
The columns x_CommitmentDiscountSpendEligibility and x_CommitmentDiscountUsageEligibility carry the wrong values. Their meanings are swapped.
FOCUS defines CommitmentDiscountCategory with two values:
Usage means the commitment is based on a usage quantity. A reservation is a usage commitment.
Spend means the commitment is based on an amount of money. A savings plan is a spend commitment.
The toolkit sets the eligibility columns the other way round:
x_CommitmentDiscountSpendEligibility reports reservation pricing.
x_CommitmentDiscountUsageEligibility reports savings plan pricing.
A user who reads these columns with the FOCUS definition gets the opposite answer.
The toolkit also disagrees with itself. Two components use the FOCUS definition. Three components use the swapped one. The list is in the table below.
Where the swap occurs
The clearest example sits inside one file. IngestionSetup_v1_2.kql sets CommitmentDiscountCategory correctly on line 89. It then sets the two eligibility columns with the opposite mapping on line 98. Ten lines separate the two blocks.
// Line 89 to 93 -- correct, matches FOCUS
| extend CommitmentDiscountCategory = case(
x_SkuPriceType == 'ReservedInstance', 'Usage',
x_SkuPriceType == 'SavingsPlan', 'Spend',
''
)
//
// Line 96 to 99 -- swapped
// TODO: Check this to ensure it's correct
| extend x_CommitmentDiscountSpendEligibility = iff(x_SkuMeterId in (riMeters) and x_SkuPriceType != 'ReservedInstance', 'Eligible', 'Not Eligible')
| extend x_CommitmentDiscountUsageEligibility = iff(x_SkuMeterId in (spMeters), 'Eligible', 'Not Eligible')
Line 97 already carries the comment // TODO: Check this to ensure it's correct.
👣 Repro steps
Meter 00020329-e657-5687-9d1a-0be9876e5116 shows the effect. It is a Azure_Redis_Cache_Enterprise_E100 SKU. The open data documentation uses this same meter as its sample row.
-
Query the Azure Retail Prices API for that meter. Include the preview API version. The default version omits the savingsPlan field, and every meter then looks ineligible.
https://prices.azure.com/api/retail/prices?api-version=2023-01-01-preview&meterRegion='primary'&$filter=meterId eq '00020329-e657-5687-9d1a-0be9876e5116'
-
Read the response. The meter has two Reservation items. The meter has one Consumption item, and that item has an empty savingsPlan array. The meter therefore has reservation pricing and no savings plan pricing.
-
Open CommitmentDiscountEligibility.csv and find the same meter.
-
Compare the two results.
| Column |
Value in the file |
What FOCUS says it should be |
x_CommitmentDiscountSpendEligibility |
Eligible |
Not Eligible — the meter has no savings plan pricing |
x_CommitmentDiscountUsageEligibility |
Not Eligible |
Eligible — the meter has reservation pricing |
I checked six meters this way. All six show the same swap.
🤔 Expected
The columns follow the FOCUS definition:
x_CommitmentDiscountSpendEligibility reports savings plan pricing.
x_CommitmentDiscountUsageEligibility reports reservation pricing.
All five components then agree with each other and with FOCUS.
ℹ️ Additional context
This is not a new defect. The behavior is present since the dataset shipped in v14. PR #2251 rewrote the fetch logic in the open data script. It did not change this mapping. PR #2278 refreshes the data with the same mapping.
A fix breaks existing consumers. The column names stay the same and the values change. Any report, query, or dashboard that reads these columns today produces different results after the fix. The change therefore needs a release note and a version boundary.
The scope is larger than the open data file. A fix must cover the four swapped components in the table above. The best practice query already uses the correct mapping and needs no change.
Sources
🐛 Problem
The columns
x_CommitmentDiscountSpendEligibilityandx_CommitmentDiscountUsageEligibilitycarry the wrong values. Their meanings are swapped.FOCUS defines
CommitmentDiscountCategorywith two values:Usagemeans the commitment is based on a usage quantity. A reservation is a usage commitment.Spendmeans the commitment is based on an amount of money. A savings plan is a spend commitment.The toolkit sets the eligibility columns the other way round:
x_CommitmentDiscountSpendEligibilityreports reservation pricing.x_CommitmentDiscountUsageEligibilityreports savings plan pricing.A user who reads these columns with the FOCUS definition gets the opposite answer.
The toolkit also disagrees with itself. Two components use the FOCUS definition. Three components use the swapped one. The list is in the table below.
Where the swap occurs
Update-CommitmentDiscountEligibility.ps1#L642-L643open-data.md#L170-L171IngestionSetup_v1_0.kql#L99-L100IngestionSetup_v1_2.kql#L98-L99compute.md#L186-L188The clearest example sits inside one file.
IngestionSetup_v1_2.kqlsetsCommitmentDiscountCategorycorrectly on line 89. It then sets the two eligibility columns with the opposite mapping on line 98. Ten lines separate the two blocks.Line 97 already carries the comment
// TODO: Check this to ensure it's correct.👣 Repro steps
Meter
00020329-e657-5687-9d1a-0be9876e5116shows the effect. It is aAzure_Redis_Cache_Enterprise_E100SKU. The open data documentation uses this same meter as its sample row.Query the Azure Retail Prices API for that meter. Include the preview API version. The default version omits the
savingsPlanfield, and every meter then looks ineligible.Read the response. The meter has two
Reservationitems. The meter has oneConsumptionitem, and that item has an emptysavingsPlanarray. The meter therefore has reservation pricing and no savings plan pricing.Open
CommitmentDiscountEligibility.csvand find the same meter.Compare the two results.
x_CommitmentDiscountSpendEligibilityEligibleNot Eligible— the meter has no savings plan pricingx_CommitmentDiscountUsageEligibilityNot EligibleEligible— the meter has reservation pricingI checked six meters this way. All six show the same swap.
🤔 Expected
The columns follow the FOCUS definition:
x_CommitmentDiscountSpendEligibilityreports savings plan pricing.x_CommitmentDiscountUsageEligibilityreports reservation pricing.All five components then agree with each other and with FOCUS.
ℹ️ Additional context
This is not a new defect. The behavior is present since the dataset shipped in v14. PR #2251 rewrote the fetch logic in the open data script. It did not change this mapping. PR #2278 refreshes the data with the same mapping.
A fix breaks existing consumers. The column names stay the same and the values change. Any report, query, or dashboard that reads these columns today produces different results after the fix. The change therefore needs a release note and a version boundary.
The scope is larger than the open data file. A fix must cover the four swapped components in the table above. The best practice query already uses the correct mapping and needs no change.
Sources
UsageandSpendforCommitmentDiscountCategorycommitmentdiscountcategory.mdUsage, savings plan maps toSpenddocs-mslearn/focus/mapping.md#L80-L81docs-mslearn/focus/convert.md#L46docs-mslearn/focus/metadata.md#L51