mta-audit 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. mta_audit-0.1.0/.github/workflows/ci.yml +28 -0
  2. mta_audit-0.1.0/.github/workflows/publish.yml +23 -0
  3. mta_audit-0.1.0/.gitignore +14 -0
  4. mta_audit-0.1.0/CHANGELOG.md +30 -0
  5. mta_audit-0.1.0/LICENSE +21 -0
  6. mta_audit-0.1.0/PKG-INFO +389 -0
  7. mta_audit-0.1.0/README.md +334 -0
  8. mta_audit-0.1.0/benchmarks/__init__.py +1 -0
  9. mta_audit-0.1.0/benchmarks/criteo_benchmark.py +353 -0
  10. mta_audit-0.1.0/benchmarks/results/criteo_benchmark.json +253 -0
  11. mta_audit-0.1.0/benchmarks/results/criteo_benchmark.md +108 -0
  12. mta_audit-0.1.0/benchmarks/results/criteo_linear_attribution.csv +234 -0
  13. mta_audit-0.1.0/benchmarks/results/sample_report.html +717 -0
  14. mta_audit-0.1.0/benchmarks/results/sample_report.md +105 -0
  15. mta_audit-0.1.0/benchmarks/results/scoring_sensitivity.md +32 -0
  16. mta_audit-0.1.0/benchmarks/scoring_sensitivity.py +127 -0
  17. mta_audit-0.1.0/docs/api.md +80 -0
  18. mta_audit-0.1.0/docs/concepts.md +32 -0
  19. mta_audit-0.1.0/docs/methodology.md +156 -0
  20. mta_audit-0.1.0/docs/practitioner-review.md +27 -0
  21. mta_audit-0.1.0/docs/releasing.md +41 -0
  22. mta_audit-0.1.0/docs/stability.md +37 -0
  23. mta_audit-0.1.0/examples/criteo_example.ipynb +368 -0
  24. mta_audit-0.1.0/examples/quickstart.py +36 -0
  25. mta_audit-0.1.0/pyproject.toml +92 -0
  26. mta_audit-0.1.0/src/mta_audit/__init__.py +196 -0
  27. mta_audit-0.1.0/src/mta_audit/attribution/__init__.py +31 -0
  28. mta_audit-0.1.0/src/mta_audit/attribution/base.py +110 -0
  29. mta_audit-0.1.0/src/mta_audit/attribution/first_touch.py +5 -0
  30. mta_audit-0.1.0/src/mta_audit/attribution/last_touch.py +5 -0
  31. mta_audit-0.1.0/src/mta_audit/attribution/linear.py +5 -0
  32. mta_audit-0.1.0/src/mta_audit/attribution/markov.py +291 -0
  33. mta_audit-0.1.0/src/mta_audit/attribution/rules.py +33 -0
  34. mta_audit-0.1.0/src/mta_audit/audit.py +557 -0
  35. mta_audit-0.1.0/src/mta_audit/audits/__init__.py +83 -0
  36. mta_audit-0.1.0/src/mta_audit/audits/channel_concentration.py +117 -0
  37. mta_audit-0.1.0/src/mta_audit/audits/concentration.py +15 -0
  38. mta_audit-0.1.0/src/mta_audit/audits/contamination.py +178 -0
  39. mta_audit-0.1.0/src/mta_audit/audits/conversion_window.py +243 -0
  40. mta_audit-0.1.0/src/mta_audit/audits/data_quality.py +13 -0
  41. mta_audit-0.1.0/src/mta_audit/audits/exposure.py +189 -0
  42. mta_audit-0.1.0/src/mta_audit/audits/identity.py +39 -0
  43. mta_audit-0.1.0/src/mta_audit/audits/leakage.py +267 -0
  44. mta_audit-0.1.0/src/mta_audit/audits/model_disagreement.py +152 -0
  45. mta_audit-0.1.0/src/mta_audit/audits/model_stability.py +217 -0
  46. mta_audit-0.1.0/src/mta_audit/audits/path_quality.py +12 -0
  47. mta_audit-0.1.0/src/mta_audit/audits/path_sparsity.py +97 -0
  48. mta_audit-0.1.0/src/mta_audit/bootstrap.py +195 -0
  49. mta_audit-0.1.0/src/mta_audit/checks.py +476 -0
  50. mta_audit-0.1.0/src/mta_audit/core.py +30 -0
  51. mta_audit-0.1.0/src/mta_audit/datasets/__init__.py +58 -0
  52. mta_audit-0.1.0/src/mta_audit/datasets/criteo.py +331 -0
  53. mta_audit-0.1.0/src/mta_audit/datasets/evaluation.py +47 -0
  54. mta_audit-0.1.0/src/mta_audit/datasets/external.py +431 -0
  55. mta_audit-0.1.0/src/mta_audit/datasets/scenarios.py +149 -0
  56. mta_audit-0.1.0/src/mta_audit/datasets/synthetic.py +168 -0
  57. mta_audit-0.1.0/src/mta_audit/journeys.py +423 -0
  58. mta_audit-0.1.0/src/mta_audit/py.typed +1 -0
  59. mta_audit-0.1.0/src/mta_audit/results.py +647 -0
  60. mta_audit-0.1.0/src/mta_audit/robustness.py +341 -0
  61. mta_audit-0.1.0/src/mta_audit/sampling.py +96 -0
  62. mta_audit-0.1.0/src/mta_audit/schema.py +190 -0
  63. mta_audit-0.1.0/src/mta_audit/scoring.py +157 -0
  64. mta_audit-0.1.0/src/mta_audit/simulation/__init__.py +17 -0
  65. mta_audit-0.1.0/src/mta_audit/simulation/corruption.py +450 -0
  66. mta_audit-0.1.0/src/mta_audit/utils/__init__.py +10 -0
  67. mta_audit-0.1.0/src/mta_audit/utils/validation.py +5 -0
  68. mta_audit-0.1.0/src/mta_audit/visualization/__init__.py +19 -0
  69. mta_audit-0.1.0/src/mta_audit/visualization/plots.py +128 -0
  70. mta_audit-0.1.0/tests/conftest.py +14 -0
  71. mta_audit-0.1.0/tests/fixtures/criteo_mini.tsv +7 -0
  72. mta_audit-0.1.0/tests/fixtures/ignazio_mini.csv +6 -0
  73. mta_audit-0.1.0/tests/fixtures/triangulation_mini.csv +4 -0
  74. mta_audit-0.1.0/tests/integration/test_criteo.py +86 -0
  75. mta_audit-0.1.0/tests/test_attribution.py +42 -0
  76. mta_audit-0.1.0/tests/test_audit.py +57 -0
  77. mta_audit-0.1.0/tests/test_contract_hardening.py +142 -0
  78. mta_audit-0.1.0/tests/test_criteo_adapter.py +79 -0
  79. mta_audit-0.1.0/tests/test_external_synthetics.py +97 -0
  80. mta_audit-0.1.0/tests/test_journeys.py +65 -0
  81. mta_audit-0.1.0/tests/test_phase2.py +107 -0
  82. mta_audit-0.1.0/tests/test_phase3.py +106 -0
  83. mta_audit-0.1.0/tests/test_phase4.py +178 -0
  84. mta_audit-0.1.0/tests/test_phase5.py +108 -0
  85. mta_audit-0.1.0/tests/test_schema.py +54 -0
  86. mta_audit-0.1.0/tests/test_scoring_sensitivity.py +33 -0
  87. mta_audit-0.1.0/tests/test_uncertainty_robustness.py +378 -0
  88. mta_audit-0.1.0/tests/test_v02_readiness.py +138 -0
  89. mta_audit-0.1.0/uv.lock +1458 -0
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.11", "3.12", "3.13"]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - uses: actions/setup-python@v5
20
+ with:
21
+ python-version: ${{ matrix.python-version }}
22
+ cache: pip
23
+ - run: python -m pip install --upgrade pip
24
+ - run: python -m pip install -e ".[dev]"
25
+ - run: pytest
26
+ - run: ruff check src tests
27
+ - if: matrix.python-version == '3.11'
28
+ run: mypy
@@ -0,0 +1,23 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ contents: read
10
+ id-token: write
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ environment: pypi
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.11"
21
+ - run: python -m pip install --upgrade pip build
22
+ - run: python -m build
23
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,14 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .coverage
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ .venv/
8
+ build/
9
+ dist/
10
+ data/
11
+ *.tsv.gz
12
+ .mypy_cache/
13
+ benchmarks/zeta_*.py
14
+ benchmarks/results/zeta_*/
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ All notable changes follow [Keep a Changelog](https://keepachangelog.com/) conventions.
4
+
5
+ ## 0.1.0 - 2026-09-15
6
+
7
+ ### Added
8
+
9
+ - Add a standalone Python library for auditing observational multi-touch
10
+ attribution reliability.
11
+ - Add typed event validation and converter/non-converter journey construction.
12
+ - Add first-touch, last-touch, linear, and absorbing Markov attribution.
13
+ - Add data-quality, duplicate, path, window, identity-loss, touchpoint-loss,
14
+ temporal-stability, and model-disagreement checks.
15
+ - Add deterministic journey-level bootstrap attribution intervals and rank frequencies.
16
+ - Add decision robustness and rank/share assumption-sensitivity matrices.
17
+ - Add typed insufficient-evidence statuses that abstain from aggregate scoring.
18
+ - Add six deterministic known-condition stress scenarios.
19
+ - Add standalone Markdown and HTML reports.
20
+ - Add complete-user sampling with report-visible metadata.
21
+ - Add public Criteo and Hugging Face synthetic dataset adapters.
22
+ - Add independent JD-style and Criteo Research label-mismatch synthetic generators.
23
+ - Add a Poisson multi-touch synthesizer compatible with the PubliusV CSV schema.
24
+ - Add optional adapters for IgnazioDS journeys and triangulation user-level MTA tables.
25
+ - Identify Markov only when NULL/non-converter paths are observed.
26
+ - Score identity robustness in the default audit run.
27
+ - Treat date-grain repeated touches as informational, not duplicate failures.
28
+ - Fail data quality when converting events have zero conversion value.
29
+ - Add transparent configurable scoring weights, interpretation bands, and a
30
+ reproducible score-sensitivity benchmark.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 mta-audit contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,389 @@
1
+ Metadata-Version: 2.5
2
+ Name: mta-audit
3
+ Version: 0.1.0
4
+ Summary: Reliability audits for multi-touch attribution data and models.
5
+ Project-URL: Homepage, https://github.com/morantejr/mta-audit
6
+ Project-URL: Documentation, https://github.com/morantejr/mta-audit/tree/main/docs
7
+ Project-URL: Issues, https://github.com/morantejr/mta-audit/issues
8
+ Author: mta-audit contributors
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 mta-audit contributors
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: attribution,audit,data-quality,marketing-analytics
32
+ Classifier: Development Status :: 3 - Alpha
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Programming Language :: Python :: 3.11
36
+ Classifier: Programming Language :: Python :: 3.12
37
+ Classifier: Programming Language :: Python :: 3.13
38
+ Classifier: Typing :: Typed
39
+ Requires-Python: >=3.11
40
+ Requires-Dist: numpy>=1.26
41
+ Requires-Dist: pandas>=2.1
42
+ Provides-Extra: dev
43
+ Requires-Dist: matplotlib>=3.8; extra == 'dev'
44
+ Requires-Dist: mypy>=1.11; extra == 'dev'
45
+ Requires-Dist: pandas-stubs>=2.1; extra == 'dev'
46
+ Requires-Dist: pyarrow>=15; extra == 'dev'
47
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
48
+ Requires-Dist: pytest>=8; extra == 'dev'
49
+ Requires-Dist: ruff>=0.6; extra == 'dev'
50
+ Provides-Extra: parquet
51
+ Requires-Dist: pyarrow>=15; extra == 'parquet'
52
+ Provides-Extra: viz
53
+ Requires-Dist: matplotlib>=3.8; extra == 'viz'
54
+ Description-Content-Type: text/markdown
55
+
56
+ # mta-audit
57
+
58
+ **Stress-testing and reliability testing for multi-touch attribution.**
59
+
60
+ `mta-audit` evaluates whether campaign conclusions remain stable when
61
+ attribution windows, identity quality, touchpoint availability, attribution
62
+ models, sampling, and other measurement assumptions change.
63
+
64
+ > It does not estimate causal lift or incrementality.
65
+
66
+ This project is a standalone reliability library. Attribution systems still
67
+ allocate credit; this package scores whether journeys and model outputs are
68
+ stable enough to use.
69
+
70
+ Optional public-dataset adapters only map foreign tables onto the package event
71
+ schema.
72
+
73
+ ## What it catches
74
+
75
+ The public Criteo benchmark uses an explicit 8,000-user sample: 21,307 mapped
76
+ events, 639 anonymized campaigns, 8,144 journeys, and 586 conversions.
77
+
78
+ - Injecting 1–10% duplicate events was detected every time and reduced the
79
+ scoped data-quality score from **72.35 to 50.20–50.70**.
80
+ - Conversion-window campaign ranks reached a minimum Spearman correlation of
81
+ **0.588** across 1/3/7/14/30-day windows.
82
+ - Dropping 30% of eligible touchpoints produced **2.2% attribution-share
83
+ drift** and reduced campaign rank correlation to **0.972**.
84
+ - Fragmenting 20% of identities increased journeys from **8,144 to 8,908**.
85
+
86
+ See the [rendered sample audit](benchmarks/results/sample_report.html), its
87
+ [Markdown source](benchmarks/results/sample_report.md), and the full
88
+ [Criteo reliability scorecard](benchmarks/results/criteo_benchmark.md).
89
+ The sample is synthetic and deterministic; the Criteo figures are measured,
90
+ not illustrative.
91
+
92
+ ## Installation
93
+
94
+ Python 3.11–3.13 is supported.
95
+
96
+ ```bash
97
+ pip install "mta-audit @ git+https://github.com/morantejr/mta-audit.git@v0.1.0"
98
+ pip install "mta-audit[viz] @ git+https://github.com/morantejr/mta-audit.git@v0.1.0"
99
+ ```
100
+
101
+ PyPI publication is pending its account-side Trusted Publisher registration.
102
+ After that is connected, the shorter command will be `pip install mta-audit`.
103
+ For an unreleased main-branch snapshot:
104
+
105
+ ```bash
106
+ pip install "mta-audit @ git+https://github.com/morantejr/mta-audit.git"
107
+ ```
108
+
109
+ For contributors: `pip install -e ".[dev]"`.
110
+
111
+ ## Quickstart
112
+
113
+ ```python
114
+ import pandas as pd
115
+ from mta_audit import MTAAudit
116
+
117
+ data = pd.DataFrame({
118
+ "user_id": ["a", "a", "b", "b"],
119
+ "timestamp": pd.to_datetime([
120
+ "2026-01-01", "2026-01-03", "2026-01-02", "2026-01-04"
121
+ ]),
122
+ "channel": ["search", "email", "social", "direct"],
123
+ "conversion": [False, True, False, True],
124
+ })
125
+
126
+ report = MTAAudit(data=data).run(
127
+ bootstrap=True,
128
+ n_bootstrap=200,
129
+ random_state=42,
130
+ )
131
+ print(report.summary())
132
+ print(report.decision_robustness())
133
+ report.sensitivity_matrix(metric="rank")
134
+ report.to_dataframe()
135
+ report.to_json()
136
+ ```
137
+
138
+ Example output:
139
+
140
+ ```text
141
+ MTA Audit Reliability Report
142
+ Overall audit score: 67.5/100 — Fragile
143
+ Component scores:
144
+ - Data Quality: …
145
+ - Window Stability: …
146
+ - Identity Robustness: …
147
+ - Path Quality: …
148
+ - Model Agreement: …
149
+ - Temporal Stability: insufficient evidence
150
+ Checks run: 12 | Visible findings: 7
151
+ Markov removal effects: not evaluated
152
+ Channel grain: channel
153
+
154
+ Decision robustness:
155
+ Search remains top-two in 94% of tested scenarios.
156
+ Display and Social frequently change position; avoid a strong reallocation
157
+ between them based on this observational attribution analysis alone.
158
+ ```
159
+
160
+ Custom schemas and the advanced API remain concise:
161
+
162
+ ```python
163
+ audit = MTAAudit(
164
+ data=data,
165
+ user_col="visitor_id",
166
+ timestamp_col="event_time",
167
+ channel_col="source",
168
+ conversion_col="converted",
169
+ scoring_weights={"data_quality": 2, "model_agreement": 1},
170
+ )
171
+ report = audit.run(
172
+ attribution_models=["first_touch", "last_touch", "linear", "markov"],
173
+ conversion_windows=[7, 14, 30, 60],
174
+ checks=["data_quality", "conversion_window", "model_disagreement"],
175
+ simulations={"identity_loss": {"rates": [0.05, 0.10, 0.20]}},
176
+ bootstrap=True,
177
+ n_bootstrap=500,
178
+ random_state=42,
179
+ )
180
+ ```
181
+
182
+ For reusable bootstrap settings:
183
+
184
+ ```python
185
+ from mta_audit import BootstrapConfig
186
+
187
+ report = MTAAudit(data).run(
188
+ bootstrap=BootstrapConfig(
189
+ n_iterations=500,
190
+ confidence_level=0.90,
191
+ random_state=42,
192
+ )
193
+ )
194
+ report.bootstrap.to_dataframe()
195
+ ```
196
+
197
+ Bootstrap resamples complete journeys, never touchpoint rows. Its percentile
198
+ intervals and rank frequencies measure observational attribution stability;
199
+ they are not causal confidence intervals.
200
+
201
+ ## Checks
202
+
203
+ - Required fields, nulls, timestamps, channels, and duplicate events
204
+ - Conversion-window sensitivity and delayed-converter contamination
205
+ - First-touch, last-touch, linear, and absorbing Markov model disagreement
206
+ - Path sparsity and channel concentration
207
+ - Weekly or monthly temporal stability
208
+ - Converter/non-converter exposure comparison
209
+ - Deterministic identity, touchpoint, impression, and click-loss simulations
210
+
211
+ ## Methodology
212
+
213
+ Every audit emits a normalized 0–100 **audit robustness score**, severity,
214
+ observed metric, and recommendation. The score does not mean percent correct.
215
+ Related checks feed six reliability components:
216
+ `data_quality`, `window_stability`, `identity_robustness`, `path_quality`,
217
+ `model_agreement`, and `temporal_stability`. The overall formula is:
218
+
219
+ ```text
220
+ reliability = Σ(component score × normalized available-component weight)
221
+ ```
222
+
223
+ Only completed components are included; skipped checks are never treated as
224
+ perfect. Attribution models allocate observed conversion value. Markov credit
225
+ uses channel-removal effects from an absorbing transition chain.
226
+
227
+ Qualitative bands are Robust (90–100), Stable (80–89), Caution (70–79),
228
+ Fragile (60–69), and Highly Fragile (<60). The component scorecard is more
229
+ important than the aggregate.
230
+
231
+ ## Shareable reports and local sampling
232
+
233
+ ```python
234
+ markdown = report.to_markdown()
235
+ html = report.to_html()
236
+
237
+ from mta_audit import sample_for_audit
238
+ sample = sample_for_audit(data, max_journeys=100_000, random_state=42)
239
+ sampled_report = MTAAudit(sample).run()
240
+ print(sampled_report.sample_info)
241
+ ```
242
+
243
+ Sampling preserves complete user histories and marks the resulting report.
244
+ This remains a local pandas package; no warehouse or distributed execution is
245
+ included.
246
+
247
+ ## Thresholds and configuration
248
+
249
+ Default scoring weights are 20%, 15%, 15%, 15%, 20%, and 15% in the component
250
+ order above. Any non-negative relative values can be passed through
251
+ `scoring_weights`; they are normalized automatically over available components.
252
+ These are explicit policy defaults, not empirically estimated constants:
253
+ data quality and model agreement receive 20% because invalid inputs and
254
+ conclusion-changing model choice are direct decision risks; the other four
255
+ dimensions receive equal 15% weights. The round-number bands are likewise
256
+ communication thresholds, not confidence intervals.
257
+
258
+ The reproducible [score-policy sensitivity report](benchmarks/results/scoring_sensitivity.md)
259
+ reweights the committed Criteo components and shifts every rating cutoff by
260
+ five points. It shows how much the aggregate and label depend on those policy
261
+ choices. Component scores must remain visible; users should override weights
262
+ when their decision context differs.
263
+ Audit-specific threshold dataclasses such as `ConversionWindowThresholds`,
264
+ `ContaminationThresholds`, and `TemporalStabilityThresholds` expose warning
265
+ cutoffs. See [the methodology](docs/methodology.md) for formulas.
266
+
267
+ ## Visualization
268
+
269
+ With the `viz` extra installed, reports provide `plot_scorecard()`,
270
+ `plot_model_comparison()`, `plot_window_sensitivity()`, and
271
+ `plot_channel_volatility()`. Each returns a matplotlib `Axes`.
272
+
273
+ ## Limitations
274
+
275
+ Results depend on identity resolution, channel taxonomy, event collection, and
276
+ the selected lookback/conversion windows. Sparse paths make transition estimates
277
+ unstable. Converter/non-converter comparisons are confounded and are not lift
278
+ estimates. Tracking-loss simulations test sensitivity to specified corruption,
279
+ not the true unknown missingness process.
280
+
281
+ Converter-only sequencing tables do **not** identify Markov removal effects.
282
+ The report sets `markov_identified=false` in that case. Date-grain
283
+ timestamps are not treated as duplicates. Campaign-name "channels" are flagged as
284
+ fine grain.
285
+
286
+ Kaggle does not currently publish a licensed event-level multi-touch path dataset
287
+ with converters and non-converters comparable to Criteo. Public fixtures:
288
+
289
+ - Criteo Attribution Modeling (real impressions; see walkthrough below)
290
+ - Hugging Face [synthetic attribution benchmark](https://huggingface.co/datasets/lucianfialho/synthetic-attribution-benchmark) (CC BY 4.0)
291
+ - Independent generators inspired by JD MTA (Du et al., 2019) and Criteo Research
292
+ robust-label experiments (Bompaire et al., 2020): `simulate_jd_mta_events`,
293
+ `simulate_criteo_label_events`, `simulate_synthesizer_events`
294
+ - Optional CSV adapters for IgnazioDS journeys and the triangulation project's
295
+ user-level `df_mta.csv` (`load_ignazio_attribution`, `load_triangulation_mta`).
296
+ Those files are not stored in git. Weekly MMM / geo tables are out of scope.
297
+
298
+ ## Roadmap
299
+
300
+ Current stage: **0.1.0 alpha**. Next:
301
+
302
+ 1. Keep 0.1.x installable and documented (stability contract in
303
+ [docs/stability.md](docs/stability.md)).
304
+ 2. **Beta** when `run()` / report fields stay boring across a few tagged
305
+ releases and the Criteo reference scorecard is re-run before each tag.
306
+ 3. **1.0** when scoring defaults are frozen and third parties can depend on
307
+ the public API. Warehouse extracts stay out of this repository.
308
+
309
+ Later, optional work: more public-dataset adapters and richer performance
310
+ benchmarks.
311
+
312
+ See [concepts](docs/concepts.md), [methodology](docs/methodology.md),
313
+ [API reference](docs/api.md), [stability](docs/stability.md),
314
+ [releasing](docs/releasing.md), the
315
+ [external practitioner review protocol](docs/practitioner-review.md), and
316
+ [examples](examples/quickstart.py).
317
+
318
+ ## Criteo walkthrough
319
+
320
+ The public Criteo Attribution Modeling dataset (CC-BY-NC-SA-4.0) is the
321
+ real-world integration set for this package. **It is not stored in git.**
322
+
323
+ 1. Download `criteo_attribution_dataset.tsv.gz` from
324
+ [Hugging Face](https://huggingface.co/datasets/criteo/criteo-attribution-dataset)
325
+ (Criteo's published copy of Diemert et al., 2017).
326
+ 2. Save it as `./data/criteo_attribution_dataset.tsv.gz`, or let the loader
327
+ cache it under `~/.cache/mta-audit/` with `download=True`.
328
+ 3. Map impressions through the adapter — do **not** pass Criteo's impression-level
329
+ `conversion` flag straight into `conversion_col`.
330
+
331
+ ```python
332
+ from mta_audit import MTAAudit
333
+ from mta_audit.datasets import load_criteo_attribution, CriteoAttributionAdapter
334
+
335
+ # Explicit representative sample; pass sample_users=None for the full file.
336
+ df = load_criteo_attribution(path="./data/criteo_attribution_dataset.tsv.gz", sample_users=20000)
337
+ # equivalent: CriteoAttributionAdapter("./data/criteo_attribution_dataset.tsv.gz").load()
338
+
339
+ report = MTAAudit(data=df).run(
340
+ attribution_models=["first_touch", "last_touch", "linear", "markov"]
341
+ )
342
+ print(report.summary())
343
+ ```
344
+
345
+ Public synthetic journeys (named channels + NULL paths, CC BY 4.0):
346
+
347
+ ```python
348
+ from mta_audit.datasets import load_synthetic_attribution
349
+
350
+ events = load_synthetic_attribution(download=True)
351
+ report = MTAAudit(data=events).run(attribution_models=["linear", "markov"])
352
+ print(report.markov_identified)
353
+ ```
354
+
355
+ Independent research-style synthetics (no third-party generators vendored):
356
+
357
+ ```python
358
+ from mta_audit.datasets import (
359
+ simulate_criteo_label_events,
360
+ simulate_jd_mta_events,
361
+ simulate_synthesizer_events,
362
+ )
363
+
364
+ jd = simulate_jd_mta_events(n_users=200, random_state=42)
365
+ labels = simulate_criteo_label_events(n_users=400, random_state=42)
366
+ synth = simulate_synthesizer_events(n_users=300, random_state=42)
367
+ ```
368
+
369
+ Unit tests never require the file. Integration tests and the benchmark do:
370
+
371
+ ```bash
372
+ pytest # default, no Criteo download
373
+ pytest -m criteo # loads the local/public dataset
374
+ python benchmarks/criteo_benchmark.py --download --sample-users 20000
375
+ ```
376
+
377
+ Results from a completed run (8,000-user explicit sample) live in
378
+ [`benchmarks/results/criteo_benchmark.md`](benchmarks/results/criteo_benchmark.md).
379
+ On that run, injected duplicates dropped the data-quality score from ~72 to ~50,
380
+ 20% identity loss raised journey count from 8,144 to 8,908, and conversion-window
381
+ ranks correlated at only 0.59. The notebook `examples/criteo_example.ipynb` is
382
+ the measurement-team walkthrough.
383
+
384
+ Criteo campaigns are anonymized. Treat outputs as campaign-level attribution
385
+ reliability diagnostics, not named-channel budget recommendations.
386
+
387
+ Removal-effect Markov on ~700 campaigns is implemented with a numpy transition
388
+ matrix. `MarkovAttribution(max_channels=N)` can explicitly collapse a long tail
389
+ into `__OTHER__`; the benchmark does **not** do that by default.