Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/queries/catalog/commitment-utilization-score.kql
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ let commitmentRows = materialize(
| where isnotempty(CommitmentDiscountId)
| extend x_CommitmentDiscountUtilizationPotential = case(
ChargeCategory == 'Purchase', toreal(0),
ProviderName == 'Microsoft' and isnotempty(CommitmentDiscountCategory), toreal(EffectiveCost),
// HostProviderName (FOCUS 1.4) = infrastructure provider; replaces the removed ProviderName for "is this Microsoft-billed data" checks
HostProviderName == 'Microsoft' and isnotempty(CommitmentDiscountCategory), toreal(EffectiveCost),
CommitmentDiscountCategory == 'Usage', toreal(ConsumedQuantity),
CommitmentDiscountCategory == 'Spend', toreal(EffectiveCost),
toreal(0))
Expand Down
3 changes: 2 additions & 1 deletion src/queries/catalog/costs-enriched-base.kql
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ Costs()
| extend x_CommitmentDiscountKey = iff(tmp_IsVMUsage and isnotempty(x_SkuDetails.ServiceType), strcat(x_SkuDetails.ServiceType, x_SkuMeterId), '')
| extend x_CommitmentDiscountUtilizationPotential = case(
ChargeCategory == 'Purchase', toreal(0),
ProviderName == 'Microsoft' and isnotempty(CommitmentDiscountCategory), toreal(EffectiveCost),
// HostProviderName (FOCUS 1.4) = infrastructure provider; replaces the removed ProviderName for "is this Microsoft-billed data" checks
HostProviderName == 'Microsoft' and isnotempty(CommitmentDiscountCategory), toreal(EffectiveCost),
CommitmentDiscountCategory == 'Usage', toreal(ConsumedQuantity),
CommitmentDiscountCategory == 'Spend', toreal(EffectiveCost),
toreal(0)
Expand Down
5 changes: 3 additions & 2 deletions src/queries/catalog/top-other-transactions.kql
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
//
// Output:
// Each row represents a single cost record for a non-commitment purchase, with key financial and allocation metadata.
// Columns: ChargePeriodStart, ChargeCategory, BilledCost, BillingCurrency, SubAccountName, x_InvoiceSectionName, PricingCategory, PricingQuantity, PricingUnit, ProviderName, PublisherName
// Columns: ChargePeriodStart, ChargeCategory, BilledCost, BillingCurrency, SubAccountName, x_InvoiceSectionName, PricingCategory, PricingQuantity, PricingUnit, ServiceProviderName
// Note: ServiceProviderName (FOCUS 1.4) identifies the vendor (Marketplace publisher or Microsoft) and replaces the removed ProviderName/PublisherName columns.
//
// Usage:
// Use this query to analyze miscellaneous Azure purchases that are not usage-based and not covered by Reserved Instances or Savings Plans.
Expand All @@ -24,4 +25,4 @@ let endDate = startofmonth(now());
Costs()
| where ChargePeriodStart >= startDate and ChargePeriodStart < endDate and tolower(tostring(ChargeCategory)) != 'usage' and isempty(CommitmentDiscountType) and toreal(BilledCost) > 0
| top N by toreal(BilledCost)
| project ChargePeriodStart, ChargeCategory, BilledCost, BillingCurrency, SubAccountName, x_InvoiceSectionName, PricingCategory, PricingQuantity, PricingUnit, ProviderName, PublisherName
| project ChargePeriodStart, ChargeCategory, BilledCost, BillingCurrency, SubAccountName, x_InvoiceSectionName, PricingCategory, PricingQuantity, PricingUnit, ServiceProviderName
7 changes: 4 additions & 3 deletions src/queries/finops-hub-database-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ Costs()
| extend x_CommitmentDiscountKey = iff(tmp_IsVMUsage and isnotempty(x_SkuDetails.ServiceType), strcat(x_SkuDetails.ServiceType, x_SkuMeterId), '')
| extend x_CommitmentDiscountUtilizationPotential = case(
ChargeCategory == 'Purchase', real(0),
ProviderName == 'Microsoft' and isnotempty(CommitmentDiscountCategory), EffectiveCost,
// HostProviderName (FOCUS 1.4) = infrastructure provider; replaces the removed ProviderName for "is this Microsoft-billed data" checks
HostProviderName == 'Microsoft' and isnotempty(CommitmentDiscountCategory), EffectiveCost,
CommitmentDiscountCategory == 'Usage', ConsumedQuantity,
CommitmentDiscountCategory == 'Spend', EffectiveCost,
real(0)
Expand Down Expand Up @@ -399,21 +400,21 @@ The following table lists the columns produced in the `All available columns` qu
| ContractedCost | real | Negotiated cost for the resource or usage. |
| ContractedUnitPrice | real | Negotiated unit price for the resource. |
| EffectiveCost | real | Actual cost after all discounts and credits. |
| HostProviderName | string | Infrastructure provider that hosts the resource; always "Microsoft" for Cost Management data. Replaces the removed `ProviderName` (FOCUS 1.4). |
| InvoiceIssuerName | string | Name of the invoice issuer. |
| ListCost | real | List (retail) cost for the resource or usage. |
| ListUnitPrice | real | List (retail) unit price for the resource. |
| PricingCategory | string | Category of pricing (e.g., Standard, Spot). |
| PricingQuantity | real | Quantity used for pricing. |
| PricingUnit | string | Unit of measure for pricing. |
| ProviderName | string | Name of the cloud provider. |
| PublisherName | string | Name of the publisher. |
| RegionId | string | Identifier for the region. |
| RegionName | string | Name of the region. |
| ResourceId | string | Unique identifier for the resource. |
| ResourceName | string | Name of the resource. |
| ResourceType | string | Type of resource (e.g., Virtual Machine, SQL Database). |
| ServiceCategory | string | High-level service category (e.g., Compute, Storage). |
| ServiceName | string | Name of the Azure service. |
| ServiceProviderName | string | Vendor that makes the service available (Marketplace publisher or Microsoft); never null. Replaces the removed `PublisherName` and `ProviderName` (FOCUS 1.4). |
| SkuId | string | Unique identifier for the SKU. |
| SkuPriceId | string | Unique identifier for the SKU price. |
| SubAccountId | string | Identifier for the sub-account or subscription. |
Expand Down
8 changes: 4 additions & 4 deletions src/scripts/Build-QueryCatalog.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

.DESCRIPTION
Reads all .kql files from src/queries/catalog, includes the full file content
(comments and query), replaces Costs() with Costs_v1_2(), and writes a combined
(comments and query), replaces Costs() with Costs_v1_4(), and writes a combined
markdown file to the Copilot Studio knowledge folder.

.EXAMPLE
Expand Down Expand Up @@ -46,7 +46,7 @@ $output = @"

This document contains ready-to-use KQL query patterns for common FinOps analysis tasks. Use these as templates when answering cost questions. Always execute queries via the Kusto MCP tool β€” never answer from this document alone.

All queries use the ``Costs_v1_2()`` function unless noted otherwise.
All queries use the ``Costs_v1_4()`` function unless noted otherwise.
"@

# Process each KQL file
Expand All @@ -69,8 +69,8 @@ foreach ($file in $kqlFiles)
$title = ($file.BaseName -replace '-', ' ')
$title = $title.Substring(0, 1).ToUpper() + $title.Substring(1)

# Replace Costs() with Costs_v1_2()
$content = $content -replace '\bCosts\(\)', 'Costs_v1_2()'
# Replace Costs() with Costs_v1_4()
$content = $content -replace '\bCosts\(\)', 'Costs_v1_4()'

# Guard against triple backticks in KQL content breaking the markdown code fence
if ($content -match '``````')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Database: Hub

## Knowledge references (use to BUILD queries, not to answer directly)

- **`schema-reference.md`** β€” Column names, types, usage notes, and edge cases for `Costs_v1_2()`. Check BEFORE every query. Never quote as answers.
- **`schema-reference.md`** β€” Column names, types, usage notes, and edge cases for `Costs_v1_4()`. Check BEFORE every query. Never quote as answers.
- **`query-catalog.md`** β€” Ready-to-use KQL query templates for cost breakdowns, trends, anomalies, savings, forecasting, and commitment analysis. Adapt and execute; never return as-is.
- **`weekly-report-guide.md`** β€” Workflow for structured weekly cost anomaly reports with severity classification and report structure. Follow when asked for weekly report.

Expand All @@ -22,7 +22,7 @@ On first interaction, run these steps automatically:
**Step 1: Detect currency**

```kusto
Costs_v1_2() | where ChargePeriodStart >= ago(7d) | summarize count() by BillingCurrency | top 1 by count_
Costs_v1_4() | where ChargePeriodStart >= ago(7d) | summarize count() by BillingCurrency | top 1 by count_
```

Use the returned currency symbol for the session ($ for USD, CA$ for CAD, € for EUR, Β£ for GBP, etc.).
Expand All @@ -38,7 +38,7 @@ Query and present available scopes. Ask the user to pick ONE:
| Tag | First query tag keys: `... \| mv-expand bagexpansion=array Tags \| summarize count() by tostring(Tags[0]) \| top 10 by count_` Then query values for chosen key. | `Tags['<key>'] == "<value>"` |
| All | No query needed | No filter |

All discovery queries use: `Costs_v1_2() | where ChargePeriodStart >= ago(7d)`
All discovery queries use: `Costs_v1_4() | where ChargePeriodStart >= ago(7d)`

Apply the selected scope filter to EVERY subsequent query. Mention active scope in each response. User can change scope anytime.

Expand All @@ -49,7 +49,7 @@ Apply the selected scope filter to EVERY subsequent query. Mention active scope

## Core rules

1. ALWAYS query `Costs_v1_2()` for cost data. NEVER query raw tables directly.
1. ALWAYS query `Costs_v1_4()` for cost data. NEVER query raw tables directly.
2. VERIFY column names against `schema-reference.md` before every query.
3. SHOW the KQL query you will run before executing it.
4. NEVER guess column names or values. If unsure, check `schema-reference.md`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Use these descriptions when uploading knowledge files to your Copilot Studio age

## schema-reference.md

Column reference for building KQL queries against Costs_v1_2(). Contains all column names, data types, usage notes, and edge cases like blank meter categories and BilledCost vs EffectiveCost divergence. Use to look up correct column names before writing queries.
Column reference for building KQL queries against Costs_v1_4(). Contains all column names, data types, usage notes, and edge cases like blank meter categories and BilledCost vs EffectiveCost divergence. Use to look up correct column names before writing queries.

## query-catalog.md

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# KQL column reference for Costs_v1_2()
# KQL column reference for Costs_v1_4()

This document lists all columns available in the `Costs_v1_2()` function in the FinOps Hub database.
This document lists all columns available in the `Costs_v1_4()` function in the FinOps Hub database.

**IMPORTANT: This is a SCHEMA REFERENCE for constructing KQL queries. Do NOT use values from this document to answer questions. Always EXECUTE a KQL query to get actual data.**

Based on FOCUS 1.2 (FinOps Open Cost and Usage Specification). Columns with `x_` prefix are Azure extensions.
Based on FOCUS 1.4 (FinOps Open Cost and Usage Specification). Columns with `x_` prefix are Azure extensions.

## Time

Expand Down Expand Up @@ -46,6 +46,7 @@ Relationship: `ListCost >= ContractedCost >= EffectiveCost` for discounted usage
| BillingCurrency | string | Currency code (e.g. CAD, USD, EUR). |
| x_BillingAccountAgreement | string | Agreement type: "EA", "MCA", "MOSP". |
| x_BillingAccountId | string | Numeric billing account ID. |
| x_BillingAccountName | string | Numeric billing account display name (source value before FOCUS normalization). |
| x_BillingProfileId | string | MCA billing profile ID. Not used for EA. |
| x_BillingProfileName | string | MCA billing profile name. |
| x_AccountId | string | EA enrollment account ID. |
Expand All @@ -61,6 +62,11 @@ Relationship: `ListCost >= ContractedCost >= EffectiveCost` for discounted usage
| x_CostAllocationRuleName | string | Cost allocation rule name. |
| x_CostCategories | dynamic | Cost categories from allocation rules. |
| x_Project | string | Project label from allocation or tags. |
| AllocatedResourceId | string | (FOCUS 1.3+) ARM path of the resource the cost was allocated to, if split-allocated. Null for hubs today (no Cost Management source). |
| AllocatedResourceName | string | (FOCUS 1.3+) Display name of the allocated-to resource. Null for hubs today. |
| AllocatedMethodId | string | (FOCUS 1.3+) Identifier of the allocation method/rule applied. Null for hubs today. |
| AllocatedMethodDetails | dynamic | (FOCUS 1.3+) JSON metadata describing the allocation method. Null for hubs today. |
| AllocatedTags | dynamic | (FOCUS 1.3+) Tags associated with the allocation target (JSON). Null for hubs today. |

## Resource

Expand Down Expand Up @@ -102,7 +108,7 @@ To handle in queries, use a synthetic category:

```kusto
| extend Category = iif(isempty(x_SkuMeterCategory),
iif(x_PublisherCategory == "Vendor", strcat("Vendor: ", PublisherName),
iif(x_PublisherCategory == "Vendor", strcat("Vendor: ", ServiceProviderName),
iif(CommitmentDiscountStatus == "Unused" and CommitmentDiscountType == "Savings Plan", "Savings Plan Unused",
iif(isnotempty(ServiceName), ServiceName,
"Uncategorized"))),
Expand All @@ -128,6 +134,27 @@ To handle in queries, use a synthetic category:
| x_CommitmentDiscountUtilizationAmount | real | Utilized amount. |
| x_CommitmentDiscountUtilizationPotential | real | Maximum potential utilization. |
| x_AmortizationClass | string | "Amortized Charge" or "Principal". |
| CommitmentProgramEligibilityDetails | dynamic | (FOCUS 1.4+) JSON metadata describing eligibility for provider commitment programs. Null for hubs today (no Cost Management source). |

## Contracts

| Column | Type | Usage |
|--------|------|-------|
| ContractApplied | dynamic | (FOCUS 1.3+) JSON array of contract commitments applied to this row. Null for hubs today (no Cost Management source). See `ContractCommitments()` for the referenced metadata β€” no data until a FOCUS 1.4 export ships. |
| ContractCommitmentBenefitCategory | string | (FOCUS 1.4+) Category of benefit granted by the contract commitment. Null for hubs today. |
| ContractCommitmentCreated | datetime | (FOCUS 1.4+) When the contract commitment was created. Null for hubs today. |
| ContractCommitmentDiscountPercentage | real | (FOCUS 1.4+) Discount percentage granted by the contract commitment. Null for hubs today. |
| ContractCommitmentDurationType | string | (FOCUS 1.4+) Duration type of the contract commitment (e.g. fixed, recurring). Null for hubs today. |
| ContractCommitmentFulfillmentInterval | string | (FOCUS 1.4+) Interval over which the commitment is fulfilled. Null for hubs today. |
| ContractCommitmentLastUpdated | datetime | (FOCUS 1.4+) When the contract commitment was last updated. Null for hubs today. |
| ContractCommitmentLifecycleStatus | string | (FOCUS 1.4+) Lifecycle status of the contract commitment. Null for hubs today. |
| ContractCommitmentModel | string | (FOCUS 1.4+) Commitment model (e.g. spend-based, usage-based). Null for hubs today. |
| ContractCommitmentOfferCategory | string | (FOCUS 1.4+) Offer category for the contract commitment. Null for hubs today. |
| ContractCommitmentPaymentInterval | string | (FOCUS 1.4+) Payment interval for the contract commitment. Null for hubs today. |
| ContractCommitmentPaymentModel | string | (FOCUS 1.4+) Payment model for the contract commitment. Null for hubs today. |
| ContractCommitmentPaymentUpfrontPercentage | real | (FOCUS 1.4+) Percentage of the contract commitment paid upfront. Null for hubs today. |

> All `ContractCommitment*` columns above are null for hubs today (no Cost Management source) and are duplicated as row-level fields per FOCUS 1.4. For full contract commitment metadata, use `ContractCommitments()` β€” no data until Microsoft Cost Management ships a FOCUS 1.4 export (not yet available).

## Capacity reservation

Expand Down Expand Up @@ -162,16 +189,18 @@ To handle in queries, use a synthetic category:
| x_PricingBlockSize | real | Block size for pricing. |
| x_PricingUnitDescription | string | Original CM unit description with block size. |

## Publisher
## Provider

| Column | Type | Usage |
|--------|------|-------|
| x_PublisherCategory | string | "Cloud Provider" (first-party) or "Vendor" (marketplace). |
| PublisherName | string | Publisher name (e.g. "Microsoft"). |
| ServiceProviderName | string | Vendor that makes the service available (Marketplace publisher or Microsoft). Never null. Replaces the removed `PublisherName`/`ProviderName`. |
| HostProviderName | string | Infrastructure provider that hosts the resource. Always "Microsoft" for Cost Management data. Replaces the removed `ProviderName`. |
| x_PublisherId | string | Publisher as billed by. |
| ProviderName | string | Always "Microsoft" for Azure. |
| InvoiceIssuerName | string | Entity that issued the invoice. |

> **Removed in FOCUS 1.4**: `ProviderName` and `PublisherName` no longer exist in `Costs_v1_4()`. Use `ServiceProviderName` and `HostProviderName` instead β€” see above. Original source values are preserved in `x_SourceValues` for auditing.

## Geography

| Column | Type | Usage |
Expand All @@ -180,6 +209,7 @@ To handle in queries, use a synthetic category:
| RegionName | string | e.g. "Canada Central". |
| AvailabilityZone | string | Availability zone, if applicable. |
| x_SkuRegion | string | SKU region from CM. Different format than RegionId. |
| x_Location | string | Original location string (GCP source data). Blank for Azure. |

## Tags

Expand Down Expand Up @@ -218,6 +248,7 @@ To handle in queries, use a synthetic category:
| Column | Type | Usage |
|--------|------|-------|
| InvoiceId | string | FOCUS invoice identifier. |
| InvoiceDetailId | string | (FOCUS 1.4+) Identifier of the invoice line item associated with this row. Null for hubs today (no Cost Management source). Join to `InvoiceDetails()` β€” no data until a FOCUS 1.4 export ships. |
| x_InvoiceIssuerId | string | Invoice issuer ID. |
| x_InvoiceSectionId | string | MCA invoice section / EA department ID. |
| x_InvoiceSectionName | string | MCA invoice section / EA department name. |
Expand Down Expand Up @@ -295,4 +326,4 @@ To handle in queries, use a synthetic category:
| x_SourceType | string | Type of data source. |
| x_SourceVersion | string | Schema version of source data. |
| x_SourceChanges | string | Changes applied during ingestion. |
| x_SourceValues | dynamic | Original source values before transformation (JSON). |
| x_SourceValues | dynamic | Original source values before transformation (JSON), including removed columns like `ProviderName`/`PublisherName`. |
Loading