SAM
SAMANDA
Save America Movement Analytics Network for Democratic Accountability
validation applied 2026-11-04 to 2026-11-05
sizes measured 2026-11-05
page built 2026-11-05

Verdicts, coverage, and data quality across all 36 domains. Single source of truth: validation_state.json (core battery = worst-of Quality + Fidelity). Validation engine run 41954068507.

✗ 255 datasets need a fix before shipping downstream
→ Generate a fix-it prompt for these
456,221
Files tracked
5313 datasets
3.1 TB
Total data
in the archive, bucket total of 2026-11-05
100%
Validation coverage
5313 of 5313 datasets fully run through the battery
100%
Provenance complete
4709 of 4712 assessed datasets have all provenance fields · 601 not assessed (no committed data files for the battery to walk)
State Coverage

Tiles show the % of datasets that hold data for each state. Pick a domain to see just its datasets.

AK
ME
VT
NH
WA
ID
MT
ND
MN
WI
MI
NY
MA
OR
NV
WY
SD
IA
IL
IN
OH
PA
NJ
CT
CA
UT
CO
NE
MO
KY
WV
VA
MD
DE
RI
AZ
NM
KS
AR
TN
NC
SC
DC
HI
OK
LA
MS
AL
GA
TX
FL
0datasets covering a state1527
Validation Reports

Open a domain, then a dataset, for its full validation report: overall verdict, Quality and Fidelity axes, reconciliation coverage (records re-queried from source and matched — the bootstrapped n≈300 sample that grows toward 100%), provenance, and every content-battery check with its fix. Domain verdict chips (right): pass warn fail not run.

Validation History

How validation has progressed across 60 validation runs (2026-10-07 → 2026-11-05). Each point counts every domain's latest run at that time; the newest holds 36 of 36 domains.

