Skip to content

Support latest MetricFlow YAML spec, conversion metrics, and saved queries#213

Open
nicosuave wants to merge 9 commits into
mainfrom
update-metricflow-adapter
Open

Support latest MetricFlow YAML spec, conversion metrics, and saved queries#213
nicosuave wants to merge 9 commits into
mainfrom
update-metricflow-adapter

Conversation

@nicosuave

Copy link
Copy Markdown
Member

What changed

Extends sidemantic/adapters/metricflow.py to keep pace with dbt MetricFlow / the dbt Semantic Layer. All additions are backward compatible: the legacy YAML spec continues to parse unchanged and existing tests stay green.

Latest YAML spec (dbt Core 1.12 / Fusion engine)

The adapter now detects new-vs-legacy shape and parses both. For the latest spec it handles:

  • Top-level models: with a nested semantic_model: block (honors enabled: false, and semantic_model.name defaulting to the model name).
  • Column-based entity: / dimension: declared under columns:, including the entity: primary shorthand and column-level granularity: for time dimensions.
  • Measures folded into type: simple metrics carrying agg / expr at the top level.
  • Promoted top-level metric keys that replace type_params: numerator / denominator (ratio), input_metrics (derived), input_metric + window + grain_to_date + period_agg (cumulative), and base_metric / conversion_metric / entity (conversion).

Conversion metrics

Previously skipped with a "conversion not yet supported" comment. Now parsed from type_params.conversion_type_params (legacy) and the promoted top-level keys (latest), mapping base_measure/conversion_measure to base/conversion events, entity, and window to conversion_window. The calculation flavor (conversion_rate / conversion / conversions) and constant_properties are retained in metric metadata.

Saved queries

Top-level saved_queries (list or mapping form) are parsed with their query_params (metrics, group_by, where, order_by, limit) and exports, and exposed on graph.metadata["saved_queries"]. They are intentionally kept out of graph.metrics.

Derived/cumulative modifiers

Per-input offset_window / offset_to_grain / alias on derived inputs and cumulative period_agg are retained in metric metadata.

Tests

  • Updated the conversion and saved-query tests that asserted the old "skipped/not supported" behavior to assert the new parsed output (legacy conversion_metrics.yml, simple_manifest_metrics.yaml, simple_manifest_saved_queries.yaml, saved_queries_example.yml).
  • Added a new latest-spec fixture (tests/fixtures/metricflow/latest_spec_models.yml) and a parsing test covering embedded semantic models, column-based entities/dimensions, folded simple metrics, promoted ratio/derived/cumulative/conversion keys, and offset/period_agg metadata, and wired it into the shared added-fixture coverage suite.

Known limitations

  • MetricFlow conversion metrics are measure-based; Sidemantic models conversions as a base/conversion event funnel keyed on an entity, so the measure names become the event references and the calculation flavor / fill_nulls_with / constant_properties are preserved in metadata rather than driving execution semantics.
  • Saved queries are retained as metadata only (no query execution).
  • Export remains in the legacy semantic_models: shape.

…aved queries

Extend the MetricFlow adapter to parse, in addition to the legacy spec:

- Latest spec (dbt Core 1.12 / Fusion): top-level models: with a nested
  semantic_model: block, column-based entity:/dimension: under columns:,
  measures folded into type: simple metrics with agg/expr, and promoted
  top-level metric keys (input_metrics, input_metric, numerator/denominator,
  base_metric/conversion_metric, window, grain_to_date, granularity).
- Conversion metrics via type_params.conversion_type_params (and promoted
  keys), mapped onto Sidemantic conversion metrics with calculation flavor
  and constant_properties retained in metadata.
- Top-level saved_queries (query_params + exports), exposed on
  graph.metadata['saved_queries'].
- Derived per-input offset_window/offset_to_grain modifiers and cumulative
  period_agg, retained in metric metadata.

Legacy-format parsing is unchanged.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8949d78a1b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/adapters/metricflow.py Outdated
Comment thread sidemantic/adapters/metricflow.py
…saved queries

Latest-spec type:simple metrics fold a model measure but were registered as
graph-level metrics with unqualified SQL (e.g. amount) or no SQL (a bare
count). Selecting only such a metric raised No models found for query because
the planner could not infer the owning model. Qualify the folded expression
with the model name, and anchor a bare count to the model primary key, so the
metric carries model context while staying queryable by dependent ratio and
derived metrics.

