Real UCI Online Retail transactions through layered ETL, a point-in-time feature store, a repeat-purchase model and a data-quality engine. Every figure on this page was written by the pipeline itself — this page is rebuilt by running it, not by editing it.
10/10 models, p95 latency 541 ms.
24.86% caught at ingestion, not silently loaded.
vs 0.684 baseline — +0.047 improvement.
11/11 assertions, 0 critical failures.
make all on a clean runner, then renders whatever
reports/*.json the pipeline produced. If the pipeline breaks or a
quality assertion fails, that shows up here.
Last run 2026-07-24 23:07 UTC · commit 445ddf3
· workflow run
Ten SQL models across three layers — staging, intermediate, marts — executed in dependency order. Bars show relative execution time; the figure is in the next column.
| Model | Layer | Rows | Time | Seconds | Status |
|---|---|---|---|---|---|
| stg_invoice_lines | staging | 392,690 | 0.5414s | ✓ success | |
| stg_invoice_lines_rejected | staging | 134,737 | 0.1708s | ✓ success | |
| stg_products | staging | 4,070 | 0.0212s | ✓ success | |
| stg_returns | staging | 9,288 | 0.0194s | ✓ success | |
| int_orders | intermediate | 18,532 | 0.0417s | ✓ success | |
| mart_cohort_retention | marts | 91 | 0.0127s | ✓ success | |
| mart_country_revenue | marts | 37 | 0.0084s | ✓ success | |
| mart_customer_features | marts | 4,338 | 0.0292s | ✓ success | |
| mart_product_performance | marts | 3,665 | 0.0557s | ✓ success | |
| mart_rfm_segments | marts | 4,338 | 0.0090s | ✓ success |
541,909 raw line items in, 392,690 loaded, 14,482 duplicates removed and 134,737 quarantined (mostly guest checkouts with no customer id) — the difference is accounted for, not dropped.
8 features computed as of each cutoff date, so a training row
only ever sees data that existed at that moment. The label is
repeat_purchase_next_90d.
✓ leakage check
passed
| As-of cutoff | Rows | Positives | Base rate |
|---|---|---|---|
| 2011-03-31 | 2,134 | 1,157 | 54.22% |
| 2011-06-30 | 2,960 | 1,466 | 49.53% |
| 2011-08-31 | 3,317 | 1,864 | 56.20% |
Predicts whether a customer orders again within 90 days. Trained on cutoffs 2011-03-31, 2011-06-30 and validated on 2011-08-31 — 5,094 training rows, 3,317 validation rows at a 56.20% base rate. The baseline is the obvious heuristic: rank customers by how recently they last ordered.
| Metric | Model | Baseline | Δ |
|---|---|---|---|
| ROC-AUC | 0.7305 | 0.6838 | +0.0467 |
| PR-AUC | 0.7949 | 0.7040 | +0.0909 |
| Top-decile lift | 1.683× | 1.360× | +0.323 |
Signed model coefficients. Direction is shown by which side of the axis the bar falls as well as by colour, and every bar carries its value.
| Feature | Weight | Value |
|---|---|---|
| orders_last_180d | ▲ +1.3942 | |
| units_last_90d | ▲ +1.0106 | |
| avg_line_value_90d | ▼ -0.9569 | |
| distinct_products_90d | ▲ +0.2320 | |
| orders_last_90d | ▲ +0.2188 | |
| revenue_last_90d | ▼ -0.1242 | |
| days_since_last_order | ▼ -0.1010 | |
| revenue_last_180d | ▲ +0.0354 |
11 YAML-declared assertions run against the warehouse after every pipeline execution, written to an audit table and scored. Critical failures fail the build.
| Check | Type | Severity | Observed | Threshold | Status |
|---|---|---|---|---|---|
| sales_volume | row_count_min | critical | 3.927e+05 | 1e+05 | ✓ pass |
| sales_freshness | freshness | critical | 1 | 2 | ✓ pass |
| customer_id_not_null | not_null | critical | 0 | 0 | ✓ pass |
| unit_price_positive | min_value | high | 0.001 | 0 | ✓ pass |
| quantity_positive | min_value | high | 1 | 1 | ✓ pass |
| orders_reconcile_lines | reconcile_count | high | 1.853e+04 | 1.853e+04 | ✓ pass |
| customer_features_unique | unique | high | 0 | 0 | ✓ pass |
| monetary_non_negative | min_value | high | 3.75 | 0 | ✓ pass |
| rfm_segments_not_orphaned | relationship | medium | 0 | 0 | ✓ pass |
| propensity_scores_not_orphaned | relationship | medium | 0 | 0 | ✓ pass |
| unattributable_rows_within_slo | quarantine_rate | medium | 0.2486 | 0.3 | ✓ pass |
It runs locally on DuckDB with no cloud account and no cost, and the same modelling logic ports to BigQuery and Dataform — see /bigquery.
make setup
make all
pytest -q