Repository navigation
feat(OMN-19980): Overview Spend, Measured runs, Tokens and Savings read one metering-summary all row - #364
Closed
Patel230 wants to merge 3 commits into
Conversation
…ll-time row Step B of AC2. The Overview Savings total was the last savings figure on the six local pages still read from another exposure (cost.savings-overview.v1, let through by the guard's Step A allowlist), and its baseline caption came from delegation.savings.v1. Both now come from one metering-summary.v1 row, the all-time row `onex metering` renders, so the figure and the baseline under it cannot disagree. The allowlist is empty and asserted empty, so the guard now holds AC2 as written. The fold keys rows by baseline model and keeps an older baseline's rows, so a baseline change leaves two all rows. The card shows the one refreshed last (every refresh runs under the resolved baseline) and refuses, by name, two refreshed at the same moment rather than picking one. An unresolved baseline reads "Baseline unresolved", a null saving "Not measured", no all row "Not measured: no all-time row", and an unserved exposure names itself; never $0. Spend and Measured runs stay on cost.savings-overview.v1 (ruling 2: AC2 covers savings only). Known red until the lab serves the exposure: four pages.test.ts cases that compare Overview's bindings with served-catalogue.lab.json. The capture (2026-10-02) has no metering-summary.v1 and the catalogue is not edited by hand; it turns green when a release carrying omnimarket#3368 is deployed and the catalogue is re-captured.
…me metering all row Amendment 2 (Lakshman, 2026-10-06 ~07:20Z: "Move all to metering"). After the Savings rebind, Overview still took Spend and Measured runs from cost.savings-overview.v1 and left Tokens unbound, so the four headline figures came from different rows and could disagree with `onex metering` and with each other. All four now bind metering-summary.v1 and pick one row the same way: the all-time row refreshed last, refusing by name two refreshed at the same moment. Spend is spend_usd, Measured runs is runs_measured with the same row's run classes (runs_total, unknown-token and unknown-spend runs) as its caption, and Tokens shows tokens_in and tokens_out side by side, never summed. Only Savings is priced at the baseline, so an unresolved baseline is that card's state alone; MetricCard applies it only to a binding that asks for baseline_state. A null spend or measured count reads Not measured, and token totals with no run that recorded tokens read Not measured rather than 0. Overview no longer binds cost.savings-overview.v1 at all. The old Measured runs caption (estimated and unknown run counts) had no metering equivalent for "estimated"; it is replaced by metering's own run classes, every run in exactly one. delegation.savings.v1 stays only for the per-run cost lookups (ruling 2). The guard gains a headline rule with planted controls (another exposure, a second caption exposure, an unbound card, no all-row fields, the wrong column), and the page tests cover served, unserved, unresolved baseline, null figures, a baseline change, a same-moment tie and day rows only, for every card.
…d, not the exposure The lakshman lane (omnimarket 0.4.301, read 2026-10-06T07:34:32Z) now serves onex.snapshot.projection.metering-summary.v1 ok, but its columns are tenant_id, window_kind, window_start, window_end, as_of, baseline_model, pricing_manifest_version, baseline_state, runs_total, runs_measured, runs_unknown_tokens, runs_unknown_spend, tokens_in, tokens_out, spend_usd, counterfactual_usd, savings_usd, summary_json. savings_per_measured_run_usd is not among them (git grep over omnimarket origin/dev finds nothing), and the dashboard must never divide savings by runs in the browser. C2 assumed "exposure served" meant "field served" and went red on the new catalogue. The catalogue entries now carry the served columns, taken from the saved GET (no new remote read), and C2 binds the card only when the exposure is ok AND lists savings_per_measured_run_usd. Until then the card stays unbound with upstream-blocked. Planted controls (in-test catalogue copies) cover served without the field, served with the field, and degraded with the field. OMN-20009 owns the card and binds it when the field is served.
This was referenced Oct 6, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
OMN-19980 AC2, Step B: the Overview Spend, Measured runs, Tokens and Savings cards read one
metering-summary.v1row, theallrow with the newestas_of, so the four figures cannot disagree with each other or withonex metering. It is stacked on #361 (Step A, the guard) and carries #359's stack beneath it; retarget it todevwhen #361 merges.What changed
Bindings, before to after (
src/pages/local/overview.contracts.yaml,overview.page.yaml):cost.savings-overview.v1total_cost_usdmetering-summary.v1spend_usdcost.savings-overview.v1total_savings_usd,total_baseline_cost_usd, plusdelegation.savings.v1baseline labelsmetering-summary.v1savings_usd,baseline_model,pricing_manifest_version,baseline_statecost.savings-overview.v1measured_run_countand the zero-token, estimated and unknown countsmetering-summary.v1runs_measured,runs_total,runs_unknown_tokens,runs_unknown_spendupstream-blocked)metering-summary.v1tokens_in,tokens_out,runs_total,runs_unknown_tokensAll four select
window_kind = alland order byas_ofdescending. The Overview no longer bindscost.savings-overview.v1.src/pages/LocalDashboardPage.tsx: the Overview cards render those fields; a card whose field is not served shows the typed waiting state, never a number or $0.The guard
src/pages/local/omn19980.savings-source.test.tsdrops the Step A allowlist entry (overview-savings-snapshot), so any Overview binding to another savings exposure now fails it.delegation.savings.v1stays only for per-run cost lookups (local_cost_usd), as ruled in the OMN-19980 spec's Amendment 2.Avg saving / call (OMN-20009's card) binds only once the field
savings_per_measured_run_usdis served, not merely the exposure. The lakshman-laneGET /projectionsread at 2026-10-06T07:34:32Z (omnimarket 0.4.301) servesmetering-summary.v1without that column.src/pages/local/served-catalogue.lab.jsonre-captured with per-exposure columns (sha256ba54e427...; the old transform's control output is byte-equal, sha25619c35077...). Both digests are from the implementing helper's measurement.Tests: guard 30, Overview page tests 22 (
LocalDashboardPage.omn19980.test.tsx), OMN-20009 contract tests 4; existing tests updated to the new shape; 8 screenshots regenerated.Size: 21 files, 1812 insertions and 217 deletions against #361's head (
a996599); 8 of the files are regenerated screenshots, 1204 of the changed lines are the re-captured catalogue fixture, and 162 changed lines are production code and contracts (LocalDashboardPage.tsxand the two Overview yaml files).How it was verified
Commits
10c3450,1a6159bandf9d10bfare each signed (git log --format=%G?printsGfor all three).f9d10bfat 2026-10-06T07:57Z (measured by me):npx vitest run src/pages/local/omn19980.savings-source.test.ts src/pages/LocalDashboardPage.omn19980.test.tsx src/pages/local/omn20009.contracts.test.tsexits 0, 3 files and 56 tests passed, 1.91 s.10c3450's code 14 of 52 failed, and at1a6159b52 of 52 passed.f9d10bf, the field-served tripwire (helper's measurement): OMN-20009's C2 failed 1 of 3 before the change and passed 4 of 4 after. A mutation that addssavings_per_measured_run_usdto the catalogue makes C2 fail, so the tripwire turns red the moment the field is served.npm run check,tsc -p tsconfig.node.json --noEmit, lint and build exit 0; Playwright contracts plus omn20009 20 passed; pre-commit passed.Failure paths
n/a: this change renders served fields and adds tests; it writes no receipt, verdict or report.
Open defects
metering-summary.v1is not done.metering_summaryhas 0 rows on the lakshman lane, and the cause is under investigation; until rows exist, the Overview shows the waiting state, and no figure on this page has been compared withonex meteringon live data. No fixing commit yet.Local gates
--no-verify, noSKIP=, no--no-gpg-sign, nocore.hooksPathoverride. Every pre-commit and pre-push hook ran.Not in this change
savings_per_measured_run_usd: it stays waiting until the exposure serves it (OMN-20009).onex metering(see Open defects).Overlapping open PRs
Read live at 2026-10-06T07:57Z: all seven open omnidash PRs were listed and each one's changed-file list compared with this branch's.
Overlap-Reviewed: #361 — OMN-19980 Step A, the base of this PR; an ancestor of this head (
git merge-base --is-ancestortrue), so no conflict. Step B removes the allowlist entry that Step A adds.Overlap-Reviewed: #359 — OMN-20009, beneath #361 in the stack; its head
4517cf3is in this head's history. It owns the Avg saving / call card; this PR changes only how that card is gated (the field, not the exposure).Overlap-Reviewed: #358 — OMN-20006 adds the Usage page's Savings per day card waiting on
metering-summary.v1. It sharesLocalDashboardPage.tsx,LocalDashboardPage.live.test.tsx,pages.test.tsandlocal-dashboard-contracts.spec.tswith this branch; this PR does not change the Usage page's cards, and both readmetering-summary.v1. Both are needed; expect a textual conflict in those four files on whichever merges second.No file overlap with #356, #352, #350 or #337 (bot pin bumps, a receipt-gate pin, and a parked graph spike).
Evidence companion: onex_change_control#13027 (item
dod-omn19980-pr364-overview-metering-vitest, AC2, receipt captured atf9d10bf: 56 passed).Evidence-Source: OCC#13027
Evidence-Ticket: OMN-19980