Skip to main content
Your progress
0 of 5 lessons complete0%
T0 / M0.4 / L4 OF 5 / Operator TIER / 10 min

The two-source cost model

Outcome

By the end of this lesson, you will be able to describe the two-source cost model and pick the right source for any cost question.


TierOperator
JTBD”Have one cost model that everyone uses the same way.”
PersonasFinOps Analyst · Engineering Leader · Finance Partner
PrerequisitesL1, L2, L3
Time10 minutes
Bloom verbDescribe (Understand) and Pick (Apply)

1. Concept

Keep two cost numbers, not one.

One is calculated live from what is running and the public price list. The other is the actual billed amount, after discounts, which arrives a day late. Label both clearly, and choose between them depending on the question being asked.

This is the pattern any serious cost practice ends up at, and it is what ZopNight implements.

Why two sources

A single-source cost model breaks under one of three pressures:

Freshness against accuracy. Billing data is at least a day behind. A calculated figure is available now. With only one of them you can either spot a problem today or reconcile an invoice correctly, but not both.

Before discount against after discount. A savings claim needs the rack rate, because that is the money you stopped spending. A budget needs the billed amount, because that is what was paid. One column cannot answer both without being wrong somewhere.

Gaps in coverage. Not every account has billing data wired up, and a new account will be running resources before it does. A calculated figure means there is a cost from day one rather than a blank.

The model

Terminal window
TWO COLUMNS, ONE TABLE
─────────────────────────────────────────────────────────────
cost_usd = live calculated rack rate
pricing API × hours running × units
ALWAYS available, ZERO lag, NO discount
actual_cost_usd = post-discount billing cost (provider source)
from CUR / Cost Explorer / Cost Mgmt
24-48 hr lag, post-discount, NULL if not yet synced
cost_source = label: 'calculated' or 'actual'
tells the reader which column is authoritative

How aggregations work

ZopNight uses a single SQL expression, costColumn(hasBilling), across every aggregate query:

Terminal window
-- If ALL cloud accounts have billing sync, use actual_cost_usd everywhere
-- Otherwise fall back to cost_usd (rack rate) for consistency
SELECT
COALESCE(actual_cost_usd, cost_usd) AS cost
FROM cost_records
WHERE...

The hasBilling predicate is resolved once per organization (cached for 60 seconds) and applied identically across summary, MTD, provider, budget, showback, and trends queries. The result: every number on every report comes from the same logic, no per-report drift.

The cost-source label

Every report header carries the label “Unblended Cost” (when actual is used) or “Rack Rate” (when calculated is used). The label is the contract with the reader:

  • Unblended Cost = billed, post-discount, lagged. Use for: budgets, chargeback, monthly close.
  • Rack Rate = calculated, pre-discount, live. Use for: savings claims, anomaly detection, live monitoring.

A report that does not name its column is leaking trust. The two-source model is what makes the label honest.

When a single source is sufficient

There are organizations where a single source is fine:

  • Very small, single-account. Calculated cost is close enough; the discount stack is minimal.
  • Single-cloud, billing pipeline mature. If billing data is consistently fresh and the discount stack is well-understood, the actual column alone may serve.

But for any multi-account, multi-cloud, or governance-heavy environment, the two-source model is the defensible posture.

The mistake the two-source model prevents

Three common errors disappear when both columns are present and labelled:

  1. The “we don’t know what we paid yet” stall. A team waits for monthly close to know last week’s cost. The live calculated column unblocks them.
  2. The “I thought we had a discount” surprise. Finance reports a rack-rate-flavored number. The bill arrives lower. Trust degrades. Two columns labelled explicitly prevent this.
  3. The over-claimed savings. A scheduling rollout is reported at billed-cost savings (much smaller than the rack-rate savings). The team loses sponsor confidence. Rack rate, labelled, is the right number for the claim.

Two sources, labelled, picked per question.

Per-row vs per-rollup

cost_source is per-row in cost_records. Rollup tables (daily / monthly aggregates) derive their own cost_source:

  • actual if any contributing row is actual
  • calculated otherwise

A daily roll-up that is partially actual and partially calculated is labelled actual (with a tooltip explaining the partial state). Users reading the daily number get the most-recent best answer.


2. Demo

Same resource, same week, both columns visible:

