GASP

Attribution Taxonomy Layer (ATL)

The tagging system that makes dual-lens metrics possible.

Every event in the Commercial Event Ledger (CEL) is an atomic fact: something happened, to someone, on a date, for an amount. But the same event can mean different things depending on which lens you apply. A $500/mo expansion might be organic seat growth (operating signal) or it might include a cross-module upsell (market-comparable signal). The ATL classifies events so that downstream metrics can include or exclude based on governed rules.

Every CEL event carries the tags appropriate to its event class (see Tagging Rules). The tags are what metrics filter on: the Operating and Market forms of Customer Acquisition Cost (CAC) read the same cost events and differ only in which cost_function values they include.


Three Tag Dimensions

ATL defines three orthogonal tag dimensions. Each dimension answers a different question about a CEL event.

DimensionQuestionApplies to
Lifecycle AttributionWhere is this customer in their journey?All event classes
Expansion ClassificationWhat kind of growth is this?Revenue_Event (expansion/contraction/reactivation), Amendment_Event
Cost Function AttributionWhat commercial function incurred this cost?Cost_Event

Lifecycle Attribution

Every CEL event receives exactly one lifecycle tag. This is the primary dimension. It tells you why the event happened in the context of the customer relationship.

Values

TagDefinitionExample
acquisitionFirst commercial engagement with a new customer.New customer signs a $2,000/mo contract.
activationCustomer reaches first value milestone after acquisition.Customer completes onboarding and goes live in production.
retentionExisting customer continues or renews without change.Annual renewal at the same MRR.
expansionExisting customer increases their commercial commitment.Customer upgrades from Professional to Enterprise tier.
reactivationPreviously churned customer returns.Customer who cancelled 6 months ago signs a new contract.
servicingOngoing delivery cost for an active customer.Monthly infrastructure cost, support staffing.

Assignment Rules

  1. A customer’s first Revenue_Event is always acquisition.
  2. Lifecycle_State_Change events with state_category = activation or state_category = onboarding_complete are activation.
  3. Revenue_Event with event_type = renewal and zero MRR change is retention.
  4. Revenue_Event with event_type = expansion is expansion.
  5. Revenue_Event with event_type = reactivation is reactivation.
  6. Cost_Event records for active customers with no change event are servicing.
  7. When a single action generates multiple CEL events (e.g., a renewal with expansion), each event gets its own lifecycle tag. The renewal portion is retention; the expansion portion is expansion.
  8. Revenue_Event with event_type = contraction or event_type = churn is retention: the retention lens carries what was kept and what was lost, which is what Net Revenue Retention (NRR) and Gross Revenue Retention (GRR) read.

Expansion Classification

A customer adding seats to the product they already have is growing differently from a customer buying a new module; operators read the first as product pull and investors count both. This dimension records which kind of growth each event is.

Applies to: Revenue_Event where event_type is expansion, contraction or reactivation, plus every Amendment_Event record. A price cut or a restructured contract that lowers MRR is a contraction tagged pricing_adjustment or recontracting. ARR-O reads those tags whatever the direction.

Values

TagDefinitionExample
same_productMore of what the customer already has. Seat adds, tier upgrades within the same module.20 → 30 seats on the same Professional plan.
new_moduleCustomer purchases a distinct product module they did not have before.Analytics customer adds the Automation module.
new_buying_centreA different department or division within the same legal entity starts purchasing.Engineering team adopts the product already used by Marketing.
pricing_adjustmentMRR change driven by pricing action, not usage or scope change.Annual price increase of 5% on renewal.
recontractingMRR change driven by contract restructuring (e.g., monthly → annual, co-terming).Customer consolidates three monthly subscriptions into one annual contract.
usage_realisationMRR change from usage commitments being met or exceeded.Customer exceeds their committed API call volume, triggering overage billing.

Why This Matters

Expansion classification separates the Operating form of Net Revenue Retention (NRR-O) from its Market form (NRR-M).

  • NRR-O (Operating) focuses on organic, durable expansion: same_product and usage_realisation. These signal product-market fit and natural customer growth.
  • NRR-M (Market) includes all expansion types because investor-comparable NRR counts everything that is not net-new logo acquisition.

With expansion classification the same ledger reports organic growth apart from growth that came through new modules, new buying centres or pricing actions. Each number answers a different question.


Cost Function Attribution

Sales and marketing (S&M) spend to win a logo and implementation labour to onboard it are both costs of getting a paying customer. Only the first appears in the CAC that investors benchmark, so this dimension classifies every cost by the function it serves.

Applies to: all Cost_Event records.

Values