Also reset per-parse saved_queries state at the start of parse() so reusing a
MetricFlowAdapter does not leak a prior source's saved queries into a later
graph's metadata.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9bd15a4186

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/adapters/metricflow.py Outdated
Comment thread sidemantic/adapters/metricflow.py
Comment thread sidemantic/adapters/metricflow.py Outdated
…ain conversion metrics as metadata

Derived metrics referencing inputs by a plain (non-offset, unfiltered)
alias now rewrite the alias back to the real input metric so dependency
resolution sees real metrics and the metric is queryable. Aliases carrying
offset_window/offset_to_grain or a per-input filter are preserved as
round-trip metadata.

Inline latest-spec count metrics with a constant expr (count with expr: 1
or '*') are anchored to the model primary key, the same as a bare count, so
selecting them no longer raises No models found for query.

MetricFlow conversion metrics reference base/conversion measures, which have
no faithful mapping to Sidemantic's event-filter conversion funnel; they are
retained on graph.metadata[metricflow_conversion_metrics] instead of being
registered as broken queryable conversion metrics that would generate wrong
SQL. Conversion specs are reset per parse to avoid leaking across reuse.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8180ae98b3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/adapters/metricflow.py
… own column

An inline latest-spec simple metric with an aggregation but no expr (e.g.
agg: sum on a customers model) was anchored to the model primary key, so it
generated SUM(primary_key) and silently aggregated the wrong column. Only
count-style measures may use the primary key anchor (COUNT(pk) == COUNT(*));
other expr-less aggregations now default to the measure's own column,
qualified with the model (e.g. customers.lifetime_spend_pretax).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2107c1c396

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/adapters/metricflow.py
Comment thread sidemantic/adapters/metricflow.py
A latest-spec model with semantic_model.enabled: false yields no model, but
its inline model-local metrics were still registered. Those metrics fold a
measure on the absent model, so they carry no SQL/model context and a CLI query
for one raised No models found for query. Skip inline metrics whenever the
owning semantic model is not produced so the graph never exposes an unqueryable
metric.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9519e6c57a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/adapters/metricflow.py
Comment thread sidemantic/adapters/metricflow.py
…entable aggs

Two correctness bugs in the latest-spec inline metric path:

- A simple metric with a filter registered the filter on the graph-level metric
  but the aggregation path ignored Metric.filters, so a filtered metric such as
  completed_revenue aggregated every row and silently dropped the MetricFlow
  filter. Render metric-level filters via CASE WHEN in the graph-level aggregate
  path (mirroring the model-scoped measure path) and project the filter columns
  into the CTE for graph-level simple aggregates.

- agg: percentile (and any other aggregation Sidemantic cannot represent) fell
  through the agg mapper's default and was coerced to sum, registering
  SUM(amount) under the percentile metric's name. Map unrepresentable aggs to
  None and skip those measures/metrics instead. Also normalize aggregation names
  case-insensitively so uppercase aggs like SUM map correctly.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47b9ab4aa6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/adapters/metricflow.py
Comment thread sidemantic/sql/generator.py Outdated
… CTE

The CASE WHEN rendered for a filtered inline simple metric left filter columns
unqualified (e.g. status = 'completed'). When the metric was queried alongside a
joined model whose CTE also exposed a same-named column, the predicate became
ambiguous and the query failed to bind. Infer the metric's owning model from its
SQL (or model context) and qualify the filter's columns with that model's CTE
before rendering the aggregation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3b89f5c656

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/sql/generator.py Outdated
A filtered graph-level count metric with an expression counted a constant 1 for
every matching row, so rows with a NULL counted expression were included even
though the unfiltered COUNT(expr) path skips them. Count the expression inside
the CASE WHEN (skipping NULLs); only a bare row count (*) counts every
matching row.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 775c084eb1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/adapters/metricflow.py
…ut metrics

A latest-spec cumulative metric built from a promoted input_metric is a
graph-level metric, so default-time-dimension resolution skipped it and a query
raised 'requires a time dimension for ordering' even when the underlying model
declares an agg_time_dimension. Resolve the cumulative metric's owning model by
following its base input reference (through intermediate graph-level metrics) and
apply that model's default time dimension.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cd289155bf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sidemantic/adapters/metricflow.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant