Skip to content

Harden data pipeline against corrupted dataset uploads#570

Merged
baogorek merged 7 commits intomainfrom
add-dataset-sanity-tests
Mar 5, 2026
Merged

Harden data pipeline against corrupted dataset uploads#570
baogorek merged 7 commits intomainfrom
add-dataset-sanity-tests

Conversation

@MaxGhenis
Copy link
Contributor

@MaxGhenis MaxGhenis commented Mar 4, 2026

Summary

Hardens the data pipeline with 5 layers of defense to prevent corrupted datasets from being uploaded to HuggingFace — the bug class from PR #569 where employment_income_before_lsr was dropped, zeroing all income and inflating poverty to 40%.

Defense layers

  1. Pre-upload validation gate (upload_completed_datasets.py): File size, H5 structure, and aggregate stats checks run before ANY upload
  2. Post-generation assertions (enhanced_cps.py, small_enhanced_cps.py): Weight validation, critical variable checks, output file size verification
  3. CI workflow safety (reusable_test.yaml): Upload gated on success(), pre-upload H5 validation step
  4. Makefile hardening: Sparse file swap validates existence/size before and after
  5. Comprehensive tests: Sparse dataset sanity tests, direct employment income checks, file size regression test

How each layer would have caught PR #569's bug

Layer Would catch? How
Pre-upload validation Yes File was 14MB (threshold: 100MB), employment_income_before_lsr was empty
Post-generation assertions Yes create_sparse_ecps() output missing critical variables
CI workflow Yes H5 check catches missing employment_income_before_lsr
Makefile swap Yes Sparse file didn't exist (wrong filename), swap would fail
Tests Yes test_ecps_employment_income_positive catches $0 employment income

Test plan

  • CI lint/format passes
  • Smoke tests pass
  • Full data build + sanity tests pass (will run on merge to main)
  • Verify pre-upload validation blocks upload when given a bad file

🤖 Generated with Claude Code

@MaxGhenis MaxGhenis changed the title Add dataset sanity tests for core variables Harden data pipeline against corrupted dataset uploads Mar 4, 2026
@MaxGhenis MaxGhenis force-pushed the add-dataset-sanity-tests branch from 4995d83 to 933427d Compare March 4, 2026 23:17
MaxGhenis and others added 4 commits March 4, 2026 18:38
Checks employment_income, population counts, poverty rate, and income
tax against wide bounds after each data build. Would have caught the
enhanced CPS overwrite bug (PR #569) where employment_income_before_lsr
was dropped, zeroing out all income and inflating poverty to 40%.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Five layers of defense against the bug class from PR #569 where
a lossy sparse rebuild overwrote the enhanced CPS, dropping
employment_income_before_lsr and zeroing all income:

1. Pre-upload validation gate (upload_completed_datasets.py):
   - File size check (enhanced CPS must be >100MB, was 14MB when bad)
   - H5 structure check (critical variables must exist with data)
   - Aggregate stats check (employment income >5T, household count 100-200M)

2. Post-generation assertions (enhanced_cps.py, small_enhanced_cps.py):
   - Weight validation (no NaN, no negatives, reasonable sum)
   - Critical variable existence checks before save
   - Output file size verification after write

3. CI workflow safety (reusable_test.yaml):
   - Upload gated on success() so test failures block upload
   - Pre-upload H5 validation step checks structure before upload
   - employment_income_before_lsr explicitly checked

4. Makefile hardening:
   - Sparse file swap validates existence and size before/after
   - New validate-data target for standalone validation

5. Comprehensive test coverage:
   - Sparse dataset sanity tests (employment income, household count, poverty)
   - Direct employment income checks in enhanced and sparse test files
   - File size regression test (catches the 590MB→14MB shrink)
   - Small ECPS employment income and household count checks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MaxGhenis MaxGhenis force-pushed the add-dataset-sanity-tests branch from 7ef864d to 6ac6adb Compare March 4, 2026 23:39
MaxGhenis and others added 3 commits March 4, 2026 19:47
The variable was named optimised_weights_dense but the actual variable
from reweight() is optimised_weights.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CPS dataset stores employment_income (older name), while
employment_income_before_lsr is only present after policyengine-us
formula processing. The assertions now accept either variable name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The generate() method only modifies household_weight — the income
variables come from the input dataset and their key names vary between
builds. Income validation belongs in the upload validator which uses
Microsimulation to compute and verify employment_income > $5T.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MaxGhenis
Copy link
Contributor Author

CI status

5/6 checks pass (lint, smoke test, changelog, uv.lock, check-fork). The Test/test failure is expected — the full Modal data build produces datasets where employment_income = 0 (the known corruption issue), and our new sanity tests correctly catch this:

FAILED test_ecps_mean_employment_income_reasonable - Mean employment income = $0, expected $15k-$80k
FAILED test_ecps_poverty_rate_reasonable - Poverty rate = 42.3%, expected 5-25%
FAILED test_sparse_employment_income_positive - employment_income sum is 0.00e+00, expected > 5T

This is the hardening working as designed — these tests would have caught the original bug before it reached production. The tests will pass once the underlying data pipeline issue is resolved (separate from this PR).

This PR should be merged to get the safety nets in place. The test failures validate that the hardening is effective.

@baogorek baogorek merged commit d286241 into main Mar 5, 2026
5 of 6 checks passed
@baogorek baogorek deleted the add-dataset-sanity-tests branch March 5, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants