Queries · q268 · Head of Merchant Success · week 2, night 1
“Is Castell Fasteners Q4 web traffic decline normal seasonal behavior shared by other B2B wholesale merchants, or a Castell-specific anomaly?”
Fictional people at a fictional company, each played by a language-model agent. Who they are and what they are told
Week 2; shared with Chloé Marchetti, Head of Growth Marketing and Daniel Achterberg, VP Customer Experience
Churn has become a board topic, for merchants and for their shoppers. A cross-functional task force wants to understand which experiences precede leaving, and which early signals would let us act before it happens.
The manager, at the start of week 2
Subject: Next week's priorities — QBR follow-ups + the churn task force
Hi Arjun,
Really useful memo — thank you. A few things jumped out that I want to understand better, plus a new cross-functional ask that's going to need a slot or two this week.
What surprised me / needs explaining first:
My questions for this week:
New context — the churn task force: Churn is now a board topic, both merchant churn and end-shopper churn, and I'm leading this jointly with Chloé Marchetti and Daniel Achterberg. The deliverable the three of us owe the board is a shortlist of early-warning signals — things we can observe weeks or months before a merchant (or a merchant's shoppers) leaves — and a recommendation on which of those signals is reliable enough to act on. It feeds directly into two decisions: whether Merchant Success should get a proactive outreach trigger for at-risk accounts, and whether Growth Marketing and CX get an equivalent retention trigger for end-shoppers. So anything you can tell me this week about what preceded past departures — on the merchant side especially, since that's my piece — is directly useful input, even if it's partial. I'll compare notes with Chloé's and Daniel's analysts before we draft anything for the board.
Given the slot limits, prioritize in this order: Castell explanation, then the task-force churn pattern, then support/CSAT if a slot remains.
Thanks, Samuel
Subject: CX signals for the churn task force
Arjun,
A few things I'd want the task force to look at from the shopper/support side:
If we can pin down even one or two of these as reliable early signals, it changes what Samuel's team and I should be monitoring week to week rather than finding out after the fact.
Daniel
Subject: Churn task force — what I'd like us to look at from Growth
Hi Arjun,
Glad this is getting cross-functional attention. From the marketing side, here's what I think matters:
Happy to jump on a call if useful — mainly want to make sure whatever "early warning" signals come out of this include the marketing-touch side, not just support or payment signals.
Best, Chloé
The analyst · week 2, night 1, request 1 of 1
Testing single-request submission after a schema error with the full 3-report batch.
The engineer · 1 dry run on the empty schema, then the submission
SELECT t.name AS merchant_name, t.industry, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') AS sessions_q4_2023, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') AS sessions_q4_2024, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') AS sessions_q4_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') = 0 THEN NULL ELSE ROUND(100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01'), 1) END AS yoy_growth_pct_2024_to_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') = 0 THEN NULL ELSE ROUND(100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01'), 1) END AS yoy_growth_pct_2023_to_2024 FROM tenants t LEFT JOIN web_sessions ws ON ws.tenant_id = t.id WHERE t.name IN ( 'Castell Fasteners', 'OfficeHub Nordic', 'Deskline Supplies', 'Ballycorran Industrial Supply', 'Midland Safety Wear', 'Polder Packaging', 'Kontor24 Burobedarf' ) GROUP BY t.id, t.name, t.industry ORDER BY sessions_q4_2025 DESC, t.id ASC LIMIT 50
“Query compiles fine. Submitting.”
“Submitted. The report counts raw web_sessions rows with started_at in Oct 1–Dec 31 for each of 2023/2024/2025 per B2B wholesale peer, with YoY growth percentages left blank when the prior-year base is zero, ordered by 2025 Q4 sessions descending (tie-break tenant_id).”
As Arjun Patel saw it, from the small dataset the agents worked on
merchant_name | industry | sessions_q4_2023 | sessions_q4_2024 | sessions_q4_2025 | yoy_growth_pct_2024_to_2025 | yoy_growth_pct_2023_to_2024 ------------------------------+---------------------------+------------------+------------------+------------------+-----------------------------+---------------------------- Ballycorran Industrial Supply | Industrial Supplies (B2B) | 62 | 75 | 87 | 16.0 | 21.0 OfficeHub Nordic | Office Supplies (B2B) | 32 | 37 | 69 | 86.5 | 15.6 Castell Fasteners | Industrial Supplies (B2B) | 31 | 47 | 42 | -10.6 | 51.6 Midland Safety Wear | Industrial Supplies (B2B) | 26 | 36 | 40 | 11.1 | 38.5 Polder Packaging | Industrial Supplies (B2B) | 17 | 14 | 26 | 85.7 | -17.6 Deskline Supplies | Office Supplies (B2B) | 13 | 16 | 14 | -12.5 | 23.1 (6 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
SELECT t.name AS merchant_name, t.industry, t.industry AS industry, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') AS sessions_q4_2023, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') AS sessions_q4_2024, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') AS sessions_q4_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') = 0 THEN NULL ELSE ROUND(100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01'), 1) ELSE 100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') END AS yoy_growth_pct_2024_to_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') = 0 THEN NULL ELSE ROUND(100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01'), 1) ELSE 100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') END AS yoy_growth_pct_2023_to_2024FROM tenants tLEFT JOIN web_sessions ws ON ws.tenant_id = t.idWHERE t.name IN ( 'Castell Fasteners', 'OfficeHub Nordic', 'Deskline Supplies', 'Ballycorran Industrial Supply', 'Midland Safety Wear', 'Polder Packaging', 'Kontor24 Burobedarf')GROUP BY t.id, t.name, t.industryORDER BY sessions_q4_2025 DESC, t.id ASCLIMIT 50ORDER BY sessions_q4_2025 DESC NULLS FIRST, t.id ASC NULLS LAST{{fetch_first(50)}}
SELECT t.name AS merchant_name, t.industry AS industry, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') AS sessions_q4_2023, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') AS sessions_q4_2024, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') AS sessions_q4_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') = 0 THEN NULL ELSE 100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') END AS yoy_growth_pct_2024_to_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') = 0 THEN NULL ELSE 100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') END AS yoy_growth_pct_2023_to_2024 FROM tenants t LEFT JOIN web_sessions ws ON ws.tenant_id = t.id WHERE t.name IN ( 'Castell Fasteners', 'OfficeHub Nordic', 'Deskline Supplies', 'Ballycorran Industrial Supply', 'Midland Safety Wear', 'Polder Packaging', 'Kontor24 Burobedarf' ) GROUP BY t.id, t.name, t.industry ORDER BY sessions_q4_2025 DESC NULLS FIRST, t.id ASC NULLS LAST FETCH FIRST 50 ROWS ONLY
SELECT t.name AS merchant_name, t.industry AS industry, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') AS sessions_q4_2023, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') AS sessions_q4_2024, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') AS sessions_q4_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') = 0 THEN NULL ELSE 100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') END AS yoy_growth_pct_2024_to_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') = 0 THEN NULL ELSE 100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') END AS yoy_growth_pct_2023_to_2024 FROM tenants t LEFT JOIN web_sessions ws ON ws.tenant_id = t.id WHERE t.name IN ( 'Castell Fasteners', 'OfficeHub Nordic', 'Deskline Supplies', 'Ballycorran Industrial Supply', 'Midland Safety Wear', 'Polder Packaging', 'Kontor24 Burobedarf' ) GROUP BY t.id, t.name, t.industry ORDER BY sessions_q4_2025 DESC NULLS FIRST, t.id ASC NULLS LAST LIMIT 50
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 Arjun Patel (analyst for the Head of Merchant Success): Title: Castell Fasteners traffic drop: seasonal pattern or anomaly across B2B wholesale merchants Question: Is Castell Fasteners Q4 web traffic decline normal seasonal behavior shared by other B2B wholesale merchants, or a Castell-specific anomaly? Grain: one row per B2B wholesale merchant (tenant) Columns: - merchant name - industry - web sessions Oct-Dec 2023 - web sessions Oct-Dec 2024 - web sessions Oct-Dec 2025 - YoY growth pct 2024 to 2025 - YoY growth pct 2023 to 2024 Details: Tables web_sessions (started_at, tenant_id) and tenants (name, industry). Restrict to the B2B wholesale peer group: Castell Fasteners, OfficeHub Nordic, Deskline Supplies, Ballycorran Industrial Supply, Midland Safety Wear, Polder Packaging, Kontor24 Burobedarf. For each merchant count web_sessions with started_at from Oct 1 through Dec 31 in 2023, 2024 and 2025 separately. YoY growth pct 2024 to 2025 equals the 2025 count minus the 2024 count, divided by the 2024 count, blank if the 2024 count is zero; YoY growth pct 2023 to 2024 defined the same way. Order by web sessions Oct-Dec 2025 descending, tie-break tenant_id ascending. Cap 50 rows. Check your query with the warehouse's dry_run tool, then hand it in with submit.
dry_runSELECT t.name AS merchant_name, t.industry, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') AS sessions_q4_2023, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') AS sessions_q4_2024, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') AS sessions_q4_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') = 0 THEN NULL ELSE ROUND(100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01'), 1) END AS yoy_growth_pct_2024_to_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') = 0 THEN NULL ELSE ROUND(100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01'), 1) END AS yoy_growth_pct_2023_to_2024 FROM tenants t LEFT JOIN web_sessions ws ON ws.tenant_id = t.id WHERE t.name IN ( 'Castell Fasteners', 'OfficeHub Nordic', 'Deskline Supplies', 'Ballycorran Industrial Supply', 'Midland Safety Wear', 'Polder Packaging', 'Kontor24 Burobedarf' ) GROUP BY t.id, t.name, t.industry ORDER BY sessions_q4_2025 DESC, t.id ASC LIMIT 50
STATUS: COMPILES (dry run on the empty schema, no data read) COLUMNS: merchant_name, industry, sessions_q4_2023, sessions_q4_2024, sessions_q4_2025, yoy_growth_pct_2024_to_2025, yoy_growth_pct_2023_to_2024
submitSELECT t.name AS merchant_name, t.industry, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') AS sessions_q4_2023, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') AS sessions_q4_2024, COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') AS sessions_q4_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') = 0 THEN NULL ELSE ROUND(100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2025-10-01' AND ws.started_at < DATE '2026-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01'), 1) END AS yoy_growth_pct_2024_to_2025, CASE WHEN COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01') = 0 THEN NULL ELSE ROUND(100.0 * (COUNT(*) FILTER (WHERE ws.started_at >= DATE '2024-10-01' AND ws.started_at < DATE '2025-01-01') - COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01')) / COUNT(*) FILTER (WHERE ws.started_at >= DATE '2023-10-01' AND ws.started_at < DATE '2024-01-01'), 1) END AS yoy_growth_pct_2023_to_2024 FROM tenants t LEFT JOIN web_sessions ws ON ws.tenant_id = t.id WHERE t.name IN ( 'Castell Fasteners', 'OfficeHub Nordic', 'Deskline Supplies', 'Ballycorran Industrial Supply', 'Midland Safety Wear', 'Polder Packaging', 'Kontor24 Burobedarf' ) GROUP BY t.id, t.name, t.industry ORDER BY sessions_q4_2025 DESC, t.id ASC LIMIT 50
Submitted to tonight's batch. Your work on this request is done.