Metric
A metric is an aggregation defined on the entity it aggregates — sum, count, average, conditional aggregates — invoked with metric().
An aggregation defined on an entity — sum, count, average, conditional aggregate — anything that produces a single value across many rows.
What it is
Where a feature answers "what is this attribute?" at row grain, a metric answers "across many rows of this entity, what's the aggregate?"
A metric is entity-local. It is defined exactly once, on the entity whose rows it aggregates — sum_net_revenue lives on order because order is the entity whose rows it sums. Its sql references that entity's own features (entity-qualified) and cannot reference other entities; there is no join_name on a metric.
To use an aggregate across an entity boundary — customer wanting total revenue across all its orders — you don't define a metric on customer. You define a feature on customer whose sql references the cross-entity metric path through a relationship, and the engine handles the join and grain alignment. This keeps the agent's mental model simple: metrics aggregate the current entity; everything else is a feature, however it's computed underneath.
Where it lives
.lynk/domains/<domain>/entities/<entity>/schema.yml, under metrics:.
Format
name
✓
string
Unique across the whole domain, not just this entity — the domain's metric namespace is flat (see Validation). Also shares the entity's namespace with features and relationships.
description
✓
string
What the metric represents. The sql must compute exactly this — the agent reasons from the description, so a mismatch misleads every query. State the scale (e.g. 0–1 vs 0–100) for any ratio.
sql
✓
aggregation expression
References this entity's features, entity-qualified. No cross-entity references. SQL expressions grammar.
data_type
✓
number | string | datetime | boolean
The type of the aggregated value.
filter
–
SQL predicate
A WHERE clause that narrows rows before the aggregation runs.
Invoking a metric
A metric is invoked with metric(<entity>.<metric_name>) — and that is the entire call. A metric takes no arguments: no parameters, no per-call filters, no date ranges. A differently-scoped aggregate is a second metric with its own filter:, or manual SQL at query time (see Lynk SQL → CTEs).
Inside
schema.yml— a feature'ssqlcan callmetric()to compose with an aggregate (see SQL expressions).At query time — the agent writes
metric(<entity>.<metric_name>)in Lynk SQL; when the entity is aliased, it uses the alias. Full rules in Lynk SQL.
Computing the right value
Two mistakes pass every structural check but still produce the wrong number, so they are called out here:
Aggregate ratios as a ratio of sums — never an average of per-row ratios. A rate or percentage is
SUM(numerator) / NULLIF(SUM(denominator), 0).AVG(per_row_pct)weights every row equally and is wrong whenever the denominators differ — a career shooting % computed by averaging per-game percentages is off by exactly this.State the scale and keep thresholds in it. Say whether a ratio is
0–1or0–100in thedescription, and write every comparison constant in that same scale. A0–1value compared against>= 55is always false.
Examples
A count.
A conditional aggregate. Counts churned customers without filtering the rest out.
An aggregate with a filter. On Bly's order, revenue from completed orders only.
A weighted ratio. A percentage is a ratio of sums, not an average of per-row ratios.
Validation
nameis unique within the entity (features, metrics, and relationships share one namespace).nameis unique across the whole domain, not just within its entity — aplayer_gameand ateam_gamecannot both define a metric namedtotal_points. References are always entity-qualified (player_game.total_points), so you'd expect that to disambiguate, but the domain's metric namespace is flat: the barenamemust be globally unique. Give each a distinct name by prefixing its subject —player_total_points,team_total_points.The metric compiles and field-probes at the Lynk build — the authoritative surface where every column must resolve to real data. A raw-warehouse check alone is a proxy that can pass while the build fails; fabricated values or columns fail the build.
Quality bars the build can't check — the
sqlmatching thedescription, descriptions distinguishable enough for the agent to choose between similar metrics — live in Modeling metrics, time, and state.sqlreferences only this entity's own features (entity-qualified); cross-entity references andjoin_nameare not allowed on a metric.data_typeis one ofnumber,string,datetime,boolean.Grammar errors are detailed in SQL expressions → validation.
Related
Parent: schema.yml · Entity
Siblings: Feature — how cross-entity aggregates are exposed · Relationships
SQL expressions —
metric()and thesqlgrammarLynk SQL — invoking
metric()at query time
Last updated