Adds a skill for authoring Tableau Next semantic models (SDMs) on Data 360: build from scratch, add data objects, define joins, enrich with calculated fields and metrics, and make models AI-ready. Smoke-tested against a live Data 360 org: SDM discovery, AI-readiness flip, dimension creation, metric creation, and description backfill all exercised end-to-end.
14 KiB
Metric Design Patterns
Semantic metrics (_mtc) are lightweight wrappers for Tableau Next dashboard KPI widgets. The semantic layer lives in Data 360. This guide covers common patterns and design decisions.
Metric Anatomy
Every metric has:
- measurementReference — references a calculated field (
_clc) - timeDimensionReference — field + table for time-based analysis
- timeGrains — granularities (Day, Week, Month, Quarter, Year)
- additionalDimensions — optional breakdown dimensions
- insightsSettings — auto-generated when additional dimensions exist
Basic Patterns
Simple Metric (No Breakdowns)
Use when you need a single KPI without dimensional breakdown.
Example: Total Revenue
# Step 1: Create calculated field
python scripts/create_calc_field.py \
--sdm Sales_Cloud12_backward \
--type measurement \
--name Total_Revenue_clc \
--label "Total Revenue" \
--expression "SUM([Amount])" \
--aggregation Sum
# Step 2: Create metric
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name Total_Revenue_mtc \
--label "Total Revenue" \
--calculated-field Total_Revenue_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud
When to use: Dashboard metric widgets showing a single trend over time.
Metric with Single Breakdown Dimension
Use when you want to analyze the metric by one categorical dimension (e.g., "Revenue by Region").
Example: Revenue by Region
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name Revenue_by_Region_mtc \
--label "Revenue by Region" \
--calculated-field Total_Revenue_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud \
--additional-dimension "Region:Opportunity_TAB_Sales_Cloud"
When to use:
- Breakdown insights with "Top contributors" or "Top detractors"
- Dashboard widgets with dimension filters
- Analysis of metric performance across categories
Metric with Multiple Breakdown Dimensions
Use when you want to analyze the metric across several dimensions simultaneously.
Example: Revenue by Region and Industry
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name Revenue_Multi_Dim_mtc \
--label "Revenue by Region and Industry" \
--calculated-field Total_Revenue_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud \
--additional-dimension "Region:Opportunity_TAB_Sales_Cloud" \
--additional-dimension "Account_Industry:Account_TAB_Sales_Cloud"
When to use:
- Complex metrics with multiple dimension breakdowns
- Flexible analysis where users choose which dimension to focus on
- Comprehensive insights across organizational hierarchy
Note: The system automatically generates insightsSettings with insightsDimensionsReferences matching the additionalDimensions.
The additionalDimensions Superset Rule
Every field referenced by identifyingDimension, insightsDimensionsReferences[], or filters[].fieldName MUST also appear in the metric's top-level additionalDimensions[]. The builder enforces this pre-POST and the --identifying-dimension / --filter flags auto-mirror their fields into additionalDimensions, so following the documented usage keeps you compliant. There are two distinct server failure modes if the rule is broken:
-
Insight / identifying dimensions missing from
additionalDimensionsfail at create time:Validation Failed: ... Insight dimension (<Table>.<Field>) is missing from the metric additional dimensions. -
Filter fields missing from
additionalDimensionssucceed at create but make the metric unqueryable:Metric Definition Filter Field <Field> is not found in Metric Definition.
The skill raises a clear pre-POST ValueError quoting these strings rather than letting the metric reach the server in a broken state.
Metric Filters
Use --filter to scope a metric to a subset of rows (e.g. revenue for the West region only). Rules enforced by the skill:
- Field must be fully qualified as
Table.Field— a bare field name is rejected (it would trigger the "is not found in Metric Definition" error above). filterLogicis auto-generated:"1"for one filter,"1 AND 2"for two, etc. (1-based, in filter order). It is required by the server alongside a non-emptyfilters[].- Filter fields are auto-mirrored into
additionalDimensionsso the metric stays queryable. - Operators (verified live against a v66.0 org, 2026-06-23):
=(Equals),>(GreaterThan),<(LessThan),In,NotIn,Contains,NotContains,Between,StartsWith. The server uses CamelCase enum values and rejects SQL-styleEQUAL/NOT_EQUAL/GREATER_THAN_OR_EQUAL; there is no>=,<=, or!=operator.
Example: West-region revenue
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name West_Revenue_mtc \
--label "West Region Revenue" \
--calculated-field Total_Revenue_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud \
--filter "Opportunity_TAB_Sales_Cloud.Region = West"
When to use: Pre-scoped KPIs (a segment-specific metric) where the filter is part of the metric's definition rather than a dashboard-level filter.
Advanced Patterns
Ratio Metrics (Win Rate, Conversion Rate)
Metrics representing rates or percentages always use UserAgg aggregation.
Example: Win Rate
# Step 1: Create win rate calculated field
python scripts/create_calc_field.py \
--sdm Sales_Cloud12_backward \
--type measurement \
--name Win_Rate_clc \
--label "Win Rate" \
--expression "SUM([Won_Count]) / SUM([Total_Count])" \
--aggregation UserAgg
# Step 2: Create metric
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name Win_Rate_mtc \
--label "Win Rate" \
--calculated-field Win_Rate_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud
When to use: Any percentage, rate, or ratio metric (conversion rate, churn rate, success rate).
Weighted Metrics
Metrics where values are weighted by another field (e.g., weighted pipeline by probability).
Example: Weighted Pipeline Value
# Step 1: Create weighted pipeline field
python scripts/create_calc_field.py \
--sdm Sales_Cloud12_backward \
--type measurement \
--name Weighted_Pipeline_clc \
--label "Weighted Pipeline Value" \
--expression "SUM([Amount] * [Probability])" \
--aggregation Sum
# Step 2: Create metric
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name Weighted_Pipeline_mtc \
--label "Weighted Pipeline Value" \
--calculated-field Weighted_Pipeline_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud
When to use: Risk-adjusted revenue, weighted scores, probabilistic forecasting.
Time-Based Metrics (Sales Cycle, Days to Close)
Metrics representing time durations or date differences.
Example: Average Sales Cycle
# Step 1: Create sales cycle field
python scripts/create_calc_field.py \
--sdm Sales_Cloud12_backward \
--type measurement \
--name Avg_Sales_Cycle_clc \
--label "Average Sales Cycle (Days)" \
--expression "AVG(DATEDIFF('day', [Created_Date], [Close_Date]))" \
--aggregation Avg
# Step 2: Create metric
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name Avg_Sales_Cycle_mtc \
--label "Average Sales Cycle" \
--calculated-field Avg_Sales_Cycle_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud
When to use: Process duration metrics (time to close, time to resolution, cycle time).
Cumulative Metrics
Metrics that accumulate over time (running totals).
Example: Cumulative Revenue
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name Cumulative_Revenue_mtc \
--label "Cumulative Revenue" \
--calculated-field Total_Revenue_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud \
--is-cumulative
When to use: Year-to-date totals, running sums, cumulative counts.
Note: Add --is-cumulative flag to create_metric.py script (you may need to add this flag if not already supported).
Sentiment Configuration
Metrics support sentiment indicators that affect how insights are displayed.
SentimentTypeUpIsGood (Default)
Use when increases are positive (revenue, wins, customer satisfaction).
python scripts/create_metric.py \
--sdm Sales_Cloud12_backward \
--name Total_Revenue_mtc \
--label "Total Revenue" \
--calculated-field Total_Revenue_clc \
--time-field Close_Date \
--time-table Opportunity_TAB_Sales_Cloud
# Default sentiment is UpIsGood
SentimentTypeUpIsBad
Use when increases are negative (costs, churn, complaints).
Example: Customer Churn Rate
# Assuming you add --sentiment flag to create_metric.py:
python scripts/create_metric.py \
--sdm Customer_Success_Model \
--name Churn_Rate_mtc \
--label "Customer Churn Rate" \
--calculated-field Churn_Rate_clc \
--time-field Churn_Date \
--time-table Customer_TAB \
--sentiment SentimentTypeUpIsBad
SentimentTypeNone
Use for neutral metrics (headcount, capacity, inventory).
Example: Headcount
python scripts/create_metric.py \
--sdm HR_Workforce_Model \
--name Headcount_mtc \
--label "Headcount" \
--calculated-field Headcount_clc \
--time-field Hire_Date \
--time-table Employee_TAB \
--sentiment SentimentTypeNone
Time Dimension Selection
Choosing the right time dimension affects metric behavior:
Transaction Date
Use the date when the event occurred (most common).
- Revenue metrics →
Close_Date - Lead metrics →
Created_Date - Support metrics →
Case_Created_Date
Effective Date
Use when you want to measure state at a point in time.
- Headcount →
Hire_DateorSnapshot_Date - Inventory →
Inventory_Date
Reporting Date
Use for fiscal/reporting period alignment.
- Fiscal metrics →
Fiscal_Period_Date
Anchor on a business-meaningful date — not a plumbing column
A metric's time anchor must be a business event date. Anchoring on a
system/load column produces a time series that tracks the data pipeline, not
the business — a silent correctness bug: the metric "works," renders, and is
wrong. create_metric.py rejects a plumbing-date anchor by default.
Negative list (rejected unless you pass --allow-junk-time-anchor):
| Pattern | Examples | Why it's not a business date |
|---|---|---|
cdp_sys_* |
cdp_sys_PartitionDate |
Data Cloud partitioning/system column |
*_SourceVersion |
Account_SourceVersion |
Ingest version stamp, not an event |
| load / ingest timestamps | load_timestamp, ingest_date, system_ts |
When the row landed, not when the event happened |
KQ_* |
KQ_flightid__c |
Data Cloud key-qualifier system field |
| connector bookkeeping | DataSourceObject__c, DataSource__c |
Pipeline metadata |
If a "plumbing"-named column genuinely is the intended anchor (rare), override explicitly:
python scripts/create_metric.py ... \
--time-field cdp_sys_PartitionDate --time-table My_Object \
--allow-junk-time-anchor
Metric Naming Best Practices
Good metric names:
Total_Revenue_mtc— Clear, specificWin_Rate_mtc— Concise, business-friendlyAvg_Sales_Cycle_mtc— Descriptive, indicates aggregation
Bad metric names:
Metric_1_mtc— Generic, meaninglessRev_mtc— Too abbreviatedTotal_Revenue_by_Region_mtc— Don't include dimension in name (useadditionalDimensionsinstead)
Rules:
- Describe WHAT is measured, not HOW it's broken down
- Use business terminology, not technical jargon
- Be specific but concise
- Always end with
_mtc
Testing Metrics
After creating a metric, test it by:
- Dashboard widget test — Reference the metric in a Tableau Next dashboard KPI widget
- Verify in consumption layer — Reference the metric in Tableau Next dashboard widgets
- Breakdown test — Verify additional dimensions enable proper insights
Verification checklist:
- Metric appears in SDM discovery
- Time dimension enables proper time-series analysis
- Additional dimensions (if any) generate proper insights
- Values are calculated correctly
- Sentiment displays correctly
Common Patterns Summary
| Pattern | Calc Field Expression | Aggregation | Use Case |
|---|---|---|---|
| Simple sum | SUM([Field]) |
Sum | Total revenue, total count |
| Average | AVG([Field]) |
Avg | Average deal size, average duration |
| Ratio | SUM([A]) / SUM([B]) |
UserAgg | Win rate, conversion rate |
| Weighted | SUM([A] * [B]) |
Sum | Weighted pipeline, risk-adjusted |
| Time calc | AVG(DATEDIFF('day', [Start], [End])) |
Avg | Sales cycle, time to close |
| Conditional sum | SUM(IF condition THEN [Field] ELSE 0 END) |
Sum | Won revenue, qualified leads |
Metric Lifecycle
- Design — Identify business question and required calc field
- Create calc field — Build the measurement logic
- Create metric — Wrap calc field with time dimension and breakdowns
- Test — Verify in Tableau Next dashboard widget
- Iterate — Adjust based on user feedback
- Reuse — Reference metric in multiple Tableau Next dashboards
Metrics are designed for reuse—create once, use everywhere. This centralizes business logic and ensures consistency across dashboards.
Metric Structure (fields on the payload)
Metrics include:
measurementReference.calculatedFieldApiName— references the calc fieldtimeDimensionReference— field + table for time-based analysistimeGrains— defaults to["Day", "Week", "Month", "Quarter", "Year"]additionalDimensions— optional breakdown dimensionsinsightsSettings— auto-generated when additional dimensions existisCumulative— set totruefor cumulative metrics (defaultfalse)sentiment—SentimentTypeUpIsGood,SentimentTypeUpIsBad, orSentimentTypeNone
Automatic insightsSettings when additional dimensions are provided
When additional dimensions are provided, the system automatically generates insightsSettings with enabled insight types (TopContributors, TrendChangeAlert, BottomContributors, etc.) and maps the dimensions to insightsDimensionsReferences.