Queries · q277 · Head of Risk and Payments · week 2, night 1
“Among the accounts with 5+ failed logins in February 2025, how many went on to log in successfully afterward, and how soon — i.e. was this a near-miss or just noise?”
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 Rosa Van den Berg, Head of Data
An enterprise prospect sent a security and compliance questionnaire covering account security, access control, privacy requests, data retention and audit trails. Sales wants answers backed by evidence from our own systems, not by policy documents.
The manager, at the start of week 2
Subject: Re: Questionnaire memo — good work, a few threads to pull
Claire,
This is a strong memo, and the gaps you flagged are exactly the kind of thing I'd rather surface now than have a prospect's security team find later. A few things stand out and I want to understand them better before we finalize anything.
The February 2025 login spike is the one that worries me most. A 10x jump in failures with no corresponding rise in flagged suspicious activity is a real detection gap, not just a reporting curiosity — if that was a credential-stuffing attempt, I need to know whether it actually got anywhere.
Questions for this week:
Keep the role/permission logging gap and the broken query as noted — no need to keep spending slots chasing those; I'll raise the first with engineering myself and we can note the second as a known limitation in the memo.
Thanks, Aylin
The analyst · week 2, night 1, request 2 of 3
Aylin flagged the Feb-2025 login spike as her top worry this week and split it into two distinct questions (concentration vs. near-miss outcome), so I'm giving it two of tonight's three slots since they're different grains (merchant-level vs. account-outcome-level) and shouldn't be bundled. For the third slot I'm taking a cheap, low-risk shot at the DSAR rejection-timing question using a completely different, simpler path than the one that broke twice last week: data_subject_requests.updated_at itself, with no JSON/change_history involved — if these 3 records weren't touched again after rejection, updated_at is a reasonable (if imperfect) proxy for "when was this decided," and it avoids re-spending slots on the broken query. I'm holding incidents (#3) and the retention-exposure check (#4) for night 2, since we have 4 nights this week and the spike is clearly the most time-sensitive item. Keeping outputs aggregate (merchant names are fine, per other teams' precedent; no individual emails/usernames).
The engineer · 1 dry run on the empty schema, then the submission
WITH failed_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = false AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01' ), cohort AS ( SELECT email, COUNT(*) AS failed_cnt, MAX(occurred_at) AS last_failed_at FROM failed_feb GROUP BY email HAVING COUNT(*) >= 5 ), success_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = true AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01' ), cohort_outcome AS ( SELECT c.email, c.failed_cnt, c.last_failed_at, MIN(s.occurred_at) AS first_success_at FROM cohort c LEFT JOIN success_feb s ON s.email = c.email AND s.occurred_at > c.last_failed_at GROUP BY c.email, c.failed_cnt, c.last_failed_at ), bucketed AS ( SELECT email, failed_cnt, CASE WHEN first_success_at IS NULL THEN 'never_succeeded_in_month' WHEN first_success_at <= last_failed_at + INTERVAL '1 hour' THEN 'succeeded_within_1h' WHEN first_success_at <= last_failed_at + INTERVAL '24 hour' THEN 'succeeded_within_24h' ELSE 'succeeded_later_in_month' END AS outcome_bucket FROM cohort_outcome ) SELECT b.outcome_bucket, COUNT(*) AS email_count, ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM cohort), 1) AS pct_of_cohort, ROUND(AVG(b.failed_cnt) FILTER (WHERE b.outcome_bucket <> 'never_succeeded_in_month'), 2) AS avg_failed_attempts_before_success, COUNT(DISTINCT la.tenant_id) AS distinct_tenants_affected FROM bucketed b JOIN login_attempts la ON la.email = b.email AND la.occurred_at >= DATE '2025-02-01' AND la.occurred_at < DATE '2025-03-01' GROUP BY b.outcome_bucket ORDER BY CASE b.outcome_bucket WHEN 'succeeded_within_1h' THEN 1 WHEN 'succeeded_within_24h' THEN 2 WHEN 'succeeded_later_in_month' THEN 3 WHEN 'never_succeeded_in_month' THEN 4 END
“Query compiles and returns the expected columns in the required bucket order.”
“Submitted. Summary of the approach:
- Cohort: distinct emails with ≥5 succeeded=false rows in Feb 2025 (matched on email across tenants, since login_attempts.email is unique per tenant, not globally).
- Bucketing: for each cohort email, took its last failed attempt in Feb, then the first subsequent succeeded=true attempt in Feb; classified the gap into the four requested buckets.
- Metrics: email_count and pct_of_cohort per bucket; avg_failed_attempts_before_success (NULL for never_succeeded_in_month); distinct_tenants_affected counted from all Feb login_attempts rows tied to that email.
Flagged in the submit note that the cross-tenant email matching was an interpretive choice, since the schema only guarantees email uniqueness within a tenant.”
As Claire Dubois saw it, from the small dataset the agents worked on
outcome_bucket | email_count | pct_of_cohort | avg_failed_attempts_before_success | distinct_tenants_affected -------------------------+-------------+---------------+------------------------------------+-------------------------- succeeded_within_1h | 42 | 41.2 | 5.6 | 3 succeeded_within_24h | 12 | 11.8 | 5.0 | 2 succeeded_later_in_month | 89 | 87.3 | 5.51 | 2 never_succeeded_in_month | 452 | 443.1 | NULL | 3 (4 rows)
The memo and the queries that followed; links found by title, so inferred
Later queries that build on this report:
It builds on:
Changed only where the benchmark needs the same result on every system
WITH failed_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = false AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01'),cohort AS ( SELECT email, COUNT(*) AS failed_cnt, MAX(occurred_at) AS last_failed_at FROM failed_feb GROUP BY email HAVING COUNT(*) >= 5),success_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = true AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01'),cohort_outcome AS ( SELECT c.email, c.failed_cnt, c.last_failed_at, SELECT c.email AS email, c.failed_cnt AS failed_cnt, c.last_failed_at AS last_failed_at, MIN(s.occurred_at) AS first_success_at FROM cohort c LEFT JOIN success_feb s ON s.email = c.email AND s.occurred_at > c.last_failed_at GROUP BY c.email, c.failed_cnt, c.last_failed_at),bucketed AS ( SELECT email, failed_cnt, CASE WHEN first_success_at IS NULL THEN 'never_succeeded_in_month' WHEN first_success_at <= last_failed_at + INTERVAL '1 hour' THEN 'succeeded_within_1h' WHEN first_success_at <= last_failed_at + INTERVAL '24 hour' THEN 'succeeded_within_24h' ELSE 'succeeded_later_in_month' END AS outcome_bucket FROM cohort_outcome)SELECT b.outcome_bucket, b.outcome_bucket AS outcome_bucket, COUNT(*) AS email_count, ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM cohort), 1) AS pct_of_cohort, ROUND(AVG(b.failed_cnt) FILTER (WHERE b.outcome_bucket <> 'never_succeeded_in_month'), 2) AS avg_failed_attempts_before_success, 100.0 * COUNT(*) / (SELECT COUNT(*) FROM cohort) AS pct_of_cohort, AVG(CAST(b.failed_cnt AS NUMERIC(18,6))) FILTER (WHERE b.outcome_bucket <> 'never_succeeded_in_month') AS avg_failed_attempts_before_success, COUNT(DISTINCT la.tenant_id) AS distinct_tenants_affectedFROM bucketed bJOIN login_attempts la ON la.email = b.email AND la.occurred_at >= DATE '2025-02-01' AND la.occurred_at < DATE '2025-03-01'GROUP BY b.outcome_bucketORDER BY CASE b.outcome_bucket WHEN 'succeeded_within_1h' THEN 1 WHEN 'succeeded_within_24h' THEN 2 WHEN 'succeeded_later_in_month' THEN 3 WHEN 'never_succeeded_in_month' THEN 4ENDEND NULLS LAST
WITH failed_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = false AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01' ), cohort AS ( SELECT email, COUNT(*) AS failed_cnt, MAX(occurred_at) AS last_failed_at FROM failed_feb GROUP BY email HAVING COUNT(*) >= 5 ), success_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = true AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01' ), cohort_outcome AS ( SELECT c.email AS email, c.failed_cnt AS failed_cnt, c.last_failed_at AS last_failed_at, MIN(s.occurred_at) AS first_success_at FROM cohort c LEFT JOIN success_feb s ON s.email = c.email AND s.occurred_at > c.last_failed_at GROUP BY c.email, c.failed_cnt, c.last_failed_at ), bucketed AS ( SELECT email, failed_cnt, CASE WHEN first_success_at IS NULL THEN 'never_succeeded_in_month' WHEN first_success_at <= last_failed_at + INTERVAL '1 hour' THEN 'succeeded_within_1h' WHEN first_success_at <= last_failed_at + INTERVAL '24 hour' THEN 'succeeded_within_24h' ELSE 'succeeded_later_in_month' END AS outcome_bucket FROM cohort_outcome ) SELECT b.outcome_bucket AS outcome_bucket, COUNT(*) AS email_count, 100.0 * COUNT(*) / (SELECT COUNT(*) FROM cohort) AS pct_of_cohort, AVG(CAST(b.failed_cnt AS NUMERIC(18,6))) FILTER (WHERE b.outcome_bucket <> 'never_succeeded_in_month') AS avg_failed_attempts_before_success, COUNT(DISTINCT la.tenant_id) AS distinct_tenants_affected FROM bucketed b JOIN login_attempts la ON la.email = b.email AND la.occurred_at >= DATE '2025-02-01' AND la.occurred_at < DATE '2025-03-01' GROUP BY b.outcome_bucket ORDER BY CASE b.outcome_bucket WHEN 'succeeded_within_1h' THEN 1 WHEN 'succeeded_within_24h' THEN 2 WHEN 'succeeded_later_in_month' THEN 3 WHEN 'never_succeeded_in_month' THEN 4 END 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 Claire Dubois (analyst for the Head of Risk and Payments): Title: February 2025 repeat-failure accounts: did they succeed afterward? Question: Among the accounts with 5+ failed logins in February 2025, how many went on to log in successfully afterward, and how soon — i.e. was this a near-miss or just noise? Grain: one row per outcome bucket, computed over the cohort of distinct emails with >=5 failed login_attempts rows in February 2025 (previously counted at 102) Columns: - outcome_bucket (succeeded_within_1h / succeeded_within_24h / succeeded_later_in_month / never_succeeded_in_month) - email_count - pct_of_cohort - avg_failed_attempts_before_success (for buckets with a success; blank for never_succeeded) - distinct_tenants_affected Details: Source: login_attempts. Define the cohort as distinct email values with >=5 failed (succeeded=false) rows in Feb 2025. For each such email, find its last failed attempt in Feb 2025, then look for the first subsequent succeeded=true attempt by that same email within February 2025; bucket by the time gap (within 1h, within 24h, later in the month) or 'never_succeeded_in_month' if none found. Report only the aggregated bucket counts — do not print individual email addresses. Order buckets: succeeded_within_1h, succeeded_within_24h, succeeded_later_in_month, never_succeeded_in_month. Check your query with the warehouse's dry_run tool, then hand it in with submit.
dry_runWITH failed_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = false AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01' ), cohort AS ( SELECT email, COUNT(*) AS failed_cnt, MAX(occurred_at) AS last_failed_at FROM failed_feb GROUP BY email HAVING COUNT(*) >= 5 ), success_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = true AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01' ), cohort_outcome AS ( SELECT c.email, c.failed_cnt, c.last_failed_at, MIN(s.occurred_at) AS first_success_at FROM cohort c LEFT JOIN success_feb s ON s.email = c.email AND s.occurred_at > c.last_failed_at GROUP BY c.email, c.failed_cnt, c.last_failed_at ), bucketed AS ( SELECT email, failed_cnt, CASE WHEN first_success_at IS NULL THEN 'never_succeeded_in_month' WHEN first_success_at <= last_failed_at + INTERVAL '1 hour' THEN 'succeeded_within_1h' WHEN first_success_at <= last_failed_at + INTERVAL '24 hour' THEN 'succeeded_within_24h' ELSE 'succeeded_later_in_month' END AS outcome_bucket FROM cohort_outcome ) SELECT b.outcome_bucket, COUNT(*) AS email_count, ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM cohort), 1) AS pct_of_cohort, ROUND(AVG(b.failed_cnt) FILTER (WHERE b.outcome_bucket <> 'never_succeeded_in_month'), 2) AS avg_failed_attempts_before_success, COUNT(DISTINCT la.tenant_id) AS distinct_tenants_affected FROM bucketed b JOIN login_attempts la ON la.email = b.email AND la.occurred_at >= DATE '2025-02-01' AND la.occurred_at < DATE '2025-03-01' GROUP BY b.outcome_bucket ORDER BY CASE b.outcome_bucket WHEN 'succeeded_within_1h' THEN 1 WHEN 'succeeded_within_24h' THEN 2 WHEN 'succeeded_later_in_month' THEN 3 WHEN 'never_succeeded_in_month' THEN 4 END
STATUS: COMPILES (dry run on the empty schema, no data read) COLUMNS: outcome_bucket, email_count, pct_of_cohort, avg_failed_attempts_before_success, distinct_tenants_affected
submitWITH failed_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = false AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01' ), cohort AS ( SELECT email, COUNT(*) AS failed_cnt, MAX(occurred_at) AS last_failed_at FROM failed_feb GROUP BY email HAVING COUNT(*) >= 5 ), success_feb AS ( SELECT email, occurred_at FROM login_attempts WHERE succeeded = true AND email IS NOT NULL AND occurred_at >= DATE '2025-02-01' AND occurred_at < DATE '2025-03-01' ), cohort_outcome AS ( SELECT c.email, c.failed_cnt, c.last_failed_at, MIN(s.occurred_at) AS first_success_at FROM cohort c LEFT JOIN success_feb s ON s.email = c.email AND s.occurred_at > c.last_failed_at GROUP BY c.email, c.failed_cnt, c.last_failed_at ), bucketed AS ( SELECT email, failed_cnt, CASE WHEN first_success_at IS NULL THEN 'never_succeeded_in_month' WHEN first_success_at <= last_failed_at + INTERVAL '1 hour' THEN 'succeeded_within_1h' WHEN first_success_at <= last_failed_at + INTERVAL '24 hour' THEN 'succeeded_within_24h' ELSE 'succeeded_later_in_month' END AS outcome_bucket FROM cohort_outcome ) SELECT b.outcome_bucket, COUNT(*) AS email_count, ROUND(100.0 * COUNT(*) / (SELECT COUNT(*) FROM cohort), 1) AS pct_of_cohort, ROUND(AVG(b.failed_cnt) FILTER (WHERE b.outcome_bucket <> 'never_succeeded_in_month'), 2) AS avg_failed_attempts_before_success, COUNT(DISTINCT la.tenant_id) AS distinct_tenants_affected FROM bucketed b JOIN login_attempts la ON la.email = b.email AND la.occurred_at >= DATE '2025-02-01' AND la.occurred_at < DATE '2025-03-01' GROUP BY b.outcome_bucket ORDER BY CASE b.outcome_bucket WHEN 'succeeded_within_1h' THEN 1 WHEN 'succeeded_within_24h' THEN 2 WHEN 'succeeded_later_in_month' THEN 3 WHEN 'never_succeeded_in_month' THEN 4 END
Submitted to tonight's batch. Your work on this request is done.