# Multi-touch attribution contract. Write and approve it before any query runs.
# Field rules: references/mta-contract.md. Any rule change is a new model_version.
model_version: "<outcome>_<model>_v1"
decision: "<one sentence from the attribution brief>"
owner: "<role>"
approved_on: ""

outcome: "<one event at one grain, for example first_paid_order_per_customer>"
outcome_ledger_query: "<metrics.md metric ID; the outcome table must reconcile with this query by count and value per currency>"
unit: "<customer, opportunity, account>"
dedupe_rule: "<what makes two rows the same outcome>"
time_basis: "<payment timestamp, opportunity create date>"
reporting_timezone: "UTC"
population: "<included customers or accounts>"
exclusions: ["internal", "test", "<other flags set at collection>"]

lookback_days: 0
lookback_basis: "<lag p50 and p90 from uncapped history, mature cohorts only, date range used; truncated yes or no>"
data_history_starts: "YYYY-MM-DD"

eligible_touchpoints:
  - "<paid clicks with click ID or tagged URL>"
  - "<organic search, organic social, referral, email clicks>"
excluded_touchpoints:
  - "direct"
  - "<impressions and opens, unless a separate labelled view>"
collapse_rule: "<for example one touch per channel per session>"
touch_ordering:
  timestamp_precision: "<per source, for example web sessions to the second, CRM campaign responses date only>"
  tie_rule: "<for example source priority web > crm > offline, then touch_id ascending>"
  date_only_touches: "<start of day in reporting_timezone, or excluded from position and decay rules>"
rounding_rule: "store unrounded weights and values; round only for display; residual to <stated touch, for example the last eligible touch>"
touch_source_fields: "<GA4 export: collected_traffic_source or session_traffic_source_last_click, never traffic_source>"
referral_exclusions: ["<payment providers>", "<identity providers>", "<own subdomains>"]
click_id_precedence: "a click ID (gclid, wbraid, gbraid, fbclid, li_fat_id, msclkid, ttclid, plus any platform in stack.md) classes the touch as that platform's paid click even without UTMs"
internal_utm_rule: "<touches with utm_source equal to the own domain are excluded>"
email_scanner_rule: "<for example email clicks within 60 seconds of send, or several links in the same second, are excluded>"
native_lead_forms: "<lead form contacts with no session reported as their own channel line>"

identity_rule: "<allowed links between anonymous IDs, users, contacts, accounts>"
allowed_identity_link_types: ["<for example logged_in_user_id>", "<verified_crm_contact>"]
account_membership: "<as of touch date, with effective dates; known vs inferred kept apart>"

credit_rule:
  model: "<first_observed, last_non_direct, linear, position_based, time_decay>"
  unit_of_credit: "<per interaction or per channel>"
  one_touch_path: "100% to the touch"
  two_touch_path: "<for example 50/50>"
  position_weights: "<for example 40/20/40, only for position_based>"
  half_life_days: "<only for time_decay; default the median observed lag, sensitivity at half and double>"
no_eligible_touchpoint: "unattributed"

value_basis: "<for example net of discounts and refunds as of cutoff, before tax and shipping>"
refund_cutoff: "<days after outcome, or not applicable>"
currency_handling: "<separate totals by currency, or conversion at named rate and date>"
repeat_and_renewal_handling: "<separate view>"

reporting_mode: "<restate or snapshot>"
reference_views: ["first_observed", "last_non_direct"]

invariants:
  - "outcome table reconciles with outcome_ledger_query by count and value per currency, before any credit is computed"
  - "each eligible outcome appears once"
  - "every outcome has credit rows, unattributed included"
  - "weights sum to 1 per outcome"
  - "credited touches occur before the outcome and inside the lookback"
  - "every credited touch uses an identity link type in allowed_identity_link_types"
  - "touch source checks run: first-acquisition share among multi-source users under 5%, referral domains, internal UTMs, click IDs classed as direct, scanner clicks, lead forms, in-app browsers"
  - "tied first or last touches counted with their value share; alternate tie order rerun when above 5%"
  - "NULL timestamps, weights or credited values fail their checks"
  - "credited value per outcome equals outcome value"
  - "totals reconcile per currency"
  - "coverage reported as count share and value share"