TagDefinitionExample
gtmGo-to-market costs: demand generation, sales compensation, partner commissions.$45,000 monthly marketing spend; $12,000 SDR compensation.
implementationCosts to deploy and configure the product for a new customer.40 hours of solutions engineering at $150/hr.
onboardingCosts to train and enable a new customer post-implementation.CSM time for 90-day onboarding programme.
infrastructureHosting, compute, storage and third-party service costs (COGS).AWS monthly bill; Datadog monitoring.
supportReactive customer assistance: tickets, escalations, troubleshooting.Support team salaries; helpdesk tooling.
success_engineeringProactive customer engagement: health monitoring, adoption programmes, QBRs.CS team salaries; Gainsight licensing.
account_managementRenewal and expansion selling to existing customers.Account executive compensation for upsell quota.
research_developmentBuilding the product. Not customer-attributable.Engineering and product salaries; development tooling.
general_administrativeRunning the company. Not customer-attributable.Finance, legal, HR, facilities.
services_deliveryDelivering paid professional services.Consultant time on a billable project.
recruitingHiring.Agency fees; recruiter time.
partner_programRunning the partner programme.Partner enablement, portal, marketing development funds.
partner_commissionCommissions paid to partners on sourced deals.15% referral fee on a closed deal.

Every cost event carries one cost_function value (Rule 3), so the enum covers all costs, including those outside the customer lifecycle.

Why This Matters

Cost function attribution separates CAC-O from CAC-M.

  • CAC-O (Operating) includes all costs to make a customer productive: gtm + implementation + onboarding. This reflects the true economic cost of acquiring a revenue-generating customer.
  • CAC-M (Market) includes only gtm costs, matching the S&M-based CAC that investors use for benchmarking.

Tagging each cost once lets both forms come from the same cost events, where a team without the tag ends up maintaining two separate cost allocation models.


Tagging Rules

Every CEL event is tagged according to these rules.

Rule 1: Every event gets a Lifecycle tag

All five event classes receive exactly one lifecycle_attribution tag.

Rule 2: Revenue growth and amendments get an Expansion tag

Revenue_Event records where event_type is expansion, contraction or reactivation, plus every Amendment_Event record, receive exactly one expansion_classification tag.

Rule 3: Cost events get a Cost Function tag

All Cost_Event records receive exactly one cost_function tag.

Rule 4: Tags are mutually exclusive within a dimension

An event cannot have two lifecycle tags, two expansion tags or two cost function tags. If an action spans two categories, it must be recorded as two CEL events with separate tags.

Rule 5: Tags are assigned at event creation

ATL tags are set when the CEL event is created and are immutable thereafter, consistent with the CEL’s immutability principle. Corrections require new events.


Example Tagged Events

These examples show CEL events with their ATL tags applied.

1. New Customer Acquisition

{
  "event_class": "Revenue_Event",
  "event_id": "rev-001",
  "event_date": "2026-02-01",
  "customer_id": "cust-1042",
  "subscription_id": "sub-2001",
  "event_type": "new",
  "mrr_change": 500.00,
  "currency": "USD",
  "prior_mrr": 0.00,
  "new_mrr": 500.00,
  "lifecycle_attribution": "acquisition"
}

2. Organic Seat Expansion

{
  "event_class": "Amendment_Event",
  "event_id": "amd-001",
  "event_date": "2026-02-10",
  "customer_id": "cust-0512",
  "subscription_id": "sub-0890",
  "amendment_type": "seat_change",
  "mrr_change": 500.00,
  "prior_quantity": 20,
  "new_quantity": 30,
  "lifecycle_attribution": "expansion",
  "expansion_classification": "same_product"
}

3. Cross-Module Upsell

{
  "event_class": "Amendment_Event",
  "event_id": "amd-002",
  "event_date": "2026-03-01",
  "customer_id": "cust-0512",
  "subscription_id": "sub-0891",
  "amendment_type": "add_on",
  "mrr_change": 800.00,
  "lifecycle_attribution": "expansion",
  "expansion_classification": "new_module"
}

4. GTM Spend (Shared Cost)

{
  "event_class": "Cost_Event",
  "event_id": "cost-002",
  "event_date": "2026-02-28",
  "cost_centre": "marketing",
  "cost": 45000.00,
  "currency": "USD",
  "cost_type": "services",
  "customer_id": null,
  "description": "February demand generation campaigns",
  "lifecycle_attribution": "acquisition",
  "cost_function": "gtm"
}

5. Onboarding Labour (Customer-Specific Cost)

