microsoft / microsoft/finops-toolkit
Costs commitment discount eligibility columns are always empty but documented as available
Nobody has claimed this yet.
- Dominant language
- PowerShell
- Stars
- 603
- Forks
- 249
- Avg merge
- 7d 11h
- Merged PRs (30d)
- 11
Description
🐛 Problem
x_CommitmentDiscountSpendEligibility and x_CommitmentDiscountUsageEligibility are declared in the FOCUS 1.2 Costs schema, projected by Costs_v1_2(), surfaced as Power BI fields, and documented as charge-level values — but the transform hard-codes both to an empty string. Anyone who follows the documentation gets blanks and no error.
// Costs_transform_v1_2, IngestionSetup_v1_2.kql
x_CommitmentDiscountSpendEligibility = '', // TODO: Add x_CommitmentDiscountSpendEligibility for Costs
x_CommitmentDiscountUsageEligibility = '', // TODO: Add x_CommitmentDiscountUsageEligibility for Costs
In FOCUS 1.0 the Costs dataset doesn't define the columns at all — they exist only on the Prices side. So the two versions disagree as well.
Where the columns are advertised
| Component | Behavior | Source |
|---|---|---|
| Costs transform, FOCUS 1.2 | Sets both to '' |
IngestionSetup_v1_2.kql#L796-L797 |
| Costs table schema, FOCUS 1.2 | Declares both columns | IngestionSetup_v1_2.kql#L992-L993 |
Costs_v1_2() query function |
Projects both columns | HubSetup_v1_2.kql#L277-L278 |
| Costs transform, FOCUS 1.0 | Columns absent entirely | IngestionSetup_v1_0.kql |
| Data dictionary | "…are eligible for this charge. Derived from the Prices dataset." | data-dictionary.md#L84 |
| Hubs data model | Listed under Costs managed dataset | data-model.md#L305-L306 |
| Power BI KQL dataset | Columns bound to Costs_v1_2 |
Costs.tmdl#L1724 |
| Copilot Studio agent knowledge | Documented for Costs_v1_2() |
schema-reference.md#L126-L127 |
The two agent-facing surfaces are the most likely to hit this: the Copilot Studio knowledge file tells the agent both columns are available on Costs_v1_2(), and the Power BI field list shows them alongside populated columns.
👣 Repro steps
-
Deploy a FinOps hub and ingest cost data.
-
Run the following against the hub database:
Costs_v1_2() | summarize Rows = count() by x_CommitmentDiscountSpendEligibility, x_CommitmentDiscountUsageEligibility -
A single row is returned, with both values empty.
-
Run the same summarize against
Prices_v1_2()for comparison — it returnsEligible/Not Eligible.
🤔 Expected
Either behavior would be consistent; today's is not:
- Populate them. Look the meter's eligibility up per cost row, the same way the Prices side resolves it. This is already tracked as an unchecked item in #1111 under Costs (FOCUS cost): "Feature: Add CommitmentDiscountSpend/UsageEligibility".
- Or stop advertising them. Drop the columns from the Costs schema,
Costs_v1_2(), the Power BI dataset, the data dictionary, the data model, and the agent knowledge file, so nothing offers a column that is always blank.
If populating them is the plan but not imminent, an interim note in the data dictionary and the agent knowledge file would stop consumers building on an empty column.
ℹ️ Additional context
- This issue covers only the discoverability mismatch — documented and exposed versus always empty. The implementation itself is the existing #1111 line item; splitting it out here because the docs, Power BI, and agent surfaces need attention regardless of when the transform is filled in.
- #2279 (PR #2284) corrects the direction of these columns on the Prices side and in the open data file. It doesn't change the Costs side, and it isn't blocked by this.
- Draft PR #2246 adds a
CommitmentDiscountEligibilityADX table loaded from the Commitment discount eligibility open data file. If that merges, populating the Costs side becomes a lookup against that table, so the two are worth sequencing together. - #1593 (closed) covered the related case of the Prices column always reading
Not eligible.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the provided Costs_v1_2() and Prices_v1_2() summarize queries, then inspect the hard-coded fields in IngestionSetup_v1_2.kql and their projections in HubSetup_v1_2.kql. Compare the exposed fields across Costs.tmdl, data-dictionary.md, data-model.md, and schema-reference.md. Done means the Costs behavior and all advertised surfaces consistently reflect the chosen populate-or-remove direction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure
- Domain
- backend-api-design, data, documentation
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100