Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
72b6d20
Fix Data Explorer dashboard savings formulas and FX fallback (#2093)
flanakin Aug 12, 2026
0e05f98
Revert FX-fallback change in CommitmentDiscountQuantity derivation
flanakin Aug 14, 2026
00f51dd
fix(hubs): reconcile displayed operands with clamped savings on 6 das…
flanakin Aug 26, 2026
60c147e
docs: prepare v15 release documentation
flanakin Aug 26, 2026
843a102
docs: add DeploymentScriptACIProvisioningTimeout mitigation
flanakin Aug 26, 2026
44293c2
chore: bump version to 15.0.0
flanakin Sep 2, 2026
327eafb
docs: finalize v15 changelog, what's new blurbs, and hubs docs
flanakin Sep 7, 2026
38a9bbe
Fix PathNotFound error in msexports ETL ingestion on first run (#2247)
flanakin Sep 8, 2026
deb6cb0
Merge origin/dev into flanakin/v15-prep and address notes
flanakin Oct 12, 2026
6e33ed6
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 12, 2026
42484fc
docs: update v15 changelog and what's new blurbs for October
flanakin Oct 14, 2026
aeb0b11
chore: keep marketplace.json versions three-part during version updates
flanakin Oct 14, 2026
4a3c5a6
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 14, 2026
07a5f23
Merge origin/dev into flanakin/v15-prep
flanakin Oct 14, 2026
5a9b60d
fix(power-bi): repoint rate optimization data quality link
flanakin Oct 15, 2026
cfafe27
Merge origin/dev into flanakin/v15-prep
flanakin Oct 15, 2026
5e2fcd6
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 15, 2026
edff142
chore: trigger CI after ms.date bot commit
flanakin Oct 16, 2026
38a071e
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 16, 2026
204d0db
fix(hubs): use one Total savings definition and derived Cost summary …
flanakin Oct 18, 2026
19cf42e
Merge remote-tracking branch 'origin/flanakin/v15-prep' into flanakin…
flanakin Oct 18, 2026
0c22699
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 18, 2026
5f76437
fix(hubs): exclude commitment purchases from dashboard savings; one p…
flanakin Oct 18, 2026
3821cd4
Return blank instead of % when list cost is zero in dashboard savings…
flanakin Oct 19, 2026
8659e04
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 19, 2026
f1cd3fb
Use semver for plugin.json and add #2247 changelog entry
flanakin Oct 19, 2026
38e6957
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 19, 2026
417790e
Address review: drop percent() code block, simplify eligibility note
flanakin Oct 19, 2026
a172db5
docs: fill v15 changelog gaps (stacked on v15-prep) (#2365)
flanakin Oct 23, 2026
27d1755
Merge dev into v15-prep
flanakin Oct 23, 2026
4f7562a
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 23, 2026
2acd385
Merge remote-tracking branch 'origin/dev' into flanakin/v15-prep
flanakin Oct 23, 2026
89cbf4b
Merge remote-tracking branch 'origin/flanakin/v15-prep' into flanakin…
flanakin Oct 23, 2026
88f080e
Merge origin/dev into PR branch
flanakin Oct 29, 2026
563db68
test(hubs): Add dashboard savings regression tests and restore change…
flanakin Oct 29, 2026
d9f7f2f
chore: Update ms.date in docs-mslearn files
github-actions[bot] Oct 29, 2026
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
9 changes: 6 additions & 3 deletions docs-mslearn/toolkit/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: FinOps toolkit changelog
description: Review the latest features and enhancements in the FinOps toolkit, including updates to FinOps hubs, Power BI reports, and more.
author: MSBrett
ms.author: brettwil
ms.date: 10/28/2026
ms.date: 10/29/2026
ms.topic: reference
ms.service: finops
ms.subservice: finops-toolkit
Expand All @@ -18,14 +18,17 @@ ms.reviewer: brettwil

This article summarizes the features and enhancements in each release of the FinOps toolkit.

<!--
<br>

## Unreleased

The following section lists features and enhancements that are currently in development.

-->
### [FinOps hubs](hubs/finops-hubs-overview.md) v16

- **Changed**
- Changed the Data Explorer dashboard's Cost summary, Savings summary, Savings breakdown by month, savings pie and trend, stacked cost + savings, and Effective Savings Rate tiles to derive their displayed List cost and Contracted cost operands from the same clamped, row-level savings basis as the results shown alongside them, so the on-screen equations (for example, "List βˆ’ Contracted = Negotiated savings") always reconcile. This changes the Effective Savings Rate definition on the affected tiles from `(sum(ListCost) βˆ’ sum(EffectiveCost)) / sum(ListCost)` to a derived List cost built from Effective cost plus the clamped Negotiated and Commitment savings sums. Total savings is now the sum of the clamped Negotiated and Commitment savings everywhere it is shown, commitment discount purchases are excluded from savings on every Summary and Rate optimization tile using the same `x_AmortizationClass != 'Principal'` filter, and the Effective Savings Rate shows blank instead of NaN when List cost is 0 ([#2093](https://github.com/microsoft/finops-toolkit/issues/2093)).


<br><a name="latest"></a>

Expand Down
50 changes: 50 additions & 0 deletions src/powershell/Tests/Unit/HubsDashboardSavings.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

<#
Regression coverage for Data Explorer dashboard savings formulas (#2093 / PR #2248):

1. Savings are never computed by subtracting raw aggregates (sum(ListCost) - sum(EffectiveCost)); tiles use the
row-level clamped x_*Savings columns so every displayed operand and result share one basis.
2. Commitment purchases are excluded via x_AmortizationClass != 'Principal'; the older
ChargeCategory == 'Usage' or isempty(CommitmentDiscountId) variant is gone.
3. Every Effective Savings Rate guards against a zero List cost (blank instead of NaN).
#>

Describe 'HubsDashboardSavings' {

BeforeDiscovery {
$repoRoot = (Resolve-Path "$PSScriptRoot/../../../..").Path
$dashboard = Get-Content (Join-Path $repoRoot 'src/templates/finops-hub/dashboard.json') -Raw | ConvertFrom-Json
$queries = @($dashboard.queries | ForEach-Object { @{ Id = $_.id.Substring(0, 8); Text = [string]$_.text } })
# 3886b5cd pivots Effective cost only; its savings columns are never displayed.
$savingsQueries = @($queries | Where-Object { $_.Id -ne '3886b5cd' -and $_.Text -match '(?i)sum(if)?\(\s*x_(Negotiated|Commitment|Total)\w*Savings' })
}

It 'Excludes commitment purchases from all Summary page savings queries' {
$summaryQueries = @($queries | Where-Object { $_.Text -match "(?i)sumif\(\s*x_(Negotiated|Commitment)DiscountSavings\s*,\s*x_AmortizationClass\s*!=\s*'Principal'\s*\)" })
$summaryQueries.Count | Should -BeGreaterOrEqual 9
}

Context 'Query <Id>' -ForEach $queries {
It 'Does not subtract raw aggregates to compute savings' {
$Text | Should -Not -Match '(?i)sum\(\s*(List|Contracted)Cost\s*\)\s*-\s*sum\('
}

It 'Does not use the legacy commitment purchase filter' {
$Text | Should -Not -Match "(?i)ChargeCategory\s*==\s*'Usage'\s+or\s+isempty\(CommitmentDiscountId\)"
}
}

Context 'Savings query <Id>' -ForEach $savingsQueries {
It 'Excludes commitment purchases or is limited to usage rows' {
$Text | Should -Match "(?i)x_AmortizationClass\s*!=\s*'Principal'|ChargeCategory\s*==\s*'Usage'"
}

It 'Guards the savings rate against zero list cost' {
if ($Text -match '(?i)EffectiveSavingsRate\s*=') {
$Text | Should -Match '(?i)ListCost\s*==\s*0'
}
}
}
}
Loading
Loading