Queries · q373 · Head of Lifecycle Marketing · week 2, night 2
“Using date-proximity matching instead of the unusable order_id link, do loyalty members' orders that coincide with a points redemption on the same calendar day show a different refund rate than their other orders?”
Fictional people at a fictional company, each played by a language-model agent. Who they are and what they are told
Week 1; shared with Tobias Lindqvist, Chief Financial Officer
Is the loyalty and referral programme worth it? Do members and referred customers behave differently from others, and what does the programme cost?
The manager, at the start of week 2
Subject: Re: Loyalty & referral — thank you, and where to dig next
Ingrid, this is excellent — especially catching that the refund-rate gap was a vertical mix artifact. Good instinct to go back and break that out rather than let the scary headline stand.
What surprised me most, and what I want explained before we take this to Tobias as a joint recommendation: a 19.4% cost-to-member-revenue ratio is strikingly high, and members showing lower revenue and order counts than non-members is the opposite of what a loyalty programme is supposed to produce. I don't want to present "the programme loses money" to leadership until I understand whether that's a true causal effect or another mix artifact like the refund rate turned out to be — since 72% of members sit in one vertical, I'm wary of a second apples-to-oranges comparison hiding in there.
Questions for this week, in my own words:
The B2B extension question can wait — I agree we shouldn't open that door until we trust the member economics number. Let's keep that out of this week's slots unless there's room left over.
Thanks again, Ingrid — this is exactly the kind of rigor I want from this team.
Best, Aisha
The analyst · week 2, night 2, request 1 of 3
Night 1 answered Aisha's Q1 cleanly: within Apparel and controlling for tenure, order counts and refund rates between members and non-members are essentially indistinguishable in every tenure band (refund rates all cluster 33-40% regardless of segment) - the refund-rate and order-frequency 'penalty' really was mostly mix artifact. But a new, robust finding emerged: average order value is 28-40% lower for members than non-members in every single tenure band within Apparel - consistent and large, so that's the real driver of lower member revenue, and it needs explaining before I call it a verdict. Report 2 answered Q2 well: redemption rate rises steadily with cohort age (4% for 2-month-old cohorts up to ~32-37% for cohorts over 2 years old) and then plateaus around that 32-37% level even for the oldest 2023 cohorts - so it's both a timing lag (explains why young cohorts drag the blended rate down) and a structural ceiling (most points, even given 3 years, never get redeemed) - meaning the liability will keep growing in euros as we add members, while each cohort's own eventual redemption converges to roughly a third of what's issued. Report 3 gave a clean, important negative result for Q3: order_id is populated on 100% of 'earn' transactions but 0% of 343 'burn' transactions - the data model genuinely never records which order (if any) a redemption applied to, so the order_id-based gaming test was never going to work; I need a different join (same-user, same-day proximity) before I can call this inconclusive for good. Tonight: (1) retry the gaming test using date-proximity matching instead of order_id; (2) decompose the Apparel AOV gap into subtotal vs discount to see if heavier discounting (consistent with points use) explains it; (3) start on Q4 by comparing top-revenue members against the rest of the member base to see if better performers use the programme differently.
The engineer · 1 dry run on the empty schema, then the submission
WITH loyalty_user_ids AS ( SELECT DISTINCT user_id FROM loyalty_accounts ), eligible_orders AS ( SELECT o.id AS order_id, o.tenant_id, o.user_id, o.placed_at, o.grand_total, o.currency_code, o.status FROM orders o JOIN loyalty_user_ids lu ON lu.user_id = o.user_id WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01' ), burn_by_user_day AS ( SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points FROM loyalty_transactions WHERE direction = 'burn' GROUP BY user_id, CAST(occurred_at AS DATE) ), classified_orders AS ( SELECT eo.order_id, eo.user_id, eo.placed_at, eo.grand_total, eo.currency_code, eo.status, bd.day_points, CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type FROM eligible_orders eo LEFT JOIN burn_by_user_day bd ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE) ), refund_flags AS ( SELECT co.order_id, co.order_type, CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0) OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id) THEN 1 ELSE 0 END AS is_refunded FROM classified_orders co ), order_value_eur AS ( SELECT co.order_id, co.order_type, CASE WHEN co.currency_code = 'EUR' THEN co.grand_total ELSE co.grand_total / er.rate END AS grand_total_eur FROM classified_orders co LEFT JOIN exchange_rates er ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE) WHERE co.status <> 'cancelled' ), order_counts AS ( SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day FROM classified_orders GROUP BY order_type ), refund_rates AS ( SELECT order_type, AVG(is_refunded) * 100 AS refund_rate_pct FROM refund_flags GROUP BY order_type ), avg_values AS ( SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur FROM order_value_eur GROUP BY order_type ) SELECT oc.order_type, oc.order_count, oc.distinct_customers, ROUND(rr.refund_rate_pct, 2) AS refund_rate_pct, ROUND(av.avg_order_value_eur, 2) AS avg_order_value_eur, ROUND(oc.avg_points_redeemed_that_day, 1) AS avg_points_redeemed_that_day FROM order_counts oc JOIN refund_rates rr ON rr.order_type = oc.order_type JOIN avg_values av ON av.order_type = oc.order_type ORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END, oc.order_type
“Query compiles and returns the expected columns. Submitting.”
“Submitted. Summary of approach:
- Population: orders from users with a loyalty_accounts row, placed_at in 2023‑01‑01–2025‑12‑31.
- Classification: an order is 'same-day points redemption' if the same user_id has any loyalty_transactions row with direction='burn' on the same calendar date as placed_at (date-proximity match, as requested instead of the broken order_id link).
- refund_rate_pct: share of orders (all statuses) with payments.amount_refunded > 0 or a linked order_returns row.
- avg_order_value_eur: average grand_total of non-cancelled orders, converted to EUR using exchange_rates (EUR→currency rate as of the order date).
- avg_points_redeemed_that_day: average of the summed absolute burn points for that user/day (0 for the no-redemption group).
Noted in the submit note that points are summed across multiple same-day burns per user before averaging, and that order_count/refund_rate include all order statuses while avg_order_value_eur excludes cancelled orders, per the stated definitions.”
As Ingrid Solberg saw it, from the small dataset the agents worked on
order_type | order_count | distinct_customers | refund_rate_pct | avg_order_value_eur | avg_points_redeemed_that_day ------------------------------+-------------+--------------------+-----------------+---------------------+----------------------------- same-day points redemption | 5 | 5 | 40.0 | 183.69 | 500.0 no same-day points redemption | 4936 | 1330 | 32.35 | 194.41 | 0.0 (2 rows)
The memo and the queries that followed; links found by title, so inferred
It builds on:
Changed only where the benchmark needs the same result on every system
WITH loyalty_user_ids AS ( SELECT DISTINCT user_id FROM loyalty_accounts),eligible_orders AS ( SELECT o.id AS order_id, o.tenant_id, o.user_id, o.placed_at, o.grand_total, o.currency_code, o.status SELECT o.id AS order_id, o.tenant_id AS tenant_id, o.user_id AS user_id, o.placed_at AS placed_at, o.grand_total AS grand_total, o.currency_code AS currency_code, o.status AS status FROM orders o JOIN loyalty_user_ids lu ON lu.user_id = o.user_id WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01'),burn_by_user_day AS ( SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points FROM loyalty_transactions WHERE direction = 'burn' GROUP BY user_id, CAST(occurred_at AS DATE)),classified_orders AS ( SELECT eo.order_id, eo.user_id, eo.placed_at, eo.grand_total, eo.currency_code, eo.status, bd.day_points, eo.order_id AS order_id, eo.user_id AS user_id, eo.placed_at AS placed_at, eo.grand_total AS grand_total, eo.currency_code AS currency_code, eo.status AS status, bd.day_points AS day_points, CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type FROM eligible_orders eo LEFT JOIN burn_by_user_day bd ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE)),refund_flags AS ( SELECT co.order_id, co.order_type, co.order_id AS order_id, co.order_type AS order_type, CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0) OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id) THEN 1 ELSE 0 END AS is_refunded FROM classified_orders co),order_value_eur AS ( SELECT co.order_id, co.order_type, co.order_id AS order_id, co.order_type AS order_type, CASE WHEN co.currency_code = 'EUR' THEN co.grand_total ELSE co.grand_total / er.rate END AS grand_total_eur ELSE CAST(co.grand_total / er.rate AS NUMERIC(18,6)) END AS grand_total_eur FROM classified_orders co LEFT JOIN exchange_rates er ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE) WHERE co.status <> 'cancelled'),order_counts AS ( SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day FROM classified_orders GROUP BY order_type),refund_rates AS ( SELECT order_type, AVG(is_refunded) * 100 AS refund_rate_pct SELECT order_type, AVG(CAST(is_refunded AS NUMERIC(18,6))) * 100 AS refund_rate_pct FROM refund_flags GROUP BY order_type),avg_values AS ( SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur FROM order_value_eur GROUP BY order_type)SELECT oc.order_type, oc.order_count, oc.distinct_customers, ROUND(rr.refund_rate_pct, 2) AS refund_rate_pct, ROUND(av.avg_order_value_eur, 2) AS avg_order_value_eur, ROUND(oc.avg_points_redeemed_that_day, 1) AS avg_points_redeemed_that_day oc.order_type AS order_type, oc.order_count AS order_count, oc.distinct_customers AS distinct_customers, rr.refund_rate_pct AS refund_rate_pct, av.avg_order_value_eur AS avg_order_value_eur, oc.avg_points_redeemed_that_day AS avg_points_redeemed_that_dayFROM order_counts ocJOIN refund_rates rr ON rr.order_type = oc.order_typeJOIN avg_values av ON av.order_type = oc.order_typeORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END, oc.order_typeORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END NULLS LAST, oc.order_type NULLS LAST
WITH loyalty_user_ids AS ( SELECT DISTINCT user_id FROM loyalty_accounts ), eligible_orders AS ( SELECT o.id AS order_id, o.tenant_id AS tenant_id, o.user_id AS user_id, o.placed_at AS placed_at, o.grand_total AS grand_total, o.currency_code AS currency_code, o.status AS status FROM orders o JOIN loyalty_user_ids lu ON lu.user_id = o.user_id WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01' ), burn_by_user_day AS ( SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points FROM loyalty_transactions WHERE direction = 'burn' GROUP BY user_id, CAST(occurred_at AS DATE) ), classified_orders AS ( SELECT eo.order_id AS order_id, eo.user_id AS user_id, eo.placed_at AS placed_at, eo.grand_total AS grand_total, eo.currency_code AS currency_code, eo.status AS status, bd.day_points AS day_points, CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type FROM eligible_orders eo LEFT JOIN burn_by_user_day bd ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE) ), refund_flags AS ( SELECT co.order_id AS order_id, co.order_type AS order_type, CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0) OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id) THEN 1 ELSE 0 END AS is_refunded FROM classified_orders co ), order_value_eur AS ( SELECT co.order_id AS order_id, co.order_type AS order_type, CASE WHEN co.currency_code = 'EUR' THEN co.grand_total ELSE CAST(co.grand_total / er.rate AS NUMERIC(18,6)) END AS grand_total_eur FROM classified_orders co LEFT JOIN exchange_rates er ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE) WHERE co.status <> 'cancelled' ), order_counts AS ( SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day FROM classified_orders GROUP BY order_type ), refund_rates AS ( SELECT order_type, AVG(CAST(is_refunded AS NUMERIC(18,6))) * 100 AS refund_rate_pct FROM refund_flags GROUP BY order_type ), avg_values AS ( SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur FROM order_value_eur GROUP BY order_type ) SELECT oc.order_type AS order_type, oc.order_count AS order_count, oc.distinct_customers AS distinct_customers, rr.refund_rate_pct AS refund_rate_pct, av.avg_order_value_eur AS avg_order_value_eur, oc.avg_points_redeemed_that_day AS avg_points_redeemed_that_day FROM order_counts oc JOIN refund_rates rr ON rr.order_type = oc.order_type JOIN avg_values av ON av.order_type = oc.order_type ORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END NULLS LAST, oc.order_type NULLS LAST
The agents' own records, as the role play wrote them; only the personal data of the person who ran it is redacted
Report request from Ingrid Solberg (analyst for the Head of Lifecycle Marketing): Title: Refund rate on orders with a same-day points redemption Question: Using date-proximity matching instead of the unusable order_id link, do loyalty members' orders that coincide with a points redemption on the same calendar day show a different refund rate than their other orders? Grain: one row per order type among loyalty members' orders: 'same-day points redemption' vs 'no same-day points redemption' Columns: - order_type - order_count - distinct_customers - refund_rate_pct - avg_order_value_eur - avg_points_redeemed_that_day Details: Population: all orders (any status, placed_at between 2023-01-01 and 2025-12-31) placed by users who have a loyalty_accounts row. For each such order, classify as 'same-day points redemption' if there exists a loyalty_transactions row for the same user_id with direction = 'burn' whose occurred_at falls on the same calendar date as the order's placed_at; otherwise 'no same-day points redemption'. refund_rate_pct = share of orders in the group with payments.amount_refunded greater than 0 OR an order_returns row, same definition used throughout. avg_order_value_eur = average grand_total of non-cancelled orders in the group, converted to EUR via exchange_rates (as_of placed_at). avg_points_redeemed_that_day = average absolute points value of the matching same-day burn transaction(s) for the 'same-day' group (0 for the other group). Order rows: 'same-day points redemption' first. Check your query with the warehouse's dry_run tool, then hand it in with submit.
dry_runWITH loyalty_user_ids AS ( SELECT DISTINCT user_id FROM loyalty_accounts ), eligible_orders AS ( SELECT o.id AS order_id, o.tenant_id, o.user_id, o.placed_at, o.grand_total, o.currency_code, o.status FROM orders o JOIN loyalty_user_ids lu ON lu.user_id = o.user_id WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01' ), burn_by_user_day AS ( SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points FROM loyalty_transactions WHERE direction = 'burn' GROUP BY user_id, CAST(occurred_at AS DATE) ), classified_orders AS ( SELECT eo.order_id, eo.user_id, eo.placed_at, eo.grand_total, eo.currency_code, eo.status, bd.day_points, CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type FROM eligible_orders eo LEFT JOIN burn_by_user_day bd ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE) ), refund_flags AS ( SELECT co.order_id, co.order_type, CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0) OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id) THEN 1 ELSE 0 END AS is_refunded FROM classified_orders co ), order_value_eur AS ( SELECT co.order_id, co.order_type, CASE WHEN co.currency_code = 'EUR' THEN co.grand_total ELSE co.grand_total / er.rate END AS grand_total_eur FROM classified_orders co LEFT JOIN exchange_rates er ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE) WHERE co.status <> 'cancelled' ), order_counts AS ( SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day FROM classified_orders GROUP BY order_type ), refund_rates AS ( SELECT order_type, AVG(is_refunded) * 100 AS refund_rate_pct FROM refund_flags GROUP BY order_type ), avg_values AS ( SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur FROM order_value_eur GROUP BY order_type ) SELECT oc.order_type, oc.order_count, oc.distinct_customers, ROUND(rr.refund_rate_pct, 2) AS refund_rate_pct, ROUND(av.avg_order_value_eur, 2) AS avg_order_value_eur, ROUND(oc.avg_points_redeemed_that_day, 1) AS avg_points_redeemed_that_day FROM order_counts oc JOIN refund_rates rr ON rr.order_type = oc.order_type JOIN avg_values av ON av.order_type = oc.order_type ORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END, oc.order_type
STATUS: COMPILES (dry run on the empty schema, no data read) COLUMNS: order_type, order_count, distinct_customers, refund_rate_pct, avg_order_value_eur, avg_points_redeemed_that_day
submitWITH loyalty_user_ids AS ( SELECT DISTINCT user_id FROM loyalty_accounts ), eligible_orders AS ( SELECT o.id AS order_id, o.tenant_id, o.user_id, o.placed_at, o.grand_total, o.currency_code, o.status FROM orders o JOIN loyalty_user_ids lu ON lu.user_id = o.user_id WHERE o.placed_at >= DATE '2023-01-01' AND o.placed_at < DATE '2026-01-01' ), burn_by_user_day AS ( SELECT user_id, CAST(occurred_at AS DATE) AS burn_date, SUM(ABS(points)) AS day_points FROM loyalty_transactions WHERE direction = 'burn' GROUP BY user_id, CAST(occurred_at AS DATE) ), classified_orders AS ( SELECT eo.order_id, eo.user_id, eo.placed_at, eo.grand_total, eo.currency_code, eo.status, bd.day_points, CASE WHEN bd.user_id IS NOT NULL THEN 'same-day points redemption' ELSE 'no same-day points redemption' END AS order_type FROM eligible_orders eo LEFT JOIN burn_by_user_day bd ON bd.user_id = eo.user_id AND bd.burn_date = CAST(eo.placed_at AS DATE) ), refund_flags AS ( SELECT co.order_id, co.order_type, CASE WHEN EXISTS (SELECT 1 FROM payments p WHERE p.order_id = co.order_id AND p.amount_refunded > 0) OR EXISTS (SELECT 1 FROM order_returns r WHERE r.order_id = co.order_id) THEN 1 ELSE 0 END AS is_refunded FROM classified_orders co ), order_value_eur AS ( SELECT co.order_id, co.order_type, CASE WHEN co.currency_code = 'EUR' THEN co.grand_total ELSE co.grand_total / er.rate END AS grand_total_eur FROM classified_orders co LEFT JOIN exchange_rates er ON er.base_code = 'EUR' AND er.quote_code = co.currency_code AND er.as_of = CAST(co.placed_at AS DATE) WHERE co.status <> 'cancelled' ), order_counts AS ( SELECT order_type, COUNT(*) AS order_count, COUNT(DISTINCT user_id) AS distinct_customers, AVG(COALESCE(day_points,0)) AS avg_points_redeemed_that_day FROM classified_orders GROUP BY order_type ), refund_rates AS ( SELECT order_type, AVG(is_refunded) * 100 AS refund_rate_pct FROM refund_flags GROUP BY order_type ), avg_values AS ( SELECT order_type, AVG(grand_total_eur) AS avg_order_value_eur FROM order_value_eur GROUP BY order_type ) SELECT oc.order_type, oc.order_count, oc.distinct_customers, ROUND(rr.refund_rate_pct, 2) AS refund_rate_pct, ROUND(av.avg_order_value_eur, 2) AS avg_order_value_eur, ROUND(oc.avg_points_redeemed_that_day, 1) AS avg_points_redeemed_that_day FROM order_counts oc JOIN refund_rates rr ON rr.order_type = oc.order_type JOIN avg_values av ON av.order_type = oc.order_type ORDER BY CASE WHEN oc.order_type = 'same-day points redemption' THEN 0 ELSE 1 END, oc.order_type
Submitted to tonight's batch. Your work on this request is done.