# GreenLeaf reporting data dictionary — v1 semantic contract

**Authored:** 2026-10-29 · **Status:** frozen source specification before fixture generation; English editorial input. The CSV is a new synthetic reconstruction, not recovered course data. The [brief](brief-v1.md) governs decisions; the [source map](course-source-map.json) governs provenance. No real customers, health information or client accounts are included.

## Grain, window and attribution

One canonical row is one UTC paid-click date × channel × device × audience × creative, in the UK. Fourteen dates × three channels × two devices × two audiences × two creatives = **336 rows**. The raw export has **337 rows**, including one exact duplicate. Campaign belongs to channel and does not add a dimension.

Week 1: `2026-09-01`–`2026-09-07` inclusive. Week 2: `2026-09-08`–`2026-09-14` inclusive. Snapshot: **`2026-09-22T23:59:59Z`**. Days are UTC and `date` always means paid-click cohort date, never purchase/event date. Funnel events and first purchases are observed during the seven days after the eligible paid click. Exact event timestamps are not exported; the seven-day attribution/observation window is a generator construction assumption. Both complete periods have matured at the snapshot. All published primary rows have `is_provisional=false`.

Spend, impressions and clicks describe the acquisition activity assigned to that cohort date. Landing, quiz and purchase counts follow its source-tagged paid-click cohort and device/audience/creative bucket. Each synthetic first-purchase customer and revenue amount is assigned once, to the last eligible paid click within seven days; all event stages follow this same exclusive assignment. Cross-device identity reconciliation is not measured. Exclusivity is guaranteed by construction, not independently established by this aggregate file.

## Fields

| Field | Type / unit | Meaning and validation |
|---|---|---|
| `row_id` | nonempty string | Stable unique canonical row ID. The raw exact duplicate repeats it; conflicting rows with the same ID are an error. |
| `date` | ISO `YYYY-MM-DD` | UTC source paid-click cohort date, within September 1–14. |
| `market` | enum | `UK` only; scope is paid cohorts in the fictional UK launch. |
| `channel` | enum | `google-search`, `linkedin`, `reddit-paid`. Organic Reddit activity is excluded. |
| `campaign_id` | enum after normalization | One campaign per channel; lookup below. |
| `device` | enum | `mobile` or `desktop`, device of assigned source paid click. |
| `audience_id` | enum | `skeptical` or `exploring`; mutually exclusive constructed buckets within channel, not validated customer traits. |
| `creative_id` | enum | `traceability` or `value`; message hypotheses with channel-specific format, lookup below. |
| `spend_cents` | nonnegative integer USD cents | Media cost only. No agency, creative, tooling, salaries or other acquisition costs. |
| `impressions` | nonnegative integer | Acquisition ad impressions in the bucket; not unique people or frequency. |
| `clicks` | nonnegative integer | Paid clicks assigned to this bucket; not unique visitors. |
| `landing_sessions` | nonnegative integer | Source-tagged landing sessions observed within seven days of the eligible paid click. At most one retained session per synthetic funnel journey. |
| `quiz_starts` | nonnegative integer | Distinct retained source-tagged quiz journeys that start within the same seven-day window; one retained start per journey. Completion-rate denominator. |
| `quiz_completions` | nonnegative integer | Those retained quiz journeys completed within the same seven-day window; no repeated completion counting. |
| `attributed_new_customers` | nonnegative integer | First-purchase customers completing this constructed quiz-led funnel within seven days, assigned once by the declared last-paid-click rule. Not all-site new customers. |
| `attributed_first_purchase_revenue_cents` | nonnegative integer USD cents | First-purchase revenue from those customers, after discounts, excluding tax and shipping. No refunds in this fixture; no renewal revenue. The generator assigns USD $80 (8,000 cents) per first-purchase customer for arithmetic clarity; this is a reconstruction assumption, not course pricing or LTV. |
| `is_provisional` | boolean | `false` means this row's seven-day observation window is mature at the declared snapshot. Reject unsupported string/boolean coercion. |

Per-row inequalities: `impressions >= clicks >= landing_sessions >= quiz_starts >= quiz_completions >= attributed_new_customers`. This is an explicit simplified quiz-led funnel construction, not a universal property of advertising exports. A row with zero customers must have zero first-purchase revenue; a positive customer count must have positive revenue. These constraints do not supply person-level evidence.

## Canonical lookups and raw cleanup

| Channel | Canonical campaign ID | Display name | Allowed raw campaign ID alias |
|---|---|---|---|
| `google-search` | `gl-uk-google-search` | GreenLeaf UK Search | `gl_uk_search` → `gl-uk-google-search` |
| `linkedin` | `gl-uk-linkedin` | GreenLeaf UK LinkedIn | None |
| `reddit-paid` | `gl-uk-reddit-paid` | GreenLeaf UK Reddit paid | None |

Audience `skeptical`: constructed bucket for a proof-seeking buyer comparing sourcing/dosing evidence; inspired by Oliver's unvalidated persona. Audience `exploring`: constructed bucket for a buyer exploring the category and considering value. They are neither real targeting specifications nor randomized treatment assignments; no identity, profession or health condition is inferred.

Creative `traceability`: illustrative “Know what is in every serving” message. Creative `value`: illustrative “Compare the value of a clearly dosed serving” message. For Google Search these are text-ad message hypotheses; for LinkedIn, sponsored-feed copy hypotheses; for Reddit paid, promoted-post copy hypotheses. Creative IDs are shared message categories within each channel, not identical finished ad assets or approved claims. No proof of efficacy or actual product certification is supplied.

Remove only a byte-for-byte/equal-field exact duplicate, recording its source row ID. Normalize only the declared alias and record the count. An unknown ID, unexpected market, missing field, malformed date, noninteger cents/count, negative value, conflicting duplicate or impossible funnel must fail validation rather than be silently repaired. Preserve a documented zero-denominator row to verify unavailable-ratio handling. Reconcile raw/canonical counts and all dimension totals. The fixture generation record must identify the exact duplicate, alias row and zero-denominator row; this dictionary does not pretend those rows already exist.

## Metrics and comparison rules

Use sums within the selected cohort/dimension, then divide; never average row-level rates. Retain full intermediate precision. Display USD by dividing cents by 100 only at presentation. A zero denominator yields **unavailable**, never zero/infinity; percent change against a zero prior value is unavailable.

| Metric | Definition | Interpretation |
|---|---|---|
| Quiz completion rate | `sum(quiz_completions) / sum(quiz_starts)` | Primary funnel KPI; paid-mobile Week 1/2 must be calibrated to 45%/28%. |
| Click-to-start rate | `sum(quiz_starts) / sum(clicks)` | Diagnostic; distinct from quiz completion. |
| Click-to-landing rate | `sum(landing_sessions) / sum(clicks)` | Diagnostic, not a verified bounce rate. |
| Completion-to-purchase rate | `sum(attributed_new_customers) / sum(quiz_completions)` | Constructed quiz-led funnel diagnostic. |
| CTR | `sum(clicks) / sum(impressions)` | Optimization metric; not awareness. |
| CPC (USD) | `sum(spend_cents) / sum(clicks) / 100` | Media cost per click. |
| CPM (USD) | `sum(spend_cents) / sum(impressions) * 1000 / 100` | Media cost per 1,000 impressions. |
| Media CPA (USD) | `sum(spend_cents) / sum(attributed_new_customers) / 100` | Media-only proxy; not full CAC. |
| Attributed first-order ROAS | `sum(attributed_first_purchase_revenue_cents) / sum(spend_cents)` | Revenue/spend ratio; not profit, incrementality or LTV. |
| First-purchase revenue (USD) | `sum(attributed_first_purchase_revenue_cents) / 100` | Paid-cohort attribution only; not a verdict against the $60K full-month target. |

A rate's percentage-point change is `(Week 2 rate - Week 1 rate) * 100`. Relative change is `(Week 2 rate / Week 1 rate - 1) * 100` when Week 1 is positive. The authored 45% → 28% equals −17 percentage points and approximately −37.8% relative; no other result is predetermined by this source contract.

Before diagnosing mobile aggregate movement, stratify mobile by channel × audience × creative. For stratum `s`, set fixed weight `w_s = Week 1 starts_s / Week 1 total starts`. Compare `sum(w_s * Week 1 completion_rate_s)` with `sum(w_s * Week 2 completion_rate_s)` and compare both with observed rates. Publish weights and counts. A positive-weight stratum without a defined Week 2 rate makes the full fixed-mix comparison unavailable; any explicitly restricted common-strata comparison must disclose excluded counts/weights and cannot silently stand in for the whole. A zero-weight stratum contributes zero and does not require a rate. Changing mix and within-stratum movement may coexist. Neither proves a cause; the cohorts are not randomized.

An incomplete snapshot or provisional primary row makes the two full periods unsettled/noncomparable. Do not treat unobserved outcomes as zero. A separately selected comparison with identical mature coverage must state the selected dates, exclusions and changed question.

## Unavailable evidence and source conflicts

Unavailable: full CAC, profit, retention, realized 12-month LTV, awareness, incrementality, true all-channel/month revenue, frequency, impression share, bounce rate, event/release logs, customer interviews and causal explanations. The source asset's separate 4.2% “quiz CVR” has no adequate shared denominator definition here; do not import it. No screenshot's loss estimate, segment multiple, budget instruction or organic-to-paid causal story is a derived fixture result. See the source map for course facts versus newly authored assumptions.
