Metric definition contract
Purpose
Two teams report "active users" and the numbers differ by 18%. Nobody is wrong;
they are answering different questions. The argument that follows is never about
the data — it is about a definition that was never written down, so each analyst
made reasonable choices about timezone, deduplication, and what counts as
activity. This skill produces the contract that ends that argument, and the
restatement rules that stop the definition drifting again silently.
Prerequisites
- Inputs: the metric name as currently used; the decision it is supposed to
support; every existing implementation of it (queries, dashboards, reports)
with the numbers each currently produces; the source tables and their event
semantics.
- Access: the systems that produce the underlying events, and the person with
authority to accept a definition on behalf of the business.
If the two conflicting numbers cannot both be reproduced, stop. A definition
written without seeing where existing implementations diverge will just become a
third number.
Procedure
Write the decision the metric serves, in one sentence, before defining
anything. "We use this to decide whether to keep investing in the onboarding
flow." Definitions have no correct answer in the abstract; they have a correct
answer relative to a decision. A metric with no decision attached is a number
the organisation maintains for free and should probably retire.
Fill every row of the contract. A blank row is where the next disagreement
will come from.
| Element |
The question it settles |
Failure if left blank |
| Population |
Which entities are eligible at all? Internal, test, bot, deleted, and trial entities in or out? |
Test traffic inflates every figure |
| Qualifying event |
What exactly must happen to count? Which event names, which statuses? |
"Activity" means login to one team and any API call to another |
| Grain |
Per what — user, account, session, transaction? |
Multi-user accounts double or halve the number |
| Time window |
Rolling N days, or a calendar period? |
Rolling-28 and calendar-month never agree |
| Timezone and boundary |
Which timezone defines the day boundary? Event time or ingestion time? |
Reports diverge by roughly one day's volume |
| Deduplication |
One entity acting five times counts as how many? |
Counts vs distinct counts differ by an order of magnitude |
| Exclusions |
Refunds, reversals, cancellations, internal transfers, fraud |
Revenue metrics overstate systematically |
| Late/backdated data |
How long does the window stay open, and does the past change? |
Yesterday's number changes and nobody knows why |
| Null and unknown handling |
Excluded, bucketed, or imputed? |
Segment sums stop matching the total |
| Source of record |
The one table or model that is authoritative |
Two pipelines drift apart quietly |
| Owner |
A named person who accepts changes |
Nobody can resolve the next dispute |
Resolve the divergences you found in step 0, explicitly, and record the
ones you rejected. For each way the existing implementations differed, state
which choice the contract makes and why. The rejected alternatives matter as
much as the chosen one — they are what stops the argument reopening.
Decide restatement policy up front.
| Policy |
Behaviour |
Use when |
| Frozen |
Once a period closes, the number never changes |
External or board reporting, anything with a compliance trail |
| Open window |
Restates for N days, then freezes |
Operational metrics with known late-arriving data |
| Always current |
Recomputed from source every run |
Internal exploration only |
A metric that is Frozen for the board and Always current on the dashboard is
two metrics and must be named as two. Naming them the same thing guarantees a
meeting.
Define the segment rule. State the dimensions the metric may be split by
and confirm segments sum to the total. If they do not — because entities can
be in two segments, or a segment is unknown — say so in the contract. Silent
non-additivity is one of the most common causes of "the numbers don't add up".
Set a tolerance and a reconciliation partner. Name the other figure this
metric must agree with (the finance ledger, the billing export, the source
system's own report) and the acceptable difference. A metric with no external
check drifts undetected. If the tolerance is exceeded, the metric is treated as
broken and its consumers are told — not quietly patched.
Version the contract, and treat a change as a breaking change. Any change
to population, qualifying event, or exclusions changes the number's history.
Publish: what changed, the effective date, whether history was restated, and
the size of the step. A metric that changes definition without a published
step is how a trend chart lies for a year.
Publish the plain-language sentence alongside the specification. "A user
who performed at least one qualifying action in the trailing 28 days, counted
once, in UTC, excluding internal and test accounts." That sentence goes in the
dashboard tooltip. Contracts nobody reads are only slightly better than no
contract; the one-line version is what actually propagates.
Worked example of the divergence this prevents
Two teams report monthly active users:
| Choice |
Team A |
Team B |
Effect |
| Window |
Calendar month |
Trailing 30 days |
Different populations at month end |
| Grain |
Per user |
Per account |
Shared accounts collapse |
| Qualifying event |
Any authenticated request |
Session with a page view |
API-only integrations counted by A only |
| Internal accounts |
Included |
Excluded |
A inflated by staff usage |
| Timezone |
Local server time |
UTC |
~1 day of boundary drift |
Neither number is wrong; there was no contract. The reconciliation is done by
walking these rows, not by re-running the queries.
Data handling
Classification: Internal; the contract itself is usually shareable, but
worked examples must not carry real customer identifiers or account numbers — use
synthetic values. If the metric covers personal, financial, or regulated data,
state that in the contract so downstream users know the outputs inherit the
classification. If someone pastes real customer records or positions into the
conversation while defining the metric, flag it and do not proceed until removed.
Boundaries
- A specific report or dashboard needs verification before it is circulated —
data-analytics-report-qa.
- The query implementing the definition needs correctness or cost review —
data-analytics-sql-review.
- The metric is an experiment's success measure and the question is whether the
result is real — that is experiment readout, not definition; define the metric
here first, then hand off.
- Choosing where the metric is computed and stored (warehouse model, streaming
pipeline) is an architecture decision —
engineering-decision-record.
Hand-offs
- Receives from:
data-analytics-report-qa (reconciliation failures that
turn out to be definitional, not computational).
- Routes to:
data-analytics-sql-review (implementation of the contract);
engineering-decision-record (when the contract forces a pipeline or storage
choice).
1---2name: data-analytics-metric-definition3description: Turns a metric name into a binding definition contract: the population, the qualifying event, the time grain, the timezone, the deduplication rule, restatement policy, and a single named owner. Use when two teams report different numbers for the same metric, when a new KPI is being introduced, when a dashboard figure cannot be reconciled with a report, or when a definition needs reviewing before it goes into a board pack. Trigger on 'what counts as an active user', 'our numbers do not match', 'define this metric', 'metric definition', 'why is the dashboard different from the report', 'source of truth for X'. Not for checking whether a specific report is correct before it ships — that is data-analytics-report-qa; not for reviewing the query that implements the definition, which is data-analytics-sql-review.4---56# Metric definition contract78## Purpose910Two teams report "active users" and the numbers differ by 18%. Nobody is wrong;11they are answering different questions. The argument that follows is never about12the data — it is about a definition that was never written down, so each analyst13made reasonable choices about timezone, deduplication, and what counts as14activity. This skill produces the contract that ends that argument, and the15restatement rules that stop the definition drifting again silently.1617## Prerequisites1819- **Inputs:** the metric name as currently used; the decision it is supposed to20 support; every existing implementation of it (queries, dashboards, reports)21 with the numbers each currently produces; the source tables and their event22 semantics.23- **Access:** the systems that produce the underlying events, and the person with24 authority to accept a definition on behalf of the business.2526If the two conflicting numbers cannot both be reproduced, stop. A definition27written without seeing where existing implementations diverge will just become a28third number.2930## Procedure31321. **Write the decision the metric serves, in one sentence, before defining33 anything.** "We use this to decide whether to keep investing in the onboarding34 flow." Definitions have no correct answer in the abstract; they have a correct35 answer relative to a decision. A metric with no decision attached is a number36 the organisation maintains for free and should probably retire.37382. **Fill every row of the contract. A blank row is where the next disagreement39 will come from.**4041 | Element | The question it settles | Failure if left blank |42 | --- | --- | --- |43 | Population | Which entities are eligible at all? Internal, test, bot, deleted, and trial entities in or out? | Test traffic inflates every figure |44 | Qualifying event | What exactly must happen to count? Which event names, which statuses? | "Activity" means login to one team and any API call to another |45 | Grain | Per what — user, account, session, transaction? | Multi-user accounts double or halve the number |46 | Time window | Rolling N days, or a calendar period? | Rolling-28 and calendar-month never agree |47 | Timezone and boundary | Which timezone defines the day boundary? Event time or ingestion time? | Reports diverge by roughly one day's volume |48 | Deduplication | One entity acting five times counts as how many? | Counts vs distinct counts differ by an order of magnitude |49 | Exclusions | Refunds, reversals, cancellations, internal transfers, fraud | Revenue metrics overstate systematically |50 | Late/backdated data | How long does the window stay open, and does the past change? | Yesterday's number changes and nobody knows why |51 | Null and unknown handling | Excluded, bucketed, or imputed? | Segment sums stop matching the total |52 | Source of record | The one table or model that is authoritative | Two pipelines drift apart quietly |53 | Owner | A named person who accepts changes | Nobody can resolve the next dispute |54553. **Resolve the divergences you found in step 0, explicitly, and record the56 ones you rejected.** For each way the existing implementations differed, state57 which choice the contract makes and why. The rejected alternatives matter as58 much as the chosen one — they are what stops the argument reopening.59604. **Decide restatement policy up front.**6162 | Policy | Behaviour | Use when |63 | --- | --- | --- |64 | Frozen | Once a period closes, the number never changes | External or board reporting, anything with a compliance trail |65 | Open window | Restates for N days, then freezes | Operational metrics with known late-arriving data |66 | Always current | Recomputed from source every run | Internal exploration only |6768 A metric that is Frozen for the board and Always current on the dashboard is69 two metrics and must be named as two. Naming them the same thing guarantees a70 meeting.71725. **Define the segment rule.** State the dimensions the metric may be split by73 and confirm segments sum to the total. If they do not — because entities can74 be in two segments, or a segment is unknown — say so in the contract. Silent75 non-additivity is one of the most common causes of "the numbers don't add up".76776. **Set a tolerance and a reconciliation partner.** Name the other figure this78 metric must agree with (the finance ledger, the billing export, the source79 system's own report) and the acceptable difference. A metric with no external80 check drifts undetected. If the tolerance is exceeded, the metric is treated as81 broken and its consumers are told — not quietly patched.82837. **Version the contract, and treat a change as a breaking change.** Any change84 to population, qualifying event, or exclusions changes the number's history.85 Publish: what changed, the effective date, whether history was restated, and86 the size of the step. A metric that changes definition without a published87 step is how a trend chart lies for a year.88898. **Publish the plain-language sentence alongside the specification.** "A user90 who performed at least one qualifying action in the trailing 28 days, counted91 once, in UTC, excluding internal and test accounts." That sentence goes in the92 dashboard tooltip. Contracts nobody reads are only slightly better than no93 contract; the one-line version is what actually propagates.9495## Worked example of the divergence this prevents9697Two teams report monthly active users:9899| Choice | Team A | Team B | Effect |100| --- | --- | --- | --- |101| Window | Calendar month | Trailing 30 days | Different populations at month end |102| Grain | Per user | Per account | Shared accounts collapse |103| Qualifying event | Any authenticated request | Session with a page view | API-only integrations counted by A only |104| Internal accounts | Included | Excluded | A inflated by staff usage |105| Timezone | Local server time | UTC | ~1 day of boundary drift |106107Neither number is wrong; there was no contract. The reconciliation is done by108walking these rows, not by re-running the queries.109110## Data handling111112Classification: **Internal**; the contract itself is usually shareable, but113worked examples must not carry real customer identifiers or account numbers — use114synthetic values. If the metric covers personal, financial, or regulated data,115state that in the contract so downstream users know the outputs inherit the116classification. If someone pastes real customer records or positions into the117conversation while defining the metric, flag it and do not proceed until removed.118119## Boundaries120121- A specific report or dashboard needs verification before it is circulated —122 `data-analytics-report-qa`.123- The query implementing the definition needs correctness or cost review —124 `data-analytics-sql-review`.125- The metric is an experiment's success measure and the question is whether the126 result is real — that is experiment readout, not definition; define the metric127 here first, then hand off.128- Choosing where the metric is computed and stored (warehouse model, streaming129 pipeline) is an architecture decision — `engineering-decision-record`.130131## Hand-offs132133- **Receives from:** `data-analytics-report-qa` (reconciliation failures that134 turn out to be definitional, not computational).135- **Routes to:** `data-analytics-sql-review` (implementation of the contract);136 `engineering-decision-record` (when the contract forces a pipeline or storage137 choice).