DB Olympics

Queries · q122 · Data Protection Officer · week 1, night 4

email_log actual retention vs. the stated 730-day delete policy

“Since email_log's retention policy is configured but inactive and has never run for any tenant, how much email data are we actually still holding well past the stated 730-day window?”

Manager · asked the questionInes LaurentData Protection Officer. Lawyer by training, previously at a European marketplace. Also reports to the board's audit committee.
Analyst · planned the reportPriyanka DesaiAuditor's mindset: traces individual records end to end to check that the totals are real.
Engineer · wrote the SQLBeaWrites SQL the way the company's BI tool generates it: verbose fully qualified aliases (t0, t1, ...), a subquery per measure joined back on the grain keys, COALESCE everywhere.

Fictional people at a fictional company, each played by a language-model agent. Who they are and what they are told

  1. Ines Laurent writes to Priyanka Desai

    The manager, at the start of week 1

    Subject: A few starting questions on privacy & data handling

    Hi Priyanka,

    Welcome aboard, and thank you for taking these on this week. As I get oriented, here's what I'd like to understand first. Given the slot constraints, please treat these as priorities in order — if only three fit this week, start from the top and we'll pick up the rest next week.

    1. How are we doing on privacy requests from shoppers? I want to know how many access/erasure/portability requests we're getting, how long they typically take to close, and whether any are overdue. This is the thing the board audit committee will ask about first, and it's also a legal deadline risk, so I need a realistic picture, not just a snapshot.
    2. What does our consent picture look like? I'd like a sense of how many of our users have actually opted in versus withdrawn or never given consent, and whether that's changed meaningfully over time. This tells me how exposed we are if we rely on consent for marketing or data use.
    3. Are there open compliance issues sitting unresolved, and how serious are they? I want to understand the volume and severity of flagged incidents (things like suspicious data access or retention problems) and how quickly they tend to get closed out. I need to know if we have a backlog building up anywhere.
    4. How long are we actually holding onto shopper data, and does it match what our retention rules say it should be? I'm less interested in the rulebook and more in whether reality matches it — are there data types we're sitting on well past when we said we would delete them?
    5. Are there any legal holds in place right now, and what do they cover? I want to know how many are active, what they're blocking, and whether any look stale (i.e., should have been released a while ago). This matters for both litigation readiness and for explaining why certain deletions haven't happened.

    For now, could you scope the first request for me? I'd like to see it broken down in a way that shows me trend over the last several months, not just a single total — I want to catch whether we're improving or falling behind.

    Let me know if any of these need to be split further once you see what the data looks like.

    Thanks, Ines

  2. Priyanka Desai plans the night

    The analyst · week 1, night 4, request 2 of 3

    The pieces from the last three nights line up almost too neatly to leave unverified: the 3 'rejected' DSARs (night 3, report 1) never get completed_at stamped — which inflated my earlier backlog numbers — and their received_at dates (2023-05-26, 2024-07-09, 2025-03-21) sit exactly one day before the 3 active legal holds' placed_at dates (2023-05-27, 2024-07-10, 2025-03-22) for the same three tenants (chargeback disputes). This looks like 'erasure correctly rejected pending an active legal hold,' which would completely reframe item 1 from 'overdue backlog' to 'holds that are now 1-2.5 years stale' — feeding directly into item 5. I want a direct join to confirm the same subject_user_id is involved before I write that into the memo, rather than relying on date coincidence. Separately, night 3's retention landscape report (report 2) surfaced the clearest answer yet to item 4: email_log has a 730-day/delete policy configured for all 120 tenants, but it is active=0 and never_run=120 for every single one — meaning it's pure paperwork, never enforced. I want to size that gap in actual months of retained email data. As a contrast, audit_log looks 'healthy' on paper (active, last_run_at=2025-12-31, action=archive) — I want to check whether old rows are actually leaving the live table, since 'archive' could just as easily mean nothing is really being purged in practice. This is my last night, so I'm spending all 3 slots on the highest-value remaining checks rather than broad new territory.

    email_log actual retention vs. the stated 730-day delete policy
    Question
    Since email_log's retention policy is configured but inactive and has never run for any tenant, how much email data are we actually still holding well past the stated 730-day window?
    One row per
    calendar month, based on email_log.created_at
    Columns
    • month (YYYY-MM)
    • emails logged in month (count)
    • days old as of 2026-01-05 (measured from month start)
    • exceeds 730-day retention (Y/N)
  3. Bea writes the SQL

    The engineer · 2 dry runs on the empty schema, then the submission

    Dry run 1 · STATUS: REJECTED
    SELECT
      to_char(t0.month_start, 'YYYY-MM') AS month,
      t0.email_count AS emails_logged,
      (DATE '2026-01-05' - t0.month_start) AS days_old_as_of_2026_01_05,
      CASE WHEN (DATE '2026-01-05' - t0.month_start) > 730 THEN 'Y' ELSE 'N' END AS exceeds_730_day_retention
    FROM (
      SELECT date_trunc('month', t1.created_at)::date AS month_start, COUNT(*) AS email_count
      FROM email_log t1
      WHERE t1.created_at >= DATE '2023-01-01' AND t1.created_at < DATE '2026-01-01'
      GROUP BY date_trunc('month', t1.created_at)
    ) t0
    ORDER BY t0.month_start ASC
    Dry run 2 · 1 change from the dry run before · STATUS: COMPILES (dry run on the empty schema, no data read)
    SELECT  to_char(t0.month_start, 'YYYY-MM') AS month,  strftime(t0.month_start, '%Y-%m') AS month,  t0.email_count AS emails_logged,  (DATE '2026-01-05' - t0.month_start) AS days_old_as_of_2026_01_05,  CASE WHEN (DATE '2026-01-05' - t0.month_start) > 730 THEN 'Y' ELSE 'N' END AS exceeds_730_day_retentionFROM (  SELECT date_trunc('month', t1.created_at)::date AS month_start, COUNT(*) AS email_count  FROM email_log t1  WHERE t1.created_at >= DATE '2023-01-01' AND t1.created_at < DATE '2026-01-01'  GROUP BY date_trunc('month', t1.created_at)) t0ORDER BY t0.month_start ASC

    “Query compiles cleanly with the right columns. Submitting.”

    Submitted · the SQL of the last dry run, unchanged · Submitted to tonight's batch. Your work on this request is done.

    “Submitted. The report gives one row per month (Jan 2023–Dec 2025) with the email count, days elapsed from that month's start to 2026-01-05, and a Y/N flag for exceeding the 730-day policy — directly sizing how much retained email data sits past the stated retention window across all 120 tenants.”

  4. The report comes back overnight

    As Priyanka Desai saw it, from the small dataset the agents worked on

    month   | emails_logged | days_old_as_of_2026_01_05 | exceeds_730_day_retention
    --------+---------------+---------------------------+--------------------------
    2023-01 |          1673 |                      1100 | Y                        
    2023-02 |          1906 |                      1069 | Y                        
    2023-03 |          2260 |                      1041 | Y                        
    2023-04 |          2338 |                      1010 | Y                        
    2023-05 |          2791 |                       980 | Y                        
    2023-06 |          2606 |                       949 | Y                        
    2023-07 |          2744 |                       919 | Y                        
    2023-08 |          2944 |                       888 | Y                        
    2023-09 |          3118 |                       857 | Y                        
    2023-10 |          3667 |                       827 | Y                        
    2023-11 |          5808 |                       796 | Y                        
    2023-12 |          5906 |                       766 | Y                        
    2024-01 |          4693 |                       735 | Y                        
    2024-02 |          3823 |                       704 | N                        
    2024-03 |          4042 |                       675 | N                        
    2024-04 |          4344 |                       644 | N                        
    2024-05 |          4691 |                       614 | N                        
    2024-06 |          4417 |                       583 | N                        
    2024-07 |          4846 |                       553 | N                        
    2024-08 |          4563 |                       522 | N                        
    2024-09 |          4674 |                       491 | N                        
    2024-10 |          5129 |                       461 | N                        
    2024-11 |          6713 |                       430 | N                        
    2024-12 |          9467 |                       400 | N                        
    2025-01 |          6387 |                       369 | N                        
    2025-02 |          4887 |                       338 | N                        
    2025-03 |          5597 |                       310 | N                        
    2025-04 |          5456 |                       279 | N                        
    2025-05 |          5715 |                       249 | N                        
    2025-06 |          5328 |                       218 | N                        
    2025-07 |          5749 |                       188 | N                        
    2025-08 |          5292 |                       157 | N                        
    2025-09 |          5919 |                       126 | N                        
    2025-10 |          6564 |                        96 | N                        
    2025-11 |          8047 |                        65 | N                        
    2025-12 |         11414 |                        35 | N                        
    (36 rows)
  5. What came of it

    The memo and the queries that followed; links found by title, so inferred

    Later queries that build on this report:

    It builds on:

  6. It becomes benchmark query q122

    Changed only where the benchmark needs the same result on every system

    • spellingcast
    • placeholderyear month
    • determinismthe standard leaves the place of NULLs in a sort to the implementation: NULLS LAST ascending, NULLS FIRST descending, as in the reference results
    The benchmark text, against the submitted SQL
    SELECT  strftime(t0.month_start, '%Y-%m') AS month,  {{year_month(t0.month_start)}} AS month,  t0.email_count AS emails_logged,  (DATE '2026-01-05' - t0.month_start) AS days_old_as_of_2026_01_05,  CASE WHEN (DATE '2026-01-05' - t0.month_start) > 730 THEN 'Y' ELSE 'N' END AS exceeds_730_day_retentionFROM (  SELECT date_trunc('month', t1.created_at)::date AS month_start, COUNT(*) AS email_count  SELECT CAST(date_trunc('month', t1.created_at) AS date) AS month_start, COUNT(*) AS email_count  FROM email_log t1  WHERE t1.created_at >= DATE '2023-01-01' AND t1.created_at < DATE '2026-01-01'  GROUP BY date_trunc('month', t1.created_at)) t0ORDER BY t0.month_start ASCORDER BY t0.month_start ASC NULLS LAST
    SELECT
      strftime(t0.month_start, '%Y-%m') AS month,
      t0.email_count AS emails_logged,
      (DATE '2026-01-05' - t0.month_start) AS days_old_as_of_2026_01_05,
      CASE WHEN (DATE '2026-01-05' - t0.month_start) > 730 THEN 'Y' ELSE 'N' END AS exceeds_730_day_retention
    FROM (
      SELECT CAST(date_trunc('month', t1.created_at) AS date) AS month_start, COUNT(*) AS email_count
      FROM email_log t1
      WHERE t1.created_at >= DATE '2023-01-01' AND t1.created_at < DATE '2026-01-01'
      GROUP BY date_trunc('month', t1.created_at)
    ) t0
    ORDER BY t0.month_start ASC NULLS LAST
    10 ms100 ms1 sHyper203 msDuckDB112 msGizmoSQL111 msclickhouse_brew134 msFirebolt83.6 msDataFusionwrong resultClickHouse77.6 ms
    • DataFusionrow 1: col 1: "2023-01" vs "YYYY-MM"
  7. Everything, as recorded

    The agents' own records, as the role play wrote them; only the personal data of the person who ran it is redacted

    Bea's whole session, 9 turns
    • The request, as Bea received it
      Report request from Priyanka Desai (analyst for the Data Protection Officer):
      
      Title: email_log actual retention vs. the stated 730-day delete policy
      Question: Since email_log's retention policy is configured but inactive and has never run for any tenant, how much email data are we actually still holding well past the stated 730-day window?
      Grain: one row per calendar month, based on email_log.created_at
      Columns:
      - month (YYYY-MM)
      - emails logged in month (count)
      - days old as of 2026-01-05 (measured from month start)
      - exceeds 730-day retention (Y/N)
      Details: Source: email_log, platform-wide (all tenants), grouped by date_trunc('month', created_at) or joined to calendar_days. Span the full 2023-01 through 2025-12 history so we can see the total volume of retained email data and how far past the 730-day policy threshold the oldest months are, using the literal date 2026-01-05 (not CURRENT_DATE) for the age calculation. This directly sizes the gap identified last night: retention_policies shows a 730-day/delete rule for email_log configured for all 120 tenants but with active_count = 0 and never_run_count = 120. Order by month ascending.
      
      Check your query with the warehouse's dry_run tool, then hand it in with submit.
    • Bea calls dry_run
      SELECT
        to_char(t0.month_start, 'YYYY-MM') AS month,
        t0.email_count AS emails_logged,
        (DATE '2026-01-05' - t0.month_start) AS days_old_as_of_2026_01_05,
        CASE WHEN (DATE '2026-01-05' - t0.month_start) > 730 THEN 'Y' ELSE 'N' END AS exceeds_730_day_retention
      FROM (
        SELECT date_trunc('month', t1.created_at)::date AS month_start, COUNT(*) AS email_count
        FROM email_log t1
        WHERE t1.created_at >= DATE '2023-01-01' AND t1.created_at < DATE '2026-01-01'
        GROUP BY date_trunc('month', t1.created_at)
      ) t0
      ORDER BY t0.month_start ASC
    • The warehouse answers
      STATUS: REJECTED
        - does not compile: Catalog Error: Scalar Function with name to_char does not exist!
    • Bea calls dry_run
      SELECT
        strftime(t0.month_start, '%Y-%m') AS month,
        t0.email_count AS emails_logged,
        (DATE '2026-01-05' - t0.month_start) AS days_old_as_of_2026_01_05,
        CASE WHEN (DATE '2026-01-05' - t0.month_start) > 730 THEN 'Y' ELSE 'N' END AS exceeds_730_day_retention
      FROM (
        SELECT date_trunc('month', t1.created_at)::date AS month_start, COUNT(*) AS email_count
        FROM email_log t1
        WHERE t1.created_at >= DATE '2023-01-01' AND t1.created_at < DATE '2026-01-01'
        GROUP BY date_trunc('month', t1.created_at)
      ) t0
      ORDER BY t0.month_start ASC
    • The warehouse answers
      STATUS: COMPILES (dry run on the empty schema, no data read)
      COLUMNS: month, emails_logged, days_old_as_of_2026_01_05, exceeds_730_day_retention
    • BeaQuery compiles cleanly with the right columns. Submitting.
    • Bea calls submit
      SELECT
        strftime(t0.month_start, '%Y-%m') AS month,
        t0.email_count AS emails_logged,
        (DATE '2026-01-05' - t0.month_start) AS days_old_as_of_2026_01_05,
        CASE WHEN (DATE '2026-01-05' - t0.month_start) > 730 THEN 'Y' ELSE 'N' END AS exceeds_730_day_retention
      FROM (
        SELECT date_trunc('month', t1.created_at)::date AS month_start, COUNT(*) AS email_count
        FROM email_log t1
        WHERE t1.created_at >= DATE '2023-01-01' AND t1.created_at < DATE '2026-01-01'
        GROUP BY date_trunc('month', t1.created_at)
      ) t0
      ORDER BY t0.month_start ASC
    • The warehouse answers
      Submitted to tonight's batch. Your work on this request is done.
    • BeaSubmitted. The report gives one row per month (Jan 2023–Dec 2025) with the email count, days elapsed from that month's start to 2026-01-05, and a Y/N flag for exceeding the 730-day policy — directly sizing how much retained email data sits past the stated retention window across all 120 tenants.