From f3d195d4886d3f540a95e9e321c160f8a522963d Mon Sep 17 00:00:00 2001
From: Jean du Plessis
@@ -135,9 +135,9 @@ export function SpendEvidenceCard({
const isPeak = highest !== undefined && point.periodStart === highest.periodStart;
const showTick = index % tickStride === 0 || index === evidence.length - 1;
const accessibilityLabel =
- point.coverage === 'complete'
- ? `${point.label}: ${money(pointTotal)} total, ${money(point.variableUsd)} usage-based, ${money(point.scheduledUsd)} scheduled`
- : `${point.label}: spend data unavailable, ${point.coveredHours} of ${point.totalHours} hours covered`;
+ point.coverage === 'unavailable'
+ ? `${point.label}: spend data unavailable, ${point.coveredHours} of ${point.totalHours} hours covered`
+ : `${point.label}: ${point.coverage === 'partial' ? 'at least ' : ''}${money(pointTotal)} total, ${money(point.variableUsd)} usage-based, ${money(point.scheduledUsd)} scheduled${point.coverage === 'partial' ? `, ${point.coveredHours} of ${point.totalHours} hours covered` : ''}`;
return (
diff --git a/apps/web/src/components/cost-insights/types.ts b/apps/web/src/components/cost-insights/types.ts
index 86ddc192a0..bec83991b5 100644
--- a/apps/web/src/components/cost-insights/types.ts
+++ b/apps/web/src/components/cost-insights/types.ts
@@ -30,12 +30,12 @@ type SpendEvidencePointBase = {
export type SpendEvidencePoint =
| (SpendEvidencePointBase & {
- coverage: 'complete';
+ coverage: 'complete' | 'partial';
variableUsd: number;
scheduledUsd: number;
})
| (SpendEvidencePointBase & {
- coverage: 'partial' | 'unavailable';
+ coverage: 'unavailable';
variableUsd: null;
scheduledUsd: null;
});
diff --git a/apps/web/src/lib/cost-insights/presenter.test.ts b/apps/web/src/lib/cost-insights/presenter.test.ts
index 75bbbf0033..ae94b38142 100644
--- a/apps/web/src/lib/cost-insights/presenter.test.ts
+++ b/apps/web/src/lib/cost-insights/presenter.test.ts
@@ -555,7 +555,7 @@ describe('Cost Insights presenter', () => {
).toThrow('Covered Cost Insights evidence must include both spend categories.');
});
- it('marks aggregate evidence partial without exposing an understated covered subtotal', () => {
+ it('shows known spend in partial aggregate evidence without presenting it as a complete total', () => {
const points = [
{
hourStart: '2026-06-25T22:00:00.000Z',
@@ -594,8 +594,8 @@ describe('Cost Insights presenter', () => {
coverage: 'partial',
coveredHours: 1,
totalHours: 2,
- variableUsd: null,
- scheduledUsd: null,
+ variableUsd: 2,
+ scheduledUsd: 1,
},
{
label: 'Jun 26',
diff --git a/apps/web/src/lib/cost-insights/presenter.ts b/apps/web/src/lib/cost-insights/presenter.ts
index da46ab7cf5..783dcbc2fc 100644
--- a/apps/web/src/lib/cost-insights/presenter.ts
+++ b/apps/web/src/lib/cost-insights/presenter.ts
@@ -225,10 +225,6 @@ function presentEvidenceBucket(points: OwnerHourlySpend[]): SpendEvidencePoint {
if (covered.length === 0) {
return { ...common, coverage: 'unavailable', variableUsd: null, scheduledUsd: null };
}
- if (covered.length !== points.length) {
- return { ...common, coverage: 'partial', variableUsd: null, scheduledUsd: null };
- }
-
let variableMicrodollars = 0;
let scheduledMicrodollars = 0;
for (const point of covered) {
@@ -238,7 +234,7 @@ function presentEvidenceBucket(points: OwnerHourlySpend[]): SpendEvidencePoint {
}
return {
...common,
- coverage: 'complete',
+ coverage: covered.length === points.length ? 'complete' : 'partial',
variableUsd: microdollarsToUsd(variableMicrodollars),
scheduledUsd: microdollarsToUsd(scheduledMicrodollars),
};
From b856ecaf6c95daab3226f61fb028c0e069e8ed33 Mon Sep 17 00:00:00 2001
From: Jean du Plessis
-
) : (