FinOps Analytics — Full Reference
Quper's FinOps module is built entirely on the FOCUS v1.2 (FinOps Open Cost and Usage Specification) data model — the vendor-neutral open standard for cloud cost and usage data. All cost calculations, aggregations, and optimization signals derive from FOCUS-normalized columns, ensuring consistent semantics across cloud providers and billing systems.
FOCUS Data Model
Data Architecture — Silver → Gold Pipeline
Analytics flow through a two-layer warehouse architecture before reaching any API endpoint:
| Layer | Table | Grain | Purpose |
|---|---|---|---|
| Silver (raw) | qup_focus_1_2_cost_usage_raw | One row per FOCUS record | Verbatim FOCUS data synced from Athena. No aggregation. Source of truth. |
| Gold (daily fact) | qup_fact_cost_usage_daily | One row per resource per day | Pre-aggregated daily costs, usage, idle flags, tag governance, and performance metrics. All API responses read from here. |
| Config | qup_config_idle_thresholds | One row per threshold key | Operator-configurable thresholds for idle, over-provisioning, and off-hours detection. |
FOCUS Column Mapping (Key Fields)
| Category | FOCUS Columns |
|---|---|
| Cost | billed_cost, effective_cost, list_cost, contracted_cost |
| Usage | consumed_quantity, consumed_unit, pricing_quantity |
| Commitment Discounts | commitment_discount_category, commitment_discount_id, commitment_discount_type, commitment_discount_status |
| Capacity Reservations | capacity_reservation_id, capacity_reservation_status |
| Pricing | list_unit_price, contracted_unit_price, pricing_currency_effective_cost |
| Resource | resource_id, resource_name, resource_type |
| Service & Region | service_name, service_category, service_subcategory, region_name, region_id |
| Time | billing_period_start, billing_period_end, charge_period_start, charge_period_end |
| Accounts | billing_account_id, billing_account_name, sub_account_id, sub_account_name |
| Metadata (JSON) | tags, sku_price_details, x_discounts |
Silver Ingestion Algorithm
- 1Pull from Athena in batches
Reads the FOCUS-normalised Athena table in batches of 1,000 rows. Column names are normalised case-insensitively — underscores, hyphens, and spaces are treated as equivalent to handle minor schema drift across cloud providers or export tools.
- 2Map 70+ FOCUS columns
All cost, usage, commitment, capacity reservation, pricing, resource, service, and tag columns are written verbatim. Tags and pricing detail fields are stored as JSON blobs.
- 3Write with provenance metadata
Each batch is stamped with a batch_id (UUID), loaded_at timestamp, and source_file reference. An optional dev-DB mirror writes in parallel for testing without touching production data.
Gold Aggregation Algorithm
- 1Group by resource + day
Silver rows are grouped by billing_account_id, provider_name, invoice_id, region_name, service_name, charge_category, resource_id, and charge_period_start truncated to date.
- 2Extract workload ID from ARN
When resource_id follows the AWS ARN pattern (arn:partition:service:region:account:resource), workload_id is the first path segment after the final slash, falling back to the seventh colon-delimited segment.
- 3Determine cost_type with commitment priority
If any row in the group carries a non-null commitment_discount_type (e.g. Reserved Instance, Savings Plan), that value wins. Otherwise: charge_category Tax → Tax, Credit → Credit, Refund → Refund, all else → OnDemand.
- 4Aggregate cost and usage
cost_amount = SUM(effective_cost). amortized_cost = SUM(effective_cost). list_cost = SUM(list_cost). usage_quantity = SUM(consumed_quantity). All aggregations COALESCE null to 0.
- 5Tag governance flag
required_tag_missing_flag = TRUE when the aggregated tags JSON is null, empty string, '{}', or the literal string 'null'. No custom tag schema is required.
- 6Initialise idle fields
idle_flag = FALSE and idle_cost = 0 as defaults. These are back-filled by the Idle Spend enrichment job after the gold table is populated.
Story 1 — Unit Cost & Efficiency
Unit cost measures what each unit of consumed resource costs. Efficiency measures whether cost is growing faster or slower than usage — the ratio of the two growth rates.
unit_cost = total_cost ÷ total_usageΔcost% = (current_cost ÷ previous_cost − 1) × 100Δusage% = (current_usage ÷ previous_usage − 1) × 100Δunit_cost% = (current_unit_cost ÷ previous_unit_cost − 1) × 100eff = CLAMP(−10, 10, Δcost% ÷ Δusage%)Computation Steps
- 1Build current-period CTE
Group the gold table by the requested dimension over the current date window. Sum cost_amount or amortized_cost depending on the cost_basis parameter.
- 2Build previous-period CTE
Identical grouping over the preceding equivalent window. Both windows are always the same number of days for a fair comparison.
- 3FULL OUTER JOIN on group key
Ensures resources present in only one period are still included — current-only items show zero previous cost; previous-only items show zero current cost.
- 4Apply formulas and rank
Unit cost, growth percentages, and efficiency ratio are computed per row. Results are ordered by current_cost descending.
Cost Basis Options
| cost_basis | FOCUS Column | Best for |
|---|---|---|
| amortized (default) | effective_cost | Budgeting and allocation — commitment discounts spread evenly over the term |
| actual | billed_cost | Invoice reconciliation — unblended on-demand cost as billed |
| list | list_cost | Savings analysis — shows full discount vs. public list price |
Story 2 — Unit Cost Time-Series
The time-series variant computes unit cost and efficiency for every day in the requested window, enabling trend charts. It uses SQL window functions rather than self-joins to avoid a full table scan per day.
- 1Daily aggregation
Group the gold table by usage_date and the chosen dimension to produce daily total_cost and total_usage per group key.
- 2LAG window function
LAG(total_cost) OVER (PARTITION BY group_key ORDER BY usage_date) retrieves the previous day's value within the same group in a single sorted pass. Applied identically for usage.
- 3Per-day formula application
Unit cost, cost_growth_pct, usage_growth_pct, and efficiency_ratio are computed from the current and lagged values using the same formulas as Story 1. Days with no prior day have NULL growth values.
Story 3 — Period Comparison
Compares two arbitrary time windows of equal length and surfaces absolute and relative deltas per group. Two comparison modes:
| Mode | Previous window definition |
|---|---|
| previous | The N days immediately preceding the current window (e.g. Mar 1–14 vs Feb 15–28) |
| mtd | The same calendar day span in the prior month (e.g. Mar 1–14 vs Feb 1–14) |
Δ$ = current_cost − previous_costΔ% = (current_cost − previous_cost) ÷ previous_cost × 100Resources appearing only in the current period carry has_previous_data = false. Resources that existed only in the prior period appear with current_cost = 0 and a fully negative delta, surfacing deleted or decommissioned workloads.
Story 4 — Optimization Indicators
Four independent indicators, each targeting a distinct waste category. Thresholds are read from qup_config_idle_thresholds at query time — changing a threshold takes effect immediately without a redeployment.
4a — Idle Spend
The gold table's idle_flag and idle_cost are pre-computed by a background enrichment job using the idle_cpu_threshold and idle_query_threshold config values. The endpoint aggregates them:
idle_pct = SUM(idle_cost) ÷ SUM(cost_amount) × 1004b — Overprovisioning
A resource group is over-provisioned only when all three performance dimensions are simultaneously below threshold. The SQL aggregates mean values; the flag is applied in Python after the query:
avg_cpu < overprovision_cpu_thresholdavg_queue_time_sec < overprovision_queue_time_thresholdavg_latency_p95_ms < overprovision_latency_thresholdoverprovision_flag = cpu_ok AND queue_ok AND latency_ok— all three must hold. Low CPU with high queue time signals I/O saturation, not over-provisioning, and is not flagged.
4c — Usage Concentration (Top-N Risk)
- 1Compute per-group usage share
usage_pct = group_usage ÷ total_usage × 100, computed against a grand-total CTE to avoid correlated subqueries.
- 2Rank by usage descending
ROW_NUMBER() OVER (ORDER BY usage_quantity DESC) assigns rank 1 to the largest consumer.
- 3Compute top-N concentration
top_n_pct = SUM(usage_pct WHERE rank ≤ concentration_top_n). Default top_n = 3. A high percentage (e.g. > 80 %) signals a concentration risk where one team or service dominates cloud spend.
Story 5 — Baseline & Z-Score Anomaly Detection
Anomaly detection uses a rolling statistical baseline to distinguish genuine cost spikes from normal variation. The baseline window deliberately excludes the two most recent days so that the current anomaly cannot contaminate its own reference period.
Baseline Window: D-16 to D-3
- 1Daily aggregation
Group gold table by usage_date and chosen dimension to produce daily_cost and daily_usage per group key.
- 2Rolling window function
SQL window: ROWS BETWEEN 16 PRECEDING AND 3 PRECEDING, partitioned by group_key, ordered by usage_date. AVG() and STDDEV() are computed within this window in a single sorted pass.
- 3Insufficient-data guard
Baseline mean and stddev are emitted as NULL when window_size < 7. This avoids anomaly flags when fewer than a week of history exists.
- 4Compute Z-score
Z = (daily_value − baseline_mean) ÷ stddev, computed independently for cost and usage. NULL when stddev = 0 (no variation in the baseline window).
- 5Flag anomalies
is_anomaly = |Z| > z_threshold. Default z_threshold = 2.0 (≈ 95th percentile under a normal distribution). Configurable 0.5 – 5.0. A threshold of 2.0 means a day must sit more than two standard deviations from the 14-day mean to be flagged.
Z = (daily_value − baseline_mean) ÷ baseline_stddevis_anomaly = |Z| > z_threshold (default 2.0)Story 6 — Stability & Volatility
Volatility measures how erratically cost or usage moves over a rolling window. The metric is the Coefficient of Variation (CV) — a normalised, unitless measure of dispersion that is comparable across resources with very different cost scales.
cv_spend = stddev(daily_cost) ÷ mean(daily_cost)cv_usage = stddev(daily_usage) ÷ mean(daily_usage)| Stability label | CV range | Recommendation |
|---|---|---|
| Stable | CV < 0.15 | Safe for long-term Reserved Instance or Savings Plan commitments |
| Moderate | 0.15 ≤ CV < 0.40 | Review before committing to multi-year pricing |
| Volatile | 0.40 ≤ CV < 0.75 | On-demand or 1-year commitments preferred |
| Highly Volatile | CV ≥ 0.75 | Investigate workload scheduling or auto-scaling patterns |
Story 7 — Advanced Optimization Metrics
7a — Idle Days
Uses the pre-computed idle_flag column in the gold daily table to count days of zero meaningful activity and the cost incurred during those days.
idle_pct = COUNT(days WHERE idle_flag) ÷ total_days × 1007b — Zero-Query Cost Days
Identifies Redshift cluster-days where compute cost was incurred but zero queries were processed — the strongest signal for completely unused capacity.
zero_query_pct = SUM(cost WHERE query_count = 0) ÷ SUM(cost) × 1007c — Off-Hours Spend
Computed from the silver table because hourly granularity (charge_period_start hour) is only available at that layer. The gold table aggregates to day, losing intra-day hour information.
off_hours = hour(charge_period_start) < bh_start OR hour ≥ bh_endoff_hours_pct = SUM(effective_cost WHERE off_hours) ÷ SUM(effective_cost) × 1007d — Underutilised Clusters
Distinguishes under-used clusters (low but non-zero CPU) from idle clusters (zero CPU). Only cluster-days with a measured CPU reading above zero are considered.
underutil_pct = days(0 < cpu_avg < threshold) ÷ days(cpu_avg > 0) × 100Configuration Thresholds
| Key | Default | Unit | Used by |
|---|---|---|---|
| idle_cpu_threshold | 5 | % | Idle flag enrichment — CPU below this = idle day |
| idle_query_threshold | 0 | count | Idle flag — queries at or below this = idle day |
| overprovision_cpu_threshold | 20 | % | Story 4b overprovisioning |
| overprovision_queue_time_threshold | 5 | seconds | Story 4b overprovisioning |
| overprovision_latency_threshold | 100 | ms | Story 4b overprovisioning |
| concentration_top_n | 3 | count | Story 4c usage concentration |
| business_hours_start | 9 | UTC hour 0–23 | Story 7c off-hours spend |
| business_hours_end | 18 | UTC hour 0–23 | Story 7c off-hours spend |
| underutil_cpu_threshold | 30 | % | Story 7d underutilisation |
API Endpoints
/api/v1/finops/unit-costUnit cost + efficiency ratio for a dimension, two periods
/api/v1/finops/unit-cost/timeseriesDaily unit cost time-series with lag-based growth rates
/api/v1/finops/period-compareFULL OUTER JOIN comparison of two arbitrary date windows
/api/v1/finops/optimization/idleIdle spend from pre-computed gold idle_flag
/api/v1/finops/optimization/overprovisionOverprovisioning flags (CPU + queue + latency)
/api/v1/finops/optimization/concentrationTop-N usage concentration risk
/api/v1/finops/baselineRolling baseline + Z-score anomaly detection
/api/v1/finops/stabilityCoefficient of Variation volatility classification
/api/v1/finops/advanced/idle-daysCount and cost of idle days per group
/api/v1/finops/advanced/zero-queryDays and cost with zero query activity
/api/v1/finops/advanced/off-hoursOff-hours spend from silver hourly granularity
/api/v1/finops/advanced/underutilUnder-utilised cluster detection
/api/v1/finops/configRetrieve all active threshold values
/api/v1/finops/configBulk upsert threshold values (takes effect immediately)
Grouping Dimensions
| group_by value | FOCUS column | Typical use |
|---|---|---|
| service | service_name | Break down cost by AWS / cloud service |
| region | region_name | Identify high-cost regions |
| resource | resource_id | Per-resource cost attribution |
| billing_account | billing_account_id | Multi-account chargeback |
| workload | workload_id (ARN-derived) | Application-level cost grouping |
| cost_type | cost_type (commitment-derived) | On-demand vs. Reserved vs. Savings Plan mix |
| tag:<key> | tags JSON field | Business dimensions: cost_center, team, environment |
FOCUS Compliance
Standard Response Envelope
{
"success": true,
"data": [ ... ],
"meta": {
"period": { "from": "2024-01-01", "to": "2024-01-31" },
"group_by": "service",
"cost_basis": "amortized",
"row_count": 24
}
}See API Overview for authentication details and the error response format.