From e8d5013ebe1f2232c84390f85464c1e06b97ffd1 Mon Sep 17 00:00:00 2001 From: Jake Brower Date: Thu, 8 Oct 2026 16:33:00 -0500 Subject: [PATCH] feat(OMN-20752): the Overview shows Baseline spend from the served counterfactual The walk found no Baseline spend on the Overview, though the mockup shows it beside Actual spend and Savings and the figure is served: the same metering-summary.v1 all-time row the Spend and Savings cards read carries counterfactual_usd, the number `onex metering --json` reports. A Baseline spend card now binds that column, with the row's baseline model and pricing manifest as its caption. It requires baseline_state, so an unresolved baseline renders Baseline unresolved, never $0, even when the row serves 0. Bumps to 1.1.6 so onex dashboard can pin a bundle that carries it. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 7 ++ package-lock.json | 4 +- package.json | 2 +- .../LocalDashboardPage.omn20752.test.tsx | 106 ++++++++++++++++++ src/pages/local/overview.contracts.yaml | 30 +++++ src/pages/local/overview.page.yaml | 18 +++ src/pages/local/pages.test.ts | 2 + 7 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 src/pages/LocalDashboardPage.omn20752.test.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index fcb5a5ea..8d79a051 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to `omnidash` are documented here. This project follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## v1.1.6 (2026-10-08) + +### Features +- The Overview shows Baseline spend: the served `counterfactual_usd` of metering-summary.v1's all-time + row, the figure `onex metering --json` reports, beside the baseline model and pricing manifest it is + priced at. With no baseline resolved it shows Baseline unresolved, never $0 (OMN-20752) + ## v1.1.5 (2026-10-08) ### Fixes diff --git a/package-lock.json b/package-lock.json index d24ee0a6..a58b5b6d 100755 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "omnidash", - "version": "1.1.5", + "version": "1.1.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "omnidash", - "version": "1.1.5", + "version": "1.1.6", "license": "MIT", "dependencies": { "@fontsource/ibm-plex-mono": "^5.2.7", diff --git a/package.json b/package.json index c63b173d..8735f543 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "omnidash", - "version": "1.1.5", + "version": "1.1.6", "description": "Composable widget dashboard for real-time observability — Vite + React with per-widget 2D and 3D variants.", "main": "index.js", "homepage": "https://github.com/OmniNode-ai/omnidash#readme", diff --git a/src/pages/LocalDashboardPage.omn20752.test.tsx b/src/pages/LocalDashboardPage.omn20752.test.tsx new file mode 100644 index 00000000..0b7b9a02 --- /dev/null +++ b/src/pages/LocalDashboardPage.omn20752.test.tsx @@ -0,0 +1,106 @@ +// @vitest-environment jsdom +// OMN-20752: the Overview shows Baseline spend, the served counterfactual_usd of metering-summary.v1's all-time row -- +// the figure `onex metering --json` reports as counterfactual_usd -- and a typed state, never $0, when no baseline +// resolved. +// +// Failure modes, each with a test below: +// B1 a served all-time row with a known counterfactual renders that amount on a Baseline spend card; +// B2 a row whose baseline_state is unresolved renders Baseline unresolved, never $0, whether the row leaves +// counterfactual_usd null or serves it as 0; +// B3 the card names the same row's baseline model and pricing manifest, and says the figure is modelled; +// B4 no served row at all is a typed not-measured state, never a number; +// B5 only the all-time row is read: a day row's counterfactual is not the headline (the control for B1). +import { act, render, screen } from '@testing-library/react'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +const METERING = 'onex.snapshot.projection.metering-summary.v1'; + +const harness = vi.hoisted(() => ({ + reachable: new Set(), + answer: (_topic: string): Promise => Promise.resolve([]), +})); + +vi.mock('@/data-source', () => ({ + createSnapshotSource: () => ({ + async *readAll() { yield []; }, + readSnapshot: async (topic: string) => { + const rows = await harness.answer(topic); + return { rows, rowCount: rows.length, dataFreshness: 'fresh', latestEventAt: null, readAt: new Date().toISOString() }; + }, + }), +})); +vi.mock('@/data-source/data-source-override', () => ({ resolveEffectiveDataSource: () => ({ mode: 'http' }) })); +vi.mock('@/data-source/exposure-census', () => ({ + fetchExposureCensus: async () => ({ + rows: [...harness.reachable].map((topic) => ({ topic, reachability: 'reachable' })), + }), +})); + +import { LocalDashboardPage } from './LocalDashboardPage'; + +// The all-time row the OMN-20223 walk read on 2026-10-08: 23 runs, `onex metering --json` counterfactual_usd 0.015292. +const allRow = (fields: Record) => ({ + window_kind: 'all', window_start: '', as_of: '2026-10-08T18:40:44Z', baseline_model: 'claude-sonnet-5-5', + pricing_manifest_version: '3', baseline_state: 'resolved', runs_total: 23, runs_measured: 23, + runs_unknown_tokens: 0, runs_unknown_spend: 0, tokens_in: 5756, tokens_out: 378, spend_usd: 0, + counterfactual_usd: 0.015292, savings_usd: 0.015292, savings_per_measured_run_usd: 0.000665, ...fields, +}); + +async function baselineCard(rows: unknown[]): Promise { + harness.reachable = new Set([METERING]); + harness.answer = (topic) => Promise.resolve(topic === METERING ? rows : []); + render(); + await act(async () => { await vi.advanceTimersByTimeAsync(0); }); + const card = screen.getByRole('heading', { name: 'Baseline spend' }).closest('article'); + if (card === null) throw new Error('no Baseline spend card on the Overview'); + return card as HTMLElement; +} + +const figure = (card: HTMLElement) => card.querySelector('.local-dashboard-metric')?.textContent ?? ''; + +describe('OMN-20752 Baseline spend on the Overview', () => { + beforeEach(() => { + vi.useFakeTimers({ toFake: ['setInterval', 'clearInterval', 'setTimeout', 'clearTimeout', 'Date'] }); + vi.setSystemTime(new Date('2026-10-08T18:45:00Z')); + }); + afterEach(() => { vi.useRealTimers(); }); + + it('B1: renders the served counterfactual_usd of the all-time row', async () => { + const card = await baselineCard([allRow({})]); + expect(figure(card)).toBe('$0.0153'); + }); + + it('B1: a different served counterfactual renders that amount, not a constant', async () => { + const card = await baselineCard([allRow({ counterfactual_usd: 12.5, savings_usd: 12.5 })]); + expect(figure(card)).toBe('$12.5000'); + }); + + for (const counterfactual of [null, 0]) { + it(`B2: an unresolved baseline is Baseline unresolved, never $0 (counterfactual_usd ${String(counterfactual)})`, async () => { + const card = await baselineCard([allRow({ + baseline_state: 'unresolved', baseline_model: null, counterfactual_usd: counterfactual, savings_usd: null, + })]); + expect(figure(card)).toBe('Baseline unresolved'); + expect(card.textContent ?? '').not.toMatch(/\$\s*0/); + }); + } + + it("B3: names the row's baseline model and pricing manifest, and says the figure is modelled", async () => { + const card = await baselineCard([allRow({})]); + expect(card.textContent).toContain('Baseline claude-sonnet-5-5'); + expect(card.textContent).toContain('pricing manifest v3'); + expect(card.textContent).toContain('Modelled'); + }); + + it('B4: no served row is a typed not-measured state, never a number', async () => { + const card = await baselineCard([]); + expect(figure(card)).toMatch(/^Not measured/); + expect(figure(card)).not.toMatch(/\d/); + }); + + it("B5: a day row's counterfactual is not the headline", async () => { + const day = { ...allRow({ counterfactual_usd: 99 }), window_kind: 'day', window_start: '2026-10-08' }; + const card = await baselineCard([day, allRow({})]); + expect(figure(card)).toBe('$0.0153'); + }); +}); diff --git a/src/pages/local/overview.contracts.yaml b/src/pages/local/overview.contracts.yaml index 8178f14a..ff99e86c 100644 --- a/src/pages/local/overview.contracts.yaml +++ b/src/pages/local/overview.contracts.yaml @@ -271,6 +271,36 @@ "no-data" ] }, + { + "component_id": "overview-baseline-spend", + "component_kind": "metric_card", + "title": "Baseline spend", + "contract_version": { + "major": 1, + "minor": 0, + "patch": 0 + }, + "data_bindings": [ + { + "binding_id": "overview-baseline-spend-metering", + "projection_topic": "onex.snapshot.projection.metering-summary.v1", + "ordering_authority_field": "as_of", + "ordering_direction": "descending", + "required_fields": [ + "window_kind", + "as_of", + "baseline_model", + "pricing_manifest_version", + "baseline_state", + "counterfactual_usd" + ] + } + ], + "supported_empty_state_reasons": [ + "missing-field", + "no-data" + ] + }, { "component_id": "overview-quality", "component_kind": "table", diff --git a/src/pages/local/overview.page.yaml b/src/pages/local/overview.page.yaml index fe883641..b638e0bb 100644 --- a/src/pages/local/overview.page.yaml +++ b/src/pages/local/overview.page.yaml @@ -277,6 +277,24 @@ "precision": 6 } }, + { + "widget_id": "6f1d2c8e-4b7a-5e39-9c0d-20752a1c0c01", + "title": "Baseline spend", + "row": 8, + "col": 8, + "width": 4, + "height": 2, + "data_source": "overview-baseline-spend", + "config": { + "config_kind": "metric_card", + "widget_type": "metric_card", + "metric_key": "counterfactual_usd", + "label": "Baseline spend", + "unit": "USD", + "format": "currency", + "precision": 4 + } + }, { "widget_id": "d4da9a48-f797-4b1d-b622-41f028a67e04", "title": "Quality", diff --git a/src/pages/local/pages.test.ts b/src/pages/local/pages.test.ts index a7128d9c..15f42b93 100644 --- a/src/pages/local/pages.test.ts +++ b/src/pages/local/pages.test.ts @@ -298,6 +298,8 @@ describe('local pages against the captured lab catalogue', () => { 'spend_usd', 'savings_usd', 'runs_measured', 'tokens_in_and_out', // OMN-20009: the served run-locally share and the served saving per measured run. 'by_tier.local_call_share', 'savings_per_measured_run_usd', + // OMN-20752: Baseline spend, the same all-time row's served counterfactual_usd. + 'counterfactual_usd', // OMN-20226: compression and cache hit rate, each a served metering-summary.v1 column, Not measured until produced. 'compression_ratio', 'cache_hit_rate', ]);