Terminal window
RESOURCE: i-0abc123def (m5.large, us-east-1, RI-covered)
DATE cost_usd (rack) actual_cost_usd (billed) cost_source
─────────────────────────────────────────────────────────────────────
2026-05-13 $2.30 $1.49 actual
2026-05-14 $2.30 $1.49 actual
2026-05-15 $2.30 $1.49 actual
2026-05-16 $2.30 $1.49 actual
2026-05-17 $2.30 $1.49 actual
2026-05-18 $2.30 NULL calculated
2026-05-19 $2.30 NULL calculated ← billing sync lag
─────────────────────────────────────────────────────────────────────
WEEK rack rate $16.10
WEEK billing (actual) $7.45 (5 days × $1.49)
WEEK using COALESCE $12.05 ($7.45 + $4.60 fallback)

The COALESCE pattern gives the best-available-answer per day: actual where available, calculated where not. The week label is actual (because some days were actual) but the rendered tooltip notes the partial fallback.


3. Hands-on (6 min)

For your own organization, evaluate:

Terminal window
1. Do you currently maintain both columns (live + billed) in your
cost data?
Y / N
2. If N: which one is your default? What gap does the missing column
create?
Default: __________
Missing column gap: __________
3. Which report uses which column?
Budget reports: __________ (should be billed)
Savings claims: __________ (should be rack rate)
Anomaly detection: __________ (should be live)
Monthly close: __________ (should be billed)
4. Are the columns labelled visibly on the report?
Y / N

If any “should be” doesn’t match what is, the report is structurally lying. The fix is either to swap the column source or to switch the report’s stated purpose.

Ask for it instead. The same task you just did in the console, asked in one sentence.

Terminal window
BEFORE A ZopNight account with one cloud connected. Billing sync run at least once.
ASK "Show the cost trend for last quarter, and tell me when billing data last synced."
CHECK the sync timestamp before you trust the last few days. Recent days are usually incomplete, not cheap.

Tools behind it: get_cost_trends (read, Cost), get_billing_sync_status (read, Cost), get_currency_exchange_rate (read, Cost). The full catalogue is at zop.dev/learn/mcp-tools.


4. Knowledge check

Q1

A new cloud account is connected to ZopNight at 10 AM. At 2 PM, what cost data is available for that account?

A. Nothing until tomorrow
B. Only the billed cost
C. The live calculated cost (rack rate) is available immediately; the billed cost lands within 24-48 hours
D. Only the resource list appears, and no cost figures at all until the billing sync lands in

Show answer

Correct: C. The two-source model guarantees live calculated cost from day one. The billed cost arrives when the billing sync catches up.

Q2

A team’s monthly variance report uses live calculated cost. Most likely consequence:

A. The report systematically overstates spend by the discount stack (typically 20-40%)
B. The report is accurate
C. The report is entirely irrelevant and ought simply to be ignored completely
D. The budget is wrong

Show answer

Correct: A. Variance vs. budget will look worse than reality. Switch to billed cost for variance reporting. Budgets are set against billed amounts. Reporting variance against rack rate over-states spend systematically.

Q3

The “cost_source” label on a daily rollup shows “actual” but a tooltip says “partial: last 2 days fallback to calculated.” How should this be interpreted?

A. The data is unreliable and should simply be ignored until the billing feed has fully caught up with it again
B. The data is best-available; actual where it has landed, calculated as a placeholder where billing sync has not yet caught up
C. Wait for the billing sync
D. The label is wrong

Show answer

Correct: B. The rollup is the right answer for “now.” This is the intended behaviour. The rollup uses the best available source per day. Users get the most up-to-date number; the tooltip is honest about the fallback.


5. Apply

The two-source model is the spine of ZopNight’s cost surface. Visible places:

  • Reports header: Cost Source label: “Unblended Cost” or “Rack Rate”
  • Reports → Trends: splits each data point into actualCostUsd and calculatedCostUsd
  • Cloud Accounts → Sync Status: per-account billing-sync health
  • Recommendations cards: savings claims use the appropriate column (rack rate for avoided hours, billed for projected forward-looking savings)

The model is documented in the USE-CASES.md and FEATURES.md reference. The architectural decision is documented in 00_PLAN.md § Voice & accessibility.


Glossary terms touched

Two-source cost model · cost_source · COALESCE pattern · Unblended Cost label


Start with the bill.

Foundations takes about five hours. The first lesson is nine minutes.

Open curriculum. No login. No paywall. 290 lessons across 7 courses, three publicly verifiable credentials. Read it on the train, take the exam on a Saturday, list the credential on your résumé Monday.

5h median time to finish Foundations
0 logins, paywalls, or marketing forms
open curriculum, public credential verifier
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·