fix(dbt): resolve 3 P0 identity/fan-out/sign bugs from warehouse audit#2400
Open
blarghmatey wants to merge 2 commits into
Open
fix(dbt): resolve 3 P0 identity/fan-out/sign bugs from warehouse audit#2400blarghmatey wants to merge 2 commits into
blarghmatey wants to merge 2 commits into
Conversation
Fixes three P0 correctness defects found in the dbt warehouse semantic- accuracy audit: - dim_user.sql: the users_with_global_id, mitxpro_user_view, and mitxresidential_user_view branches did not filter NULL emails before keying user_pk on hash(lower(email)), unlike the emeritus/global_alumni/ bootcamps branches. NULL-email rows collapsed onto one surrogate key and agg_view's max()-merge fused unrelated people together. Added the same null-email filter to all branches plus a not_null test on dim_user.email as a regression guard. - int__combined__users.sql: deduped to one row per (user_username, platform), matching logic marts__combined_course_engagements.sql already applied downstream. marts__combined_problem_submissions.sql and marts__combined_video_engagements.sql left-joined this model with no dedup of their own, duplicating event rows for any duplicated user; fixing it at the source fixes all three consumers. Also added platform to the three daily-activity join predicates in marts__combined_course_engagements.sql that were joining on (date, courserun_readable_id, user_username) alone, which double-counted engagement metrics on cross-platform username collisions. - marts__combined_program_enrollment_detail.sql: swapped date_diff argument order for program_completion_days. Trino's date_diff returns arg3-arg2, so the previous argument order produced negative day counts for completions, contradicting the documented "days between first course start and program completion certificate" semantics. Closes #2376 Closes #1957 Closes #2083 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses multiple correctness issues in the src/ol_dbt dbt project that can cause identity collisions, fan-out duplication, and incorrect metric signs in downstream marts.
Changes:
- Filters out NULL emails in additional
dim_userbranches and adds anot_nulltest ondim_user.emailto prevent identity collapse. - Adds
platformto daily-activity join predicates inmarts__combined_course_engagementsto prevent cross-platform fan-out/double counting. - Fixes the sign of
program_completion_daysby correctingdate_diffargument order, and moves user dedup logic intoint__combined__users.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/ol_dbt/models/marts/combined/marts__combined_program_enrollment_detail.sql | Swaps date_diff arguments to make program_completion_days positive per intended semantics. |
| src/ol_dbt/models/marts/combined/marts__combined_course_engagements.sql | Adds platform to join predicates for daily activity rollups to avoid cross-platform collisions. |
| src/ol_dbt/models/intermediate/combined/int__combined__users.sql | Introduces upstream dedup logic so downstream marts don’t need to defensively dedup user rows. |
| src/ol_dbt/models/dimensional/dim_user.sql | Adds NULL-email filters in additional union branches to prevent NULL-email identity collapse. |
| src/ol_dbt/models/dimensional/_dim__models.yml | Adds a not_null test on dim_user.email as a regression guard. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Review on #2400 (Copilot + Sentry bot) correctly flagged that the new row_number() dedup partitioned by (user_username, platform), but emeritus and global_alumni rows always have user_username = NULL -- PARTITION BY groups all NULLs together, so this collapsed every emeritus user (and every global_alumni user) into a single row instead of deduping only actual duplicates. Fix: partition by coalesce(user_username, user_id, user_email, user_full_name) instead, matching the same fallback chain the emeritus_users CTE already uses for its own upstream dedup. Also removed the now-redundant local dedup CTE in marts__combined_course_engagements.sql (same latent bug, inert there since emeritus/global_alumni never share a platform value with the daily-activity union) since int__combined__users is deduped at the root now. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What are the relevant tickets?
Closes #2376
Related to #1957 (same fan-out defect family; that issue investigates conditional uniqueness in a sibling model and isn't fully resolved by this PR)
Related to #2083 (that issue tracks migrating this model off int__/stg__ refs onto the dimensional layer — a different problem than the sign bug fixed here, so not closed by this PR)
Description (What does it do?)
Fixes three P0 correctness defects surfaced by a dimensional/marts/reporting semantic-accuracy audit of
src/ol_dbt:dim_user NULL-email identity collapse (Fix dim_user NULL-email identity collapse #2376) —
dim_user.sqlkeysuser_pkonhash(lower(email)). Theusers_with_global_id(MITx/mitlearn),mitxpro_user_view, andmitxresidential_user_viewbranches did not filter out NULL emails before this, unlike the emeritus/global_alumni/bootcamps branches which already did. Every NULL-email row across those branches collapsed onto a single surrogate key, andagg_view'smax()-merge silently fused unrelated people's platform IDs together. Fix: added the same null-email filter to the three unguarded branches, plus anot_nulltest ondim_user.emailas a regression guard.Un-deduped user joins / missing platform key fanning out engagement marts —
marts__combined_course_engagements.sqlalready dedupedint__combined__userswithrow_number() over (partition by user_username, platform)before joining it — proving duplicates exist in that model — butmarts__combined_problem_submissions.sqlandmarts__combined_video_engagements.sqlleft-joined the same model with no dedup, duplicating event rows for any duplicated user. Separately,marts__combined_course_engagements.sqljoined its three daily-activity CTEs on(date, courserun_readable_id, user_username)withoutplatform, double-counting engagement metrics whenever a username collided across platforms. Fix: moved the dedup intoint__combined__users.sqlitself (the root cause), so all three downstream marts get deduped data for free, and addedplatformto the three join predicates inmarts__combined_course_engagements.sql. The now-redundant local dedup inmarts__combined_course_engagements.sqlwas removed rather than duplicated.Update after review: the initial dedup partitioned by
(user_username, platform), butemeritusandglobal_alumnirows always haveuser_username = NULL— sincePARTITION BYgroups allNULLs together, this collapsed every emeritus user (and every global_alumni user) into a single row, a data-loss regression caught by review (thanks Copilot/Sentry bots). Fixed by partitioning oncoalesce(user_username, user_id, user_email, user_full_name)instead, so platforms without a username still dedupe on a stable per-user identifier instead of collapsing.Inverted sign of program_completion_days —
marts__combined_program_enrollment_detail.sqlcomputeddate_diff('day', programcertificate_created_on_date, first_courserun_start_on_date). Trino'sdate_diff(unit, x, y)returnsy - x, so this produced negative day counts for completions, contradicting the documented "days between the first course start date and the program completion certificate date" semantics. Fix: swapped the argument order. Confirmed no downstream consumer was already negating the value to compensate.How can this be tested?
dbt compile --select dim_user int__combined__users marts__combined_course_engagements marts__combined_program_enrollment_detail marts__combined_problem_submissions marts__combined_video_engagementsagainst thedev_localDuckDB/Iceberg target compiles cleanly (verified).dim_userrows with fused platform IDs; distinctemeritus/global_alumniusers still appear as separate rows inint__combined__users(not collapsed to one);marts__combined_problem_submissions/video_engagementsrow counts drop for any user with a previously-duplicatedint__combined__usersrow;program_completion_daysis positive for completed programs.Additional Context
reporting/program_enrollment_with_user_report.sqlindependently re-derivesprogram_completion_dayswith the correct sign already from a raw string — that competing definition is tracked separately (unblocked by this PR) and not addressed here.🤖 Generated with Claude Code