Analysis Readiness by Domain
How each check works — the core battery (reference)
INT-NONEMPTYL1 Integrity
323,150 files checked · 323,149 pass1 fail
What: Every file is > 0 bytes.
How: Stat every tracked file and flag any whose size is 0 bytes.
Fix: Re-fetch from the source (re-run the fetch_*.py script), confirm a non-zero size, re-push. Investigate why the original write produced 0 bytes.
Flagged files (e.g.): host.json
SCH-RAGGEDL3 Schema
152,182 files checked · 152,062 pass120 fail
What: Every data row has exactly the header's column count.
How: Parse each CSV and compare every data row's field count to the header count; count the rows that differ.
Fix: Re-export with proper RFC-4180 quoting; verify column counts are uniform before push.
Flagged files (e.g.): 44541260.csv, 56286425.csv, 56286428.csv, 56286431.csv, 56286434.csv, ofac_consolidated.apisnapshot.csv.gz …
QC-ROWCOUNTL4 Content
152,182 files checked · 152,033 pass149 fail
What: Actual row count matches the catalog's declared row_count within tolerance.
How: Count data rows and compare to the catalog's declared row_count within tolerance; flag drift.
Fix: Re-fetch and compare; if the change is real, update row_count + CHANGELOG. Large unexplained drops are truncation — re-download.
Flagged files (e.g.): 59758862.csv, 59758868.csv, 59758877.csv, 59758880.csv, 59758889.csv, 59758892.csv …
QC-PKUNIQUEL4 Content
78,842 files checked · 78,309 pass533 fail
What: The primary/join key is unique (no duplicate keys).
How: Count distinct primary/join-key tuples versus total rows; duplicate rate = 1 − distinct/total (must be 0).
Fix: De-duplicate at the cleaning step or correct the key definition; document the canonical key in DATA_DICTIONARY.md.
Flagged files (e.g.): whispers_events_raw.csv.gz, 2qns-g7s7.csv.gz, f8kp-sfr3.csv.gz, k7a5-emiw.csv.gz, mg5r-efcm.csv.gz, qew5-gawh.csv.gz …
QC-NULLRATEL4 Content
152,048 files checked · 152,047 pass1 warn
What: Per-column null rate is below threshold (default 20%); a NULL in a key column is a BLOCKER.
How: Compute the null percentage of each column; flag any column above the threshold (default 20%); a null in a key column escalates to BLOCKER.
Fix: Investigate the source for suppression/coverage gaps; document expected nulls in the catalog notes, or re-fetch if the gap is an extraction error. Null key values must be resolved before use.
Flagged files (e.g.): cdc_fluview_who_nrevss_laboratories_US_v1.0.csv.gz
KEY-FIPSL5 Keys
1,965 files checked · 1,923 pass42 fail
What: state_fips / county_fips values are valid US FIPS codes.
How: Validate every state_fips/county_fips against the canonical US FIPS set; report the percentage of valid codes (must be 100%).
Fix: Correct the FIPS mapping via the committed county_name→FIPS crosswalk; re-run the FIPS-derivation step with the 100%-coverage hard check.
Flagged files (e.g.): StormEvents_details-ftp_v1.0_d1994_c20260323.csv.gz, StormEvents_details-ftp_v1.0_d1995_c20260323.csv.gz, StormEvents_details-ftp_v1.0_d1996_c20260323.csv.gz, StormEvents_details-ftp_v1.0_d1997_c20260323.csv.gz, StormEvents_details-ftp_v1.0_d1998_c20260323.csv.gz, StormEvents_details-ftp_v1.0_d1999_c20260323.csv.gz …
PROV-FIELDSL2 Provenance
5,737 datasets checked · 5,734 pass3 warn
What: Each active catalog entry has all required fields: description, source_url, source_tier, retrieved, update_cadence, geographic_granularity.
How: Parse each active CATALOG.md entry and test for the 6 required provenance fields; report which fields are missing per entry.
Fix: Edit the CATALOG.md entry to add the named missing field(s). Values must be transcribed from the real source — do not guess.
INT-CHECKSUML1 Integrity
5,737 files checked · 0 pass5,737 deferred — content checks deferred to a full run
What: The bytes the battery read hash to the file's recorded identity (git blob SHA for a tracked file; manifest sha256 for an object in S3).
How: While the walk streams a file's bytes, hash them (lib/content_digest.py): git blob SHA-1 for a tree read, SHA-256 for an S3 read. At the end of a COMPLETE read, compare to the recorded identity — the tree listing's blob SHA, or the manifest's sha256. Match = pass; mismatch = fail; a file not read, read in part, or with no recorded identity = not measured (reported, never counted as a pass).
Fix: Re-run the walk; if it recurs, fetch the file directly and compare its hash to the record. An S3 object that differs from its manifest was overwritten or restored from the wrong version — restore the recorded version, or re-deposit and re-record it.
INT-BINARYL1 Integrity
2,714 files checked · 2,599 pass115 deferred ✓ all clear
What: Every container opens: a ZIP/XLSX's end record and central directory are whole and agree; PARQUET carries PAR1 at both ends with a sane footer; a PDF has its %PDF- header and %%EOF trailer; a SHP header's length matches the file.
How: lib/archive_integrity.py, over every container tracked in git and every container object a pointer names in S3. Ranged reads only — for a ZIP the last 64 KiB (one more read if its directory is larger): find the end record (zip64 included), check the central directory ends exactly where the record says, every entry carries its signature, and the count matches. PARQUET: PAR1 at both ends and a footer length that fits. PDF: %PDF- and %%EOF. A tree verdict is carried to the next run only while the file's git blob SHA is unchanged (same SHA = same bytes); an unread container is NOT MEASURED, never a pass.
Fix: Re-download from the primary source and re-validate the archive opens before pushing.
QC-PKUNIQUE-KEYL4 Content
565 files checked · 544 pass21 fail
What: The dataset's OWN declared key (validation spec `key:`) has no duplicate tuples — independent of whether whole rows are byte-identical.
How: Resolve the dataset's declared `key:` columns from its validation spec (scripts/lib/spec_discovery.py), count distinct key tuples versus total rows; duplicate rate = 1 − distinct/total (must be 0). No declared key, or a declared column missing from the header, yields no measurement (None) rather than a false 0.
Fix: De-duplicate at the cleaning step, or correct the declared `key:` in the validation spec if it does not match the data's actual grain. A dataset with no declared key is UNMEASURED (None), not exempt — add a `key:` to measure it.
Flagged files (e.g.): fema_pa_applicants_national_v1.0.csv.gz, fema_hma_mitigated_properties_national_v1.0.csv.gz, grant_witness_terminations_grant_2025_v1.0.csv, samhsa_treatment_facility_locator_national_2025_v1.0.csv.gz, cms_aco_snf_affiliates_national_2026_v1.0.csv, billstatus_bills_117_v1.0.csv.gz …
QC-COVERAGEL4 Content
310 files checked · 0 pass310 warn
What: Every row-table file in the dataset carries content measurements — the fraction actually content-checked is published beside the verdict.
How: Classify every file in the dataset as a row table or not (lib/content_eligibility.content_candidate_file — candidacy, NOT eligibility, so a file excluded by a future size bound stays in its own denominator), then count how many of the row tables actually carry a content block. Reports checked/candidates and bytes_checked/bytes_candidate; flags any row table the walk did not open. A file the walk TRIED and could not read is SCH-PARSE's subject and is not double-counted here.
Fix: Re-run the content walk over this dataset (`validate_data.py --full`, or a domain-scoped run naming its domain). If the file legitimately cannot be measured, that is SCH-PARSE's subject — record the read failure rather than leaving the file silently unmeasured.
Flagged files (e.g.): measles_cases.parquet, measles_long_run.parquet, amendments.parquet, countries.parquet, datasets.parquet, elements.parquet …
Fix-it prompt

Generated on demand from the failures currently shown above — always in sync with this dashboard. Click to build + copy it, then paste into a new Reference-Data session (BLOCKERs first, gate-aware).

Built at each publish from validation_state.json and each domain's validation record. Snapshot 2026-11-05T10:45:22Z.