{
  "event_class": "Cost_Event",
  "event_id": "cost-001",
  "event_date": "2026-02-05",
  "cost_centre": "services",
  "cost": 6000.00,
  "currency": "USD",
  "cost_type": "personnel",
  "customer_id": "cust-1042",
  "description": "40 hrs implementation engineering @ $150/hr",
  "lifecycle_attribution": "activation",
  "cost_function": "implementation"
}

6. Retention Success Servicing

{
  "event_class": "Cost_Event",
  "event_id": "cost-003",
  "event_date": "2026-02-12",
  "cost_centre": "customer_success",
  "cost": 2400.00,
  "currency": "USD",
  "cost_type": "personnel",
  "customer_id": "cust-0783",
  "description": "16 hrs success engineering for at-risk retention",
  "lifecycle_attribution": "servicing",
  "cost_function": "success_engineering"
}

Example SQL

ATL tags live as columns on CEL event tables. Querying by ATL dimension is a simple WHERE clause.

CAC-O (Operating): Full Acquisition Cost

CAC-O adds implementation and onboarding cost to GTM cost. This matches the cac operating form in formulas.json.

SELECT
    (SELECT SUM(cost)
     FROM cel_cost_events
     WHERE cost_function IN ('gtm', 'implementation', 'onboarding')
       AND event_date BETWEEN :period_start AND :period_end)
  / NULLIF((SELECT COUNT(DISTINCT customer_id)
            FROM cel_revenue_events
            WHERE event_type = 'new'
              AND event_date BETWEEN :period_start AND :period_end), 0) AS cac_o;

CAC-M (Market): GTM-Only Acquisition Cost

SELECT
    (SELECT SUM(cost)
     FROM cel_cost_events
     WHERE cost_function = 'gtm'
       AND event_date BETWEEN :period_start AND :period_end)
  / NULLIF((SELECT COUNT(DISTINCT customer_id)
            FROM cel_revenue_events
            WHERE event_type = 'new'
              AND event_date BETWEEN :period_start AND :period_end), 0) AS cac_m;

NRR-O (Operating): Organic Retention

SELECT
    SUM(CASE WHEN event_type IN ('expansion') AND expansion_classification IN ('same_product', 'usage_realisation')
             THEN mrr_change ELSE 0 END)
  + SUM(CASE WHEN event_type IN ('contraction', 'churn')
             THEN mrr_change ELSE 0 END)
  + SUM(CASE WHEN event_type = 'renewal' THEN new_mrr ELSE 0 END)
AS nrr_o_numerator
FROM cel_revenue_events
WHERE lifecycle_attribution IN ('retention', 'expansion')
  AND (expansion_classification IS NULL
       OR expansion_classification IN ('same_product', 'usage_realisation'))
  AND event_date BETWEEN '2025-03-01' AND '2026-02-28';

How O/M Metrics Use ATL

ATL tags are the mechanism that distinguishes Operating (O) from Market (M) metric forms. O-form metrics reflect internal economic reality, the numbers ops teams use to run the business. M-form metrics match investor-comparable definitions, the numbers boards and investors benchmark against peers. The pattern is consistent:

MetricOperating (O) IncludesMarket (M) Includes
CACcost_function ∈ (gtm, implementation, onboarding)cost_function = gtm
NRRexpansion_classification ∈ (same_product, usage_realisation)All expansion_classification except net-new logos
LTVContribution margin (includes implementation, onboarding costs)Gross margin (COGS only)
ChurnRevenue churn: MRR-weighted churned and contraction MRRLogo-based: binary churned/active
ARRDurable ARR: excludes recontracting, pricing_adjustment (trailing 12 months, customers active at period end)Contracted ARR: all recurring revenue
LTV:CACLTV-O over CAC-O (contribution margin; gtm, implementation and onboarding cost)LTV-M over CAC-M (gross margin; gtm cost only)
CAC PaybackCAC-O over ARPA × GM-OCAC-M over ARPA × GM-M

The full inclusion/exclusion rules for each dual-lens Core metric are specified as ATL Inclusion lines in the O/M subsections of Core Metrics. Rule of 40 has no separate O/M form and needs none. The ATL dimensions defined here are the building blocks for those rules.


Relationship to Existing Metrics

Each dual-lens Core metric keeps one canonical formula. For CAC, ARR, LTV, LTV:CAC, CAC Payback and Gross Margin the canonical formula equals the Market (M) form. Core Metrics declares the Operating (O) and Market (M) forms beside each canonical formula, with a Bridge subsection that reconciles the two numbers.

ATL supplies the tags both forms filter on, so the O form, the M form and the bridge between them all come from the same CEL events.

Try searching for:

↑↓navigate↵select