Observed firm-microdata readers: Form 5500 and OSHA ITA (#192) - #386
Open
vahid-ahmadi wants to merge 3 commits into
Open
Observed firm-microdata readers: Form 5500 and OSHA ITA (#192)#386vahid-ahmadi wants to merge 3 commits into
vahid-ahmadi wants to merge 3 commits into
Conversation
Every firm-side source in the repository so far is a published
aggregate (SUSB, BDS, QWI, J2J). These two are observed firm records,
which is what a firm frame built from real rather than generated firms
requires.
Coverage of the SUSB 2022 sector x canonical-band grid, measured
across both sources: 97 target cells, **zero** empty, **zero** with
fewer than 10 records, 0.00% of SUSB employment in uncovered cells,
987,039 real firm records. Implied cell weights: median 1.7, p90 14.7,
max 225.2.
Both sources carry integer employment counts, so band_of_count maps
them onto the canonical IC2 bands exactly — neither ever produces a
straddling BandSpan, unlike CPS NOEMP, SIPP EJB1_EMPSIZE, BDS fsize
("20 to 99") or LEHD firmsize ("0-19").
Three findings the readers are built around:
- The Form 5500 sponsor EIN is not the SUSB enterprise. 23,813
sponsors report 500+ active participants while SUSB counts 21,041
firms with 500+ employees, so the units provably differ. Active
participants are a lower bound on employment, and 122,173 sponsors
file more than one form, so read_sponsors aggregates by maximum and
never by sum.
- The OSHA employment field is dirty in a concentrated way: the raw
column sums to 321,889,014, or 237% of US employment. The objective
hours/employee <= 8,760 test removes only 1,996 records holding
235,875 employees; about a dozen records carry the rest. The cap
that removes them swings the national total by 32% (47.8M at 50,000
to 62.9M at 1,000,000), so it is a referee choice: read_ita applies
no cleaning and attaches quality flags, and apply_quality_rule takes
max_employees as a required argument with no default, recording what
it dropped on the returned frame.
- 43,001 EINs appear in both universes and agree on the canonical band
for only 66.3% of them, with disagreement in both directions. That
rate is registered as evidence, not as a threshold.
Raw files stay outside Git (the SIPP/PSID staging convention) under
POPULACE_DYNAMICS_FIRM_DIR, pinned by sha256 recorded at fetch time by
scripts/fetch_firm_microdata.py. All three are US federal government
works, published without stated redistribution restriction.
Verification: 26 new unit tests pass, including real-data tests that
reproduce every pinned figure in the provenance sidecar against the
staged files; full unit tier 1,549 passed / 7 skipped; tier manifest
and README updated (unit 1,530 -> 1,556); Ruff and Black clean.
This is reader/provenance work only. It does not modify gates.yaml,
IC3 targets, floors, thresholds, calibration, or candidate fitting.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
# Conflicts: # tests/README-tiers.md # tests/tier_counts.json
The 26 firm-microdata reader tests classify into the unit tier. Counts recollected from the committed tree, per the merge convention. Co-Authored-By: Claude Opus 5 (1M context) <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.
Every firm-side source in the repository so far is a published aggregate — SUSB, BDS, QWI, J2J. This adds the first observed firm records: DOL Form 5500 / 5500-SF plan-sponsor filings and OSHA ITA Form 300A establishment summaries, both public US federal works.
Why this changes the firm-side design
The design has assumed a synthetic firm population because no public firm microdata was believed to exist. It does. The decisive test is whether real records cover the SUSB calibration grid densely enough to reweight rather than generate:
Implied cell weights (SUSB firms / real records): median 1.7, p90 14.7, max 225.2 (NAICS 99
1-9, an 8,332-firm cell). Density is thinnest in1-9(74 records per 1,000 SUSB firms) and near-census in100-499(941 per 1,000).A reweighted real-firm frame is therefore viable and no synthetic firm row is required. This PR is the reader layer only; the frame construction, the unit reconciliation and the calibration are separate work.
Exact banding — the reason these sources are worth having
Both carry integer employment counts, so
firms.banding.band_of_countmaps them onto the canonical IC2 bands exactly. Neither ever produces a straddlingBandSpan, unlike CPSNOEMP, SIPPEJB1_EMPSIZE, BDSfsize("20 to 99") or LEHDfirmsize("0-19"). Tests pin the intended band for every canonical edge independently ofbanding.py's own tables.Three findings the readers are built around
1. The Form 5500 sponsor EIN is not the SUSB enterprise. 23,813 sponsors report 500+ active participants while SUSB 2022 counts 21,041 firms with 500+ employees — more large sponsors than large firms exist, which is only possible if the units differ. Active participants are additionally a lower bound on employment (plan-covered workers only). 122,173 of 828,330 sponsors file more than one form and the counts overlap rather than add, so
read_sponsorsaggregates by maximum and never by sum.2. The OSHA employment field is dirty in a concentrated way. The raw
annual_average_employeescolumn sums to 321,889,014 — 237% of total US employment. The objective physical test (annual hours per employee cannot exceed 8,760) removes only 1,996 records holding 235,875 employees. About a dozen records carry the rest, and the cap chosen to remove them swings the national total by 32%:That makes the cap a referee choice with a quantified effect on every downstream margin, not a loader detail.
read_itatherefore applies no cleaning at all and attacheshours_per_employee/hours_implausible/bandableflags;apply_quality_ruletakesmax_employeesas a required argument with no default and records exactly what it dropped on the returned frame. This mirrorsBandSpan, which carries ambiguity explicitly rather than resolving it by hidden convention.3. Two administrative firm-size measures disagree one time in three. 43,001 EINs appear in both universes; they agree on the canonical band for 66.3% of them, median ratio 0.89, with disagreement running in both directions (1,451 firms are OSHA
100-499but 5500500+— impossible if participants were merely a subset of employees). Registered here as evidence, not as a threshold. It is a measurement-floor observation and it bounds how tightly any firm-size gate can be set: a threshold finer than 66.3% band agreement is finer than the instruments resolve.Staging and provenance
Raw files stay outside Git (the SIPP/PSID convention) under
POPULACE_DYNAMICS_FIRM_DIR, pinned by sha256 recorded at fetch time byscripts/fetch_firm_microdata.py. Provenance sidecar:data/external/firm_microdata_sources.md.The DOL
.../Latest/...URLs are refreshed in place as amended filings arrive, so a digest identifies the vintage actually read, not a stable publisher artifact; a mismatch after a refresh requires a deliberate pin update and a rebuild of anything that read the old bytes.All three sources are works of the US federal government published without stated redistribution restriction — unlike the Kauffman Firm Survey (#339), whose archive carries no explicit redistribution license.
Verification
Scope
Reader and provenance work only. It does not modify
gates.yaml, IC3 targets, floors, thresholds, partitions, calibration, or candidate fitting, and authorizes no candidate run. Based on master rather than stacked on the IC3 queue, so it can be reviewed in parallel.tests/tier_counts.jsonwill conflict trivially with #212/#235/#276 — whoever merges second recounts from current master, per the existing convention.Relates to #192, #282. Supersedes the firm-microdata role of